From 738af9c88e02ae04b74a7f0927f48abdc6311bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 12:51:55 +0100 Subject: [PATCH 001/290] (#606)(#607) Added gui for the statistics control. Started refactoring Refactoring to access pr timestep data from the statistics calculation. --- .../GeoMechDataModel/RigFemNativeStatCalc.cpp | 61 ++++++------ .../GeoMechDataModel/RigFemNativeStatCalc.h | 6 +- .../Rim3dOverlayInfoConfig.cpp | 93 +++++++++++++++---- .../ProjectDataModel/Rim3dOverlayInfoConfig.h | 24 ++++- .../RigMultipleDatasetStatCalc.cpp | 10 +- .../RigMultipleDatasetStatCalc.h | 5 +- .../ReservoirDataModel/RigNativeStatCalc.cpp | 38 ++++---- .../ReservoirDataModel/RigNativeStatCalc.h | 6 +- .../RigStatisticsCalculator.cpp | 45 +++++++++ .../RigStatisticsCalculator.h | 9 +- 10 files changed, 208 insertions(+), 89 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp index 246eb857d9..5642863662 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp @@ -92,53 +92,48 @@ void RigFemNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos } } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigFemNativeStatCalc::valueSumAndSampleCount(double& valueSum, size_t& sampleCount) +void RigFemNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { - int timestepCount = (int)(this->timeStepCount()); - int partCount = static_cast(m_resultsData->m_femPartResults.size()); - - for (int pIdx = 0; pIdx < partCount; ++pIdx) - { - for (int tIdx = 0; tIdx < timestepCount; tIdx++) - { - const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, tIdx); - size_t undefValueCount = 0; - for (size_t cIdx = 0; cIdx < values.size(); ++cIdx) - { - double value = values[cIdx]; - if (value == HUGE_VAL || value != value) - { - ++undefValueCount; - continue; - } - - valueSum += value; - } - - sampleCount += values.size(); - sampleCount -= undefValueCount; - } - } + int tsIdx = static_cast(timeStepIndex); + int partCount = static_cast(m_resultsData->m_femPartResults.size()); + + for (int pIdx = 0; pIdx < partCount; ++pIdx) + { + const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, tsIdx); + size_t undefValueCount = 0; + for (size_t cIdx = 0; cIdx < values.size(); ++cIdx) + { + double value = values[cIdx]; + if (value == HUGE_VAL || value != value) + { + ++undefValueCount; + continue; + } + + valueSum += value; + } + + sampleCount += values.size(); + sampleCount -= undefValueCount; + } } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigFemNativeStatCalc::addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator) +void RigFemNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { - int timestepCount = (int)(this->timeStepCount()); int partCount = static_cast(m_resultsData->m_femPartResults.size()); for (int pIdx = 0; pIdx < partCount; ++pIdx) { - for (int tIdx = 0; tIdx < timestepCount; tIdx++) - { - const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, tIdx); + const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, static_cast(timeStepIndex)); - histogramCalculator.addData(values); - } + histogramCalculator.addData(values); } } diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h index 269083a74e..9f7b67104b 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h @@ -37,9 +37,11 @@ class RigFemNativeStatCalc : public RigStatisticsCalculator virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); - virtual void valueSumAndSampleCount(double& valueSum, size_t& sampleCount); - virtual void addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual size_t timeStepCount(); private: diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 458a091220..f80ce53311 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -41,7 +41,37 @@ #include "RigFemResultAddress.h" #include "RigFemPartResultsCollection.h" +#include "RigStatisticsDataCache.h" + CAF_PDM_SOURCE_INIT(Rim3dOverlayInfoConfig, "View3dOverlayInfoConfig"); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(Rim3dOverlayInfoConfig::ALL_TIMESTEPS, "ALL_TIMESTEPS", "All Time Steps"); + addItem(Rim3dOverlayInfoConfig::CURRENT_TIMESTEP, "CURRENT_TIMESTEP", "Current Time Step"); + setDefault(Rim3dOverlayInfoConfig::ALL_TIMESTEPS); +} +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(Rim3dOverlayInfoConfig::ALL_CELLS, "ALL_CELLS", "All Active Cells"); + addItem(Rim3dOverlayInfoConfig::VISIBLE_CELLS, "VISIBLE_CELLS", "Visible Cells"); + setDefault(Rim3dOverlayInfoConfig::ALL_CELLS); +} +} //-------------------------------------------------------------------------------------------------- /// @@ -56,6 +86,9 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitField(&showInfoText, "ShowInfoText", true, "Info Text", "", "", ""); CAF_PDM_InitField(&showAnimProgress, "ShowAnimProgress", true, "Animation progress", "", "", ""); CAF_PDM_InitField(&showHistogram, "ShowHistogram", true, "Histogram", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_statisticsCellRange, "StatisticsCellRange", "Statistics Cell Range", "", "", ""); } //-------------------------------------------------------------------------------------------------- @@ -111,7 +144,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_viewDef->viewer()->showAnimationProgress(showAnimProgress()); RimEclipseView * reservoirView = dynamic_cast(m_viewDef.p()); - if (reservoirView) updateReservoir3DInfo(reservoirView); + if (reservoirView) updateEclipse3DInfo(reservoirView); RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); if (geoMechView) updateGeoMech3DInfo(geoMechView); } @@ -135,7 +168,7 @@ void Rim3dOverlayInfoConfig::setReservoirView(RimView* ownerReservoirView) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::updateReservoir3DInfo(RimEclipseView * reservoirView) +void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) { if (showInfoText()) { @@ -183,19 +216,38 @@ void Rim3dOverlayInfoConfig::updateReservoir3DInfo(RimEclipseView * reservoirVie if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) { infoText += QString("Cell Property: %1 ").arg(propName); + // Wait until regression tests confirm new statisticks is ok infoText += QString("
Statistics for: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); - double min, max; - double p10, p90; - double mean; - size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + if (m_statisticsCellRange == ALL_CELLS) + { + double min, max; + double p10, p90; + double mean; + + size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); + + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int timeStepIdx = reservoirView->currentTimeStep(); + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); + //reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); + //reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); + p10 = HUGE_VAL; + p90 = HUGE_VAL; + mean = HUGE_VAL; + } - //infoText += QString("
Min: %1 P10: %2 Mean: %3 P90: %4 Max: %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - //infoText += QString("
Min: %1   P10: %2   Mean: %3 \n  P90: %4   Max: %5 
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - infoText += QString("" - "
MinP10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); + infoText += QString("" + "" + "" + "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); + } if (reservoirView->faultResultSettings()->hasValidCustomResult()) { @@ -257,6 +309,8 @@ void Rim3dOverlayInfoConfig::updateReservoir3DInfo(RimEclipseView * reservoirVie { if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) { + if (m_statisticsCellRange == ALL_CELLS && m_statisticsTimeRange == ALL_TIMESTEPS) + { double min, max; double p10, p90; double mean; @@ -269,6 +323,7 @@ void Rim3dOverlayInfoConfig::updateReservoir3DInfo(RimEclipseView * reservoirVie reservoirView->viewer()->showHistogram(true); reservoirView->viewer()->setHistogram(min, max, reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); + } } } } @@ -322,8 +377,7 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) break; } - infoText += QString( - "Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); + infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); double min = 0, max = 0; double p10 = 0, p90 = 0; @@ -332,13 +386,12 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); caseData->femPartResults()->meanScalarValue(resAddress, &mean); caseData->femPartResults()->minMaxScalarValues(resAddress,&min, &max); - - // ToDo: Implement statistics for geomech data - caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); - infoText += QString("" - "
MinP10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); + infoText += QString("" + "" + "" + "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); } else { diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h index 463fb6b71b..4391f3c393 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h @@ -24,12 +24,14 @@ #include "cafAppEnum.h" #include "cvfAssert.h" +#include "cvfObject.h" #include "cvfVector2.h" class RimEclipseView; class RimGeoMechView; class RimView; +class RigStatisticsDataCache; //================================================================================================== /// @@ -51,18 +53,34 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject caf::PdmField showInfoText; caf::PdmField showAnimProgress; caf::PdmField showHistogram; - + + enum StatisticsTimeRangeType + { + ALL_TIMESTEPS, + CURRENT_TIMESTEP + }; + + enum StatisticsCellRangeType + { + ALL_CELLS, + VISIBLE_CELLS + }; + protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual caf::PdmFieldHandle* objectToggleField(); private: - void updateReservoir3DInfo(RimEclipseView * reservoirView); + void updateEclipse3DInfo(RimEclipseView * reservoirView); void updateGeoMech3DInfo(RimGeoMechView * geoMechView); - + caf::PdmField > m_statisticsTimeRange; + caf::PdmField > m_statisticsCellRange; caf::PdmPointer m_viewDef; cvf::Vec2ui m_position; + + cvf::ref m_visibleCellStatistics; + }; diff --git a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp index 8db3f8a136..ba654ccf16 100644 --- a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp @@ -67,30 +67,32 @@ void RigMultipleDatasetStatCalc::posNegClosestToZero(size_t timeStepIndex, doubl } } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::valueSumAndSampleCount(double& valueSum, size_t& sampleCount) +void RigMultipleDatasetStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { if (m_nativeStatisticsCalculators.at(i)) { - m_nativeStatisticsCalculators.at(i)->valueSumAndSampleCount(valueSum, sampleCount); + m_nativeStatisticsCalculators.at(i)->valueSumAndSampleCount(timeStepIndex, valueSum, sampleCount); } } } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator) +void RigMultipleDatasetStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { if (m_nativeStatisticsCalculators.at(i)) { - m_nativeStatisticsCalculators.at(i)->addDataToHistogramCalculator(histogramCalculator); + m_nativeStatisticsCalculators.at(i)->addDataToHistogramCalculator(timeStepIndex, histogramCalculator); } } } diff --git a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h b/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h index 6085aa2e1c..b36e4e1aa3 100644 --- a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h @@ -44,8 +44,9 @@ class RigMultipleDatasetStatCalc : public RigStatisticsCalculator virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); - virtual void valueSumAndSampleCount(double& valueSum, size_t& sampleCount); - virtual void addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); virtual size_t timeStepCount(); diff --git a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp index 5008764d42..d6d1a6ac99 100644 --- a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp @@ -94,40 +94,36 @@ void RigNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, d //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator) +void RigNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { - for (size_t tIdx = 0; tIdx < m_resultsData->timeStepCount(m_scalarResultIndex); tIdx++) - { - std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, tIdx); + std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); - histogramCalculator.addData(values); - } + histogramCalculator.addData(values); } + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::valueSumAndSampleCount(double& valueSum, size_t& sampleCount) +void RigNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { - for (size_t tIdx = 0; tIdx < m_resultsData->timeStepCount(m_scalarResultIndex); tIdx++) + std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + size_t undefValueCount = 0; + for (size_t cIdx = 0; cIdx < values.size(); ++cIdx) { - std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, tIdx); - size_t undefValueCount = 0; - for (size_t cIdx = 0; cIdx < values.size(); ++cIdx) + double value = values[cIdx]; + if (value == HUGE_VAL || value != value) { - double value = values[cIdx]; - if (value == HUGE_VAL || value != value) - { - ++undefValueCount; - continue; - } - - valueSum += value; + ++undefValueCount; + continue; } - sampleCount += values.size(); - sampleCount -= undefValueCount; + valueSum += value; } + + sampleCount += values.size(); + sampleCount -= undefValueCount; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h b/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h index ece9cf800d..929888dcae 100644 --- a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h @@ -38,9 +38,11 @@ class RigNativeStatCalc : public RigStatisticsCalculator virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); - virtual void valueSumAndSampleCount(double& valueSum, size_t& sampleCount); - virtual void addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual size_t timeStepCount(); private: diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp index 6550dc8e68..80270f146d 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp @@ -42,3 +42,48 @@ void RigStatisticsCalculator::meanCellScalarValue(double& meanValue) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsCalculator::meanCellScalarValue(size_t timeStepIndex, double& meanValue) +{ + double valueSum = 0.0; + size_t sampleCount = 0; + + this->valueSumAndSampleCount(timeStepIndex, valueSum, sampleCount); + + if (sampleCount == 0) + { + meanValue = HUGE_VAL; + } + else + { + meanValue = valueSum / sampleCount; + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsCalculator::valueSumAndSampleCount(double& valueSum, size_t& sampleCount) +{ + size_t tsCount = this->timeStepCount(); + for (size_t tIdx = 0; tIdx < tsCount; tIdx++) + { + this->valueSumAndSampleCount(tIdx, valueSum, sampleCount); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsCalculator::addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator) +{ + size_t tsCount = this->timeStepCount(); + for (size_t tIdx = 0; tIdx < tsCount; tIdx++) + { + this->addDataToHistogramCalculator(tIdx, histogramCalculator); + } +} + diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h index 02ff0967ab..d3ab541e54 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h @@ -37,8 +37,13 @@ class RigStatisticsCalculator : public cvf::Object virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) = 0; void meanCellScalarValue(double& meanValue); - virtual void valueSumAndSampleCount(double& valueSum, size_t& sampleCount) = 0; - virtual void addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator) = 0; + void meanCellScalarValue(size_t timeStepIndex, double& meanValue); + + void valueSumAndSampleCount(double& valueSum, size_t& sampleCount); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) = 0; + + void addDataToHistogramCalculator(RigHistogramCalculator& histogramCalculator); + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) = 0; virtual size_t timeStepCount() = 0; }; From a4d7e369ebcbb8938ef2e706e6048124a592dfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 15:44:09 +0100 Subject: [PATCH 002/290] (#606)(#607) Added option to show 3D-info statistics pr. time step. --- .../RigFemPartResultsCollection.cpp | 24 +++ .../RigFemPartResultsCollection.h | 5 +- .../Rim3dOverlayInfoConfig.cpp | 112 ++++++++---- .../RigCaseCellResultsData.cpp | 24 +++ .../RigCaseCellResultsData.h | 3 + .../RigStatisticsDataCache.cpp | 159 +++++++++++------- .../RigStatisticsDataCache.h | 67 +++++--- 7 files changed, 279 insertions(+), 115 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp index 8421d1dcc4..493f626c54 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp @@ -781,6 +781,14 @@ void RigFemPartResultsCollection::meanScalarValue(const RigFemResultAddress& res this->statistics(resVarAddr)->meanCellScalarValues(*meanValue); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultsCollection::meanScalarValue(const RigFemResultAddress& resVarAddr, int frameIndex, double* meanValue) +{ + this->statistics(resVarAddr)->meanCellScalarValues(frameIndex, *meanValue); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -789,6 +797,14 @@ void RigFemPartResultsCollection::p10p90ScalarValues(const RigFemResultAddress& this->statistics(resVarAddr)->p10p90CellScalarValues(*p10, *p90); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultsCollection::p10p90ScalarValues(const RigFemResultAddress& resVarAddr, int frameIndex, double* p10, double* p90) +{ + this->statistics(resVarAddr)->p10p90CellScalarValues(frameIndex, *p10, *p90); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -797,3 +813,11 @@ const std::vector& RigFemPartResultsCollection::scalarValuesHistogram(co return this->statistics(resVarAddr)->cellScalarValuesHistogram(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigFemPartResultsCollection::scalarValuesHistogram(const RigFemResultAddress& resVarAddr, int frameIndex) +{ + return this->statistics(resVarAddr)->cellScalarValuesHistogram(frameIndex); +} + diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h index 48dd83b91e..8980de73c3 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h @@ -48,12 +48,15 @@ class RigFemPartResultsCollection: public cvf::Object void minMaxScalarValues (const RigFemResultAddress& resVarAddr, int frameIndex, double* localMin, double* localMax); - void posNegClosestToZero(const RigFemResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero); void minMaxScalarValues (const RigFemResultAddress& resVarAddr, double* globalMin, double* globalMax); + void posNegClosestToZero(const RigFemResultAddress& resVarAddr, int frameIndex, double* localPosClosestToZero, double* localNegClosestToZero); void posNegClosestToZero(const RigFemResultAddress& resVarAddr, double* globalPosClosestToZero, double* globalNegClosestToZero); void meanScalarValue(const RigFemResultAddress& resVarAddr, double* meanValue); + void meanScalarValue(const RigFemResultAddress& resVarAddr, int frameIndex, double* meanValue); void p10p90ScalarValues(const RigFemResultAddress& resVarAddr, double* p10, double* p90); + void p10p90ScalarValues(const RigFemResultAddress& resVarAddr, int frameIndex, double* p10, double* p90); const std::vector& scalarValuesHistogram(const RigFemResultAddress& resVarAddr); + const std::vector& scalarValuesHistogram(const RigFemResultAddress& resVarAddr, int frameIndex); private: RigFemScalarResultFrames* findOrLoadScalarResult(int partIndex, diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index f80ce53311..a22a6bf821 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -89,6 +89,7 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsCellRange, "StatisticsCellRange", "Statistics Cell Range", "", "", ""); + m_statisticsCellRange.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -220,9 +221,9 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) if (m_statisticsCellRange == ALL_CELLS) { - double min, max; - double p10, p90; - double mean; + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); @@ -236,11 +237,8 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) { int timeStepIdx = reservoirView->currentTimeStep(); reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); - //reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); - //reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); - p10 = HUGE_VAL; - p90 = HUGE_VAL; - mean = HUGE_VAL; + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); } infoText += QString("" @@ -309,20 +307,38 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) { if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) { - if (m_statisticsCellRange == ALL_CELLS && m_statisticsTimeRange == ALL_TIMESTEPS) + if (m_statisticsCellRange == ALL_CELLS) { - double min, max; - double p10, p90; - double mean; + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; + const std::vector* histogram = NULL; - size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); - reservoirView->viewer()->showHistogram(true); - reservoirView->viewer()->setHistogram(min, max, reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); - reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP ) + { + int timeStepIdx = reservoirView->currentTimeStep(); + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); + histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex, timeStepIdx)); + } + else + { + CVF_ASSERT(false); + } + + reservoirView->viewer()->showHistogram(true); + reservoirView->viewer()->setHistogram(min, max, *histogram); + reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); } } } @@ -379,14 +395,25 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); - double min = 0, max = 0; - double p10 = 0, p90 = 0; - double mean = 0; - + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; + RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); - caseData->femPartResults()->meanScalarValue(resAddress, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress,&min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); + + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + caseData->femPartResults()->meanScalarValue (resAddress, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress,&min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int timeStepIdx = geoMechView->currentTimeStep(); + caseData->femPartResults()->meanScalarValue (resAddress, timeStepIdx, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress, timeStepIdx, &min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, timeStepIdx, &p10, &p90); + } infoText += QString("
" "" @@ -420,15 +447,34 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) if (caseData) { - double min = 0, max = 0; - double p10 = 0, p90 = 0; - double mean = 0; + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; + const std::vector* histogram = NULL; RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); - caseData->femPartResults()->meanScalarValue(resAddress, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress, &min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); - geoMechView->viewer()->setHistogram(min, max, caseData->femPartResults()->scalarValuesHistogram(resAddress)); + + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + caseData->femPartResults()->meanScalarValue(resAddress, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress, &min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); + histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress)); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int timeStepIdx = geoMechView->currentTimeStep(); + caseData->femPartResults()->meanScalarValue(resAddress, timeStepIdx, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress, timeStepIdx, &min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, timeStepIdx, &p10, &p90); + histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress, timeStepIdx)); + } + else + { + CVF_ASSERT(false); + } + + geoMechView->viewer()->setHistogram(min, max, *histogram); geoMechView->viewer()->setHistogramPercentiles(p10, p90, mean); } } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 10e2a61c47..885b24d48e 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -87,6 +87,14 @@ const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(siz return m_statisticsDataCache[scalarResultIndex]->cellScalarValuesHistogram(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(size_t scalarResultIndex, size_t timeStepIndex) +{ + return m_statisticsDataCache[scalarResultIndex]->cellScalarValuesHistogram(timeStepIndex); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -95,6 +103,14 @@ void RigCaseCellResultsData::p10p90CellScalarValues(size_t scalarResultIndex, do m_statisticsDataCache[scalarResultIndex]->p10p90CellScalarValues(p10, p90); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::p10p90CellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& p10, double& p90) +{ + m_statisticsDataCache[scalarResultIndex]->p10p90CellScalarValues(timeStepIndex, p10, p90); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -103,6 +119,14 @@ void RigCaseCellResultsData::meanCellScalarValues(size_t scalarResultIndex, doub m_statisticsDataCache[scalarResultIndex]->meanCellScalarValues(meanValue); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::meanCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue) +{ + m_statisticsDataCache[scalarResultIndex]->meanCellScalarValues(timeStepIndex, meanValue); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h index a772be7f47..901b57d224 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h @@ -54,8 +54,11 @@ class RigCaseCellResultsData : public cvf::Object void posNegClosestToZero(size_t scalarResultIndex, double& pos, double& neg); void posNegClosestToZero(size_t scalarResultIndex, size_t timeStepIndex, double& pos, double& neg); const std::vector& cellScalarValuesHistogram(size_t scalarResultIndex); + const std::vector& cellScalarValuesHistogram(size_t scalarResultIndex, size_t timeStepIndex); void p10p90CellScalarValues(size_t scalarResultIndex, double& p10, double& p90); + void p10p90CellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& p10, double& p90); void meanCellScalarValues(size_t scalarResultIndex, double& meanValue); + void meanCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue); // Access meta-information about the results size_t resultCount() const; diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp index 5b4a7182b4..dff04de95e 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp @@ -39,20 +39,8 @@ RigStatisticsDataCache::RigStatisticsDataCache(RigStatisticsCalculator* statisti //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::clearAllStatistics() { - m_minValue = HUGE_VAL; - m_maxValue = -HUGE_VAL; - m_isMaxMinCalculated = false; - m_posClosestToZero = HUGE_VAL; - m_negClosestToZero = -HUGE_VAL; - m_isClosestToZeroCalculated = false; - m_p10 = HUGE_VAL; - m_p90 = HUGE_VAL; - m_meanValue = HUGE_VAL; - m_isMeanCalculated = false; - - m_histogram.clear(); - m_maxMinValuesPrTs.clear(); - m_posNegClosestToZeroPrTs.clear(); + m_statsAllTimesteps = StatisticsValues(); + m_statsPrTs.clear(); } //-------------------------------------------------------------------------------------------------- @@ -60,7 +48,7 @@ void RigStatisticsDataCache::clearAllStatistics() //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::minMaxCellScalarValues(double& min, double& max) { - if (!m_isMaxMinCalculated) + if (!m_statsAllTimesteps.m_isMaxMinCalculated) { min = HUGE_VAL; max = -HUGE_VAL; @@ -74,13 +62,13 @@ void RigStatisticsDataCache::minMaxCellScalarValues(double& min, double& max) if (tsmax > max) max = tsmax; } - m_minValue = min; - m_maxValue = max; - m_isMaxMinCalculated = true; + m_statsAllTimesteps.m_minValue = min; + m_statsAllTimesteps.m_maxValue = max; + m_statsAllTimesteps.m_isMaxMinCalculated = true; } - min = m_minValue; - max = m_maxValue; + min = m_statsAllTimesteps.m_minValue; + max = m_statsAllTimesteps.m_maxValue; } //-------------------------------------------------------------------------------------------------- @@ -88,27 +76,26 @@ void RigStatisticsDataCache::minMaxCellScalarValues(double& min, double& max) //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) { - if (timeStepIndex >= m_maxMinValuesPrTs.size()) + if (timeStepIndex >= m_statsPrTs.size()) { - m_maxMinValuesPrTs.resize(timeStepIndex + 1, std::make_pair(HUGE_VAL, -HUGE_VAL)); - m_isMaxMinPrTsCalculated.resize(timeStepIndex + 1, false); + m_statsPrTs.resize(timeStepIndex + 1); } - if (!m_isMaxMinPrTsCalculated[timeStepIndex]) + if (!m_statsPrTs[timeStepIndex].m_isMaxMinCalculated) { double tsMin = HUGE_VAL; double tsMax = -HUGE_VAL; m_statisticsCalculator->minMaxCellScalarValues(timeStepIndex, tsMin, tsMax); - m_maxMinValuesPrTs[timeStepIndex].first = tsMin; - m_maxMinValuesPrTs[timeStepIndex].second = tsMax; + m_statsPrTs[timeStepIndex].m_minValue = tsMin; + m_statsPrTs[timeStepIndex].m_maxValue = tsMax; - m_isMaxMinPrTsCalculated[timeStepIndex] = true; + m_statsPrTs[timeStepIndex].m_isMaxMinCalculated = true; } - min = m_maxMinValuesPrTs[timeStepIndex].first; - max = m_maxMinValuesPrTs[timeStepIndex].second; + min = m_statsPrTs[timeStepIndex].m_minValue; + max = m_statsPrTs[timeStepIndex].m_maxValue; } //-------------------------------------------------------------------------------------------------- @@ -116,7 +103,7 @@ void RigStatisticsDataCache::minMaxCellScalarValues(size_t timeStepIndex, double //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::posNegClosestToZero(double& pos, double& neg) { - if (!m_isClosestToZeroCalculated) + if (!m_statsAllTimesteps.m_isClosestToZeroCalculated) { pos = HUGE_VAL; neg = -HUGE_VAL; @@ -130,13 +117,13 @@ void RigStatisticsDataCache::posNegClosestToZero(double& pos, double& neg) if (tsPos < pos && tsPos > 0) pos = tsPos; } - m_posClosestToZero = pos; - m_negClosestToZero = neg; - m_isClosestToZeroCalculated = true; + m_statsAllTimesteps.m_posClosestToZero = pos; + m_statsAllTimesteps.m_negClosestToZero = neg; + m_statsAllTimesteps.m_isClosestToZeroCalculated = true; } - pos = m_posClosestToZero; - neg = m_negClosestToZero; + pos = m_statsAllTimesteps.m_posClosestToZero; + neg = m_statsAllTimesteps.m_negClosestToZero; } //-------------------------------------------------------------------------------------------------- @@ -144,13 +131,12 @@ void RigStatisticsDataCache::posNegClosestToZero(double& pos, double& neg) //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::posNegClosestToZero(size_t timeStepIndex, double& posNearZero, double& negNearZero) { - if (timeStepIndex >= m_posNegClosestToZeroPrTs.size()) + if (timeStepIndex >= m_statsPrTs.size()) { - m_posNegClosestToZeroPrTs.resize(timeStepIndex + 1, std::make_pair(HUGE_VAL, -HUGE_VAL)); - m_isClosestToZeroPrTsCalculated.resize(timeStepIndex + 1, false); + m_statsPrTs.resize(timeStepIndex + 1); } - if (!m_isClosestToZeroPrTsCalculated[timeStepIndex]) + if (!m_statsPrTs[timeStepIndex].m_isClosestToZeroCalculated) { double pos = HUGE_VAL; @@ -158,14 +144,14 @@ void RigStatisticsDataCache::posNegClosestToZero(size_t timeStepIndex, double& p m_statisticsCalculator->posNegClosestToZero(timeStepIndex, pos, neg); - m_posNegClosestToZeroPrTs[timeStepIndex].first = pos; - m_posNegClosestToZeroPrTs[timeStepIndex].second = neg; + m_statsPrTs[timeStepIndex].m_posClosestToZero = pos; + m_statsPrTs[timeStepIndex].m_negClosestToZero = neg; - m_isClosestToZeroPrTsCalculated[timeStepIndex] = true; + m_statsPrTs[timeStepIndex].m_isClosestToZeroCalculated = true; } - posNearZero = m_posNegClosestToZeroPrTs[timeStepIndex].first; - negNearZero = m_posNegClosestToZeroPrTs[timeStepIndex].second; + posNearZero = m_statsPrTs[timeStepIndex].m_posClosestToZero; + negNearZero = m_statsPrTs[timeStepIndex].m_negClosestToZero; } //-------------------------------------------------------------------------------------------------- @@ -173,9 +159,19 @@ void RigStatisticsDataCache::posNegClosestToZero(size_t timeStepIndex, double& p //-------------------------------------------------------------------------------------------------- const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram() { - computeStatisticsIfNeeded(); + computeHistogramStatisticsIfNeeded(); - return m_histogram; + return m_statsAllTimesteps.m_histogram; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram(size_t timeStepIndex) +{ + computeHistogramStatisticsIfNeeded(timeStepIndex); + + return m_statsPrTs[timeStepIndex].m_histogram; } //-------------------------------------------------------------------------------------------------- @@ -183,11 +179,21 @@ const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram() //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::p10p90CellScalarValues(double& p10, double& p90) { - // First make sure they are calculated - computeStatisticsIfNeeded(); + computeHistogramStatisticsIfNeeded(); - p10 = m_p10; - p90 = m_p90; + p10 = m_statsAllTimesteps.m_p10; + p90 = m_statsAllTimesteps.m_p90; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsDataCache::p10p90CellScalarValues(size_t timeStepIndex, double& p10, double& p90) +{ + computeHistogramStatisticsIfNeeded(timeStepIndex); + + p10 = m_statsPrTs[timeStepIndex].m_p10; + p90 = m_statsPrTs[timeStepIndex].m_p90; } //-------------------------------------------------------------------------------------------------- @@ -195,33 +201,68 @@ void RigStatisticsDataCache::p10p90CellScalarValues(double& p10, double& p90) //-------------------------------------------------------------------------------------------------- void RigStatisticsDataCache::meanCellScalarValues(double& meanValue) { - if (!m_isMeanCalculated) + if (!m_statsAllTimesteps.m_isMeanCalculated) + { + m_statisticsCalculator->meanCellScalarValue(m_statsAllTimesteps.m_meanValue); + m_statsAllTimesteps.m_isMeanCalculated = true; + } + + meanValue = m_statsAllTimesteps.m_meanValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsDataCache::meanCellScalarValues(size_t timeStepIndex, double& meanValue) +{ + if (!m_statsPrTs[timeStepIndex].m_isMeanCalculated) { - m_statisticsCalculator->meanCellScalarValue(m_meanValue); - m_isMeanCalculated = true; + m_statisticsCalculator->meanCellScalarValue(timeStepIndex, m_statsPrTs[timeStepIndex].m_meanValue); + m_statsPrTs[timeStepIndex].m_isMeanCalculated = true; } - meanValue = m_meanValue; + meanValue = m_statsPrTs[timeStepIndex].m_meanValue; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigStatisticsDataCache::computeStatisticsIfNeeded() +void RigStatisticsDataCache::computeHistogramStatisticsIfNeeded() { - if (m_histogram.size() == 0) + if (m_statsAllTimesteps.m_histogram.size() == 0) { double min; double max; size_t nBins = 100; this->minMaxCellScalarValues(min, max); - RigHistogramCalculator histCalc(min, max, nBins, &m_histogram); + RigHistogramCalculator histCalc(min, max, nBins, &m_statsAllTimesteps.m_histogram); m_statisticsCalculator->addDataToHistogramCalculator(histCalc); - m_p10 = histCalc.calculatePercentil(0.1); - m_p90 = histCalc.calculatePercentil(0.9); + m_statsAllTimesteps.m_p10 = histCalc.calculatePercentil(0.1); + m_statsAllTimesteps.m_p90 = histCalc.calculatePercentil(0.9); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsDataCache::computeHistogramStatisticsIfNeeded(size_t timeStepIndex) +{ + if (m_statsPrTs[timeStepIndex].m_histogram.size() == 0) + { + double min; + double max; + size_t nBins = 100; + this->minMaxCellScalarValues(min, max); + + RigHistogramCalculator histCalc(min, max, nBins, &m_statsPrTs[timeStepIndex].m_histogram); + + m_statisticsCalculator->addDataToHistogramCalculator(timeStepIndex, histCalc); + + m_statsPrTs[timeStepIndex].m_p10 = histCalc.calculatePercentil(0.1); + m_statsPrTs[timeStepIndex].m_p90 = histCalc.calculatePercentil(0.9); } } diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h index ae4c262f35..4926a0a68c 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h @@ -39,37 +39,60 @@ class RigStatisticsDataCache : public cvf::Object void minMaxCellScalarValues(double& min, double& max); void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); + void posNegClosestToZero(double& pos, double& neg); void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); void p10p90CellScalarValues(double& p10, double& p90); + void p10p90CellScalarValues(size_t timeStepIndex, double& p10, double& p90); + void meanCellScalarValues(double& meanValue); + void meanCellScalarValues(size_t timeStepIndex, double& meanValue); + const std::vector& cellScalarValuesHistogram(); + const std::vector& cellScalarValuesHistogram(size_t timeStepIndex); private: - void computeStatisticsIfNeeded(); + void computeHistogramStatisticsIfNeeded(); + void computeHistogramStatisticsIfNeeded(size_t timeStepIndex); private: - double m_minValue; - double m_maxValue; - bool m_isMaxMinCalculated; - - double m_posClosestToZero; - double m_negClosestToZero; - bool m_isClosestToZeroCalculated; - - double m_p10; - double m_p90; - double m_meanValue; - bool m_isMeanCalculated; - - std::vector m_histogram; - - std::vector > m_maxMinValuesPrTs; ///< Max min values for each time step - std::vector m_isMaxMinPrTsCalculated; - std::vector > m_posNegClosestToZeroPrTs; ///< PosNeg values for each time step - std::vector m_isClosestToZeroPrTsCalculated; - - cvf::ref m_statisticsCalculator; + struct StatisticsValues + { + StatisticsValues() + { + m_minValue = HUGE_VAL; + m_maxValue = -HUGE_VAL; + m_isMaxMinCalculated = false; + m_meanValue = HUGE_VAL; + m_isMeanCalculated = false; + m_posClosestToZero = HUGE_VAL; + m_negClosestToZero = -HUGE_VAL; + m_isClosestToZeroCalculated = false; + m_p10 = HUGE_VAL; + m_p90 = HUGE_VAL; + } + + double m_minValue; + double m_maxValue; + bool m_isMaxMinCalculated; + + double m_meanValue; + bool m_isMeanCalculated; + + double m_posClosestToZero; + double m_negClosestToZero; + bool m_isClosestToZeroCalculated; + + double m_p10; + double m_p90; + + std::vector m_histogram; + }; + + StatisticsValues m_statsAllTimesteps; + std::vector m_statsPrTs; + + cvf::ref m_statisticsCalculator; }; From b64d34c79171d59f3fa70d44f40eaa3f4989a195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 15:53:21 +0100 Subject: [PATCH 003/290] Rename of StatCalc classes --- .../ReservoirDataModel/CMakeLists_files.cmake | 8 +++---- .../RigCaseCellResultsData.cpp | 16 +++++++------- ...pp => RigEclipseMultiPropertyStatCalc.cpp} | 22 +++++++++---------- ...lc.h => RigEclipseMultiPropertyStatCalc.h} | 4 ++-- ...tCalc.cpp => RigEclipseNativeStatCalc.cpp} | 14 ++++++------ ...eStatCalc.h => RigEclipseNativeStatCalc.h} | 4 ++-- 6 files changed, 34 insertions(+), 34 deletions(-) rename ApplicationCode/ReservoirDataModel/{RigMultipleDatasetStatCalc.cpp => RigEclipseMultiPropertyStatCalc.cpp} (78%) rename ApplicationCode/ReservoirDataModel/{RigMultipleDatasetStatCalc.h => RigEclipseMultiPropertyStatCalc.h} (94%) rename ApplicationCode/ReservoirDataModel/{RigNativeStatCalc.cpp => RigEclipseNativeStatCalc.cpp} (85%) rename ApplicationCode/ReservoirDataModel/{RigNativeStatCalc.h => RigEclipseNativeStatCalc.h} (91%) diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 21ddac0704..33f6106e01 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -34,8 +34,8 @@ ${CEE_CURRENT_LIST_DIR}cvfGeometryTools.inl ${CEE_CURRENT_LIST_DIR}RigPipeInCellEvaluator.h ${CEE_CURRENT_LIST_DIR}RigResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.h -${CEE_CURRENT_LIST_DIR}RigNativeStatCalc.h -${CEE_CURRENT_LIST_DIR}RigMultipleDatasetStatCalc.h +${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h +${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.h ) @@ -65,8 +65,8 @@ ${CEE_CURRENT_LIST_DIR}RigFault.cpp ${CEE_CURRENT_LIST_DIR}RigNNCData.cpp ${CEE_CURRENT_LIST_DIR}cvfGeometryTools.cpp ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.cpp -${CEE_CURRENT_LIST_DIR}RigNativeStatCalc.cpp -${CEE_CURRENT_LIST_DIR}RigMultipleDatasetStatCalc.cpp +${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.cpp +${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.cpp ) diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 885b24d48e..48f2aa9083 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -23,8 +23,8 @@ #include "RigMainGrid.h" #include "RigStatisticsDataCache.h" #include "RigStatisticsMath.h" -#include "RigMultipleDatasetStatCalc.h" -#include "RigNativeStatCalc.h" +#include "RigEclipseMultiPropertyStatCalc.h" +#include "RigEclipseNativeStatCalc.h" #include #include @@ -249,7 +249,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty if (resultName == RimDefines::combinedTransmissibilityResultName()) { - cvf::ref calc = new RigMultipleDatasetStatCalc(); + cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, "TRANX")); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, "TRANY")); @@ -259,7 +259,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty } else if (resultName == RimDefines::combinedMultResultName()) { - cvf::ref calc = new RigMultipleDatasetStatCalc(); + cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, "MULTX")); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, "MULTX-")); @@ -272,7 +272,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty } else if (resultName == RimDefines::combinedRiTranResultName()) { - cvf::ref calc = new RigMultipleDatasetStatCalc(); + cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riTranXResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riTranYResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riTranZResultName())); @@ -280,7 +280,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty } else if (resultName == RimDefines::combinedRiMultResultName()) { - cvf::ref calc = new RigMultipleDatasetStatCalc(); + cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riMultXResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riMultYResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riMultZResultName())); @@ -288,7 +288,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty } else if (resultName == RimDefines::combinedRiAreaNormTranResultName()) { - cvf::ref calc = new RigMultipleDatasetStatCalc(); + cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riAreaNormTranXResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riAreaNormTranYResultName())); calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RimDefines::STATIC_NATIVE, RimDefines::riAreaNormTranZResultName())); @@ -296,7 +296,7 @@ size_t RigCaseCellResultsData::addEmptyScalarResult(RimDefines::ResultCatType ty } else { - statisticsCalculator = new RigNativeStatCalc(this, scalarResultIndex); + statisticsCalculator = new RigEclipseNativeStatCalc(this, scalarResultIndex); } cvf::ref dataCache = new RigStatisticsDataCache(statisticsCalculator.p()); diff --git a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp similarity index 78% rename from ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp rename to ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp index ba654ccf16..7bceecbf91 100644 --- a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp @@ -17,21 +17,21 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RigMultipleDatasetStatCalc.h" -#include "RigNativeStatCalc.h" +#include "RigEclipseMultiPropertyStatCalc.h" +#include "RigEclipseNativeStatCalc.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigMultipleDatasetStatCalc::RigMultipleDatasetStatCalc() +RigEclipseMultiPropertyStatCalc::RigEclipseMultiPropertyStatCalc() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::addStatisticsCalculator(RigStatisticsCalculator* statisticsCalculator) +void RigEclipseMultiPropertyStatCalc::addStatisticsCalculator(RigStatisticsCalculator* statisticsCalculator) { if (statisticsCalculator) { @@ -42,7 +42,7 @@ void RigMultipleDatasetStatCalc::addStatisticsCalculator(RigStatisticsCalculator //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +void RigEclipseMultiPropertyStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { @@ -56,7 +56,7 @@ void RigMultipleDatasetStatCalc::minMaxCellScalarValues(size_t timeStepIndex, do //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +void RigEclipseMultiPropertyStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { @@ -71,7 +71,7 @@ void RigMultipleDatasetStatCalc::posNegClosestToZero(size_t timeStepIndex, doubl //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +void RigEclipseMultiPropertyStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { @@ -86,7 +86,7 @@ void RigMultipleDatasetStatCalc::valueSumAndSampleCount(size_t timeStepIndex, do //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +void RigEclipseMultiPropertyStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { for (size_t i = 0; i < m_nativeStatisticsCalculators.size(); i++) { @@ -100,7 +100,7 @@ void RigMultipleDatasetStatCalc::addDataToHistogramCalculator(size_t timeStepInd //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigMultipleDatasetStatCalc::timeStepCount() +size_t RigEclipseMultiPropertyStatCalc::timeStepCount() { if (m_nativeStatisticsCalculators.size() > 0) { @@ -113,11 +113,11 @@ size_t RigMultipleDatasetStatCalc::timeStepCount() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigMultipleDatasetStatCalc::addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) +void RigEclipseMultiPropertyStatCalc::addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) { if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) { - this->addStatisticsCalculator(new RigNativeStatCalc(cellResultsData, scalarResultIndex)); + this->addStatisticsCalculator(new RigEclipseNativeStatCalc(cellResultsData, scalarResultIndex)); } } diff --git a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h similarity index 94% rename from ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h rename to ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h index b36e4e1aa3..6a85fa2afb 100644 --- a/ApplicationCode/ReservoirDataModel/RigMultipleDatasetStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h @@ -34,10 +34,10 @@ class RigCaseCellResultsData; //================================================================================================== /// //================================================================================================== -class RigMultipleDatasetStatCalc : public RigStatisticsCalculator +class RigEclipseMultiPropertyStatCalc : public RigStatisticsCalculator { public: - RigMultipleDatasetStatCalc(); + RigEclipseMultiPropertyStatCalc(); void addStatisticsCalculator(RigStatisticsCalculator* statisticsCalculator); void addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndices); diff --git a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp similarity index 85% rename from ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp rename to ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp index d6d1a6ac99..a152114abf 100644 --- a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RigNativeStatCalc.h" +#include "RigEclipseNativeStatCalc.h" #include "RigStatisticsMath.h" #include "RigCaseCellResultsData.h" @@ -29,7 +29,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigNativeStatCalc::RigNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) +RigEclipseNativeStatCalc::RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) : m_resultsData(cellResultsData), m_scalarResultIndex(scalarResultIndex) { @@ -39,7 +39,7 @@ RigNativeStatCalc::RigNativeStatCalc(RigCaseCellResultsData* cellResultsData, si //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +void RigEclipseNativeStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) { std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); @@ -66,7 +66,7 @@ void RigNativeStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +void RigEclipseNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) { std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); @@ -94,7 +94,7 @@ void RigNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, d //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +void RigEclipseNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); @@ -106,7 +106,7 @@ void RigNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +void RigEclipseNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); size_t undefValueCount = 0; @@ -129,7 +129,7 @@ void RigNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& val //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigNativeStatCalc::timeStepCount() +size_t RigEclipseNativeStatCalc::timeStepCount() { return m_resultsData->timeStepCount(m_scalarResultIndex); } diff --git a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h similarity index 91% rename from ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h rename to ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h index 929888dcae..2ad79f4c4d 100644 --- a/ApplicationCode/ReservoirDataModel/RigNativeStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h @@ -31,10 +31,10 @@ class RigCaseCellResultsData; //================================================================================================== /// //================================================================================================== -class RigNativeStatCalc : public RigStatisticsCalculator +class RigEclipseNativeStatCalc : public RigStatisticsCalculator { public: - RigNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex); + RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex); virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); From f77a92a77b74681532fe0312e4efa014725bc933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 15:57:06 +0100 Subject: [PATCH 004/290] Rename TrackPlot/PlotTrack classes to Track --- .../Commands/RicDeleteItemExec.cpp | 2 +- .../RicAddWellLogToPlotFeature.cpp | 2 +- .../RicDeleteWellLogPlotTrackFeature.cpp | 6 +-- .../RicNewWellLogCurveExtractionFeature.cpp | 10 ++-- .../RicNewWellLogCurveExtractionFeature.h | 6 +-- .../RicNewWellLogFileCurveFeature.cpp | 12 ++--- .../RicNewWellLogFileCurveFeature.h | 8 ++-- .../RicNewWellLogPlotFeature.cpp | 2 +- .../RicNewWellLogPlotFeatureImpl.cpp | 4 +- .../RicNewWellLogPlotFeatureImpl.h | 4 +- .../RicNewWellLogPlotTrackFeature.cpp | 2 +- .../RicWellLogPlotTrackFeatureImpl.cpp | 14 +++--- .../RicWellLogPlotTrackFeatureImpl.h | 8 ++-- .../ProjectDataModel/RimProject.cpp | 2 +- .../ProjectDataModel/RimWellLogPlot.cpp | 12 ++--- .../ProjectDataModel/RimWellLogPlot.h | 14 +++--- .../ProjectDataModel/RimWellLogPlotCurve.cpp | 6 +-- .../ProjectDataModel/RimWellLogPlotCurve.h | 6 +-- .../ProjectDataModel/RimWellLogPlotTrack.cpp | 46 +++++++++---------- .../ProjectDataModel/RimWellLogPlotTrack.h | 12 ++--- ApplicationCode/UserInterface/RiuDragDrop.cpp | 20 ++++---- ApplicationCode/UserInterface/RiuDragDrop.h | 4 +- .../UserInterface/RiuWellLogPlot.cpp | 6 +-- .../UserInterface/RiuWellLogPlot.h | 10 ++-- .../UserInterface/RiuWellLogTrackPlot.cpp | 24 +++++----- .../UserInterface/RiuWellLogTrackPlot.h | 10 ++-- 26 files changed, 126 insertions(+), 126 deletions(-) diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 184c982563..85ae9a4c80 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -120,7 +120,7 @@ void RicDeleteItemExec::redo() wellLogPlot->zoomAllDepth(); } - RimWellLogPlotTrack* wellLogPlotTrack; + RimWellLogTrack* wellLogPlotTrack; parentObj->firstAnchestorOrThisOfType(wellLogPlotTrack); if (wellLogPlotTrack) { diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index dd966b8043..9d70eec660 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -68,7 +68,7 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) RimWellLogPlot* plot = RicNewWellLogPlotFeatureImpl::createWellLogPlot(); - RimWellLogPlotTrack* plotTrack = new RimWellLogPlotTrack(); + RimWellLogTrack* plotTrack = new RimWellLogTrack(); plot->addTrack(plotTrack); plotTrack->setDescription(QString("Track %1").arg(plot->trackCount())); diff --git a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp index a6efaedfd5..12bca0e1e7 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp @@ -34,7 +34,7 @@ CAF_CMD_SOURCE_INIT(RicDeleteWellLogPlotTrackFeature, "RicDeleteWellLogPlotTrack //-------------------------------------------------------------------------------------------------- bool RicDeleteWellLogPlotTrackFeature::isCommandEnabled() { - std::vector selection; + std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); if (selection.size() > 0) @@ -55,12 +55,12 @@ bool RicDeleteWellLogPlotTrackFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicDeleteWellLogPlotTrackFeature::onActionTriggered(bool isChecked) { - std::vector selection; + std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); for (size_t i = 0; i < selection.size(); i++) { - RimWellLogPlotTrack* track = selection[i]; + RimWellLogTrack* track = selection[i]; RimWellLogPlot* wellLogPlot = NULL; track->firstAnchestorOrThisOfType(wellLogPlot); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index b862b28307..e4cbdfb00a 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -54,7 +54,7 @@ bool RicNewWellLogCurveExtractionFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicNewWellLogCurveExtractionFeature::onActionTriggered(bool isChecked) { - RimWellLogPlotTrack* wellLogPlotTrack = selectedWellLogPlotTrack(); + RimWellLogTrack* wellLogPlotTrack = selectedWellLogPlotTrack(); if (wellLogPlotTrack) { addCurve(wellLogPlotTrack, NULL, NULL); @@ -64,7 +64,7 @@ void RicNewWellLogCurveExtractionFeature::onActionTriggered(bool isChecked) RimWellPath* wellPath = selectedWellPath(); if (wellPath) { - RimWellLogPlotTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); + RimWellLogTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); RimWellLogExtractionCurve* plotCurve = addCurve(wellLogPlotTrack, RiaApplication::instance()->activeReservoirView(), wellPath); plotCurve->updatePlotData(); @@ -84,9 +84,9 @@ void RicNewWellLogCurveExtractionFeature::setupActionLook(QAction* actionToSetup //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotTrack* RicNewWellLogCurveExtractionFeature::selectedWellLogPlotTrack() const +RimWellLogTrack* RicNewWellLogCurveExtractionFeature::selectedWellLogPlotTrack() const { - std::vector selection; + std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); return selection.size() > 0 ? selection[0] : NULL; } @@ -115,7 +115,7 @@ bool RicNewWellLogCurveExtractionFeature::caseAvailable() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogExtractionCurve* RicNewWellLogCurveExtractionFeature::addCurve(RimWellLogPlotTrack* plotTrack, RimView* view, RimWellPath* wellPath) +RimWellLogExtractionCurve* RicNewWellLogCurveExtractionFeature::addCurve(RimWellLogTrack* plotTrack, RimView* view, RimWellPath* wellPath) { CVF_ASSERT(plotTrack); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h index 84fe43c76a..97d33a9b70 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h @@ -22,7 +22,7 @@ #include "cafCmdFeature.h" class RimWellLogExtractionCurve; -class RimWellLogPlotTrack; +class RimWellLogTrack; class RimWellPath; class RimView; @@ -34,7 +34,7 @@ class RicNewWellLogCurveExtractionFeature : public caf::CmdFeature CAF_CMD_HEADER_INIT; public: - static RimWellLogExtractionCurve* addCurve(RimWellLogPlotTrack* plotTrack, RimView* view, RimWellPath* wellPath); + static RimWellLogExtractionCurve* addCurve(RimWellLogTrack* plotTrack, RimView* view, RimWellPath* wellPath); protected: @@ -44,7 +44,7 @@ class RicNewWellLogCurveExtractionFeature : public caf::CmdFeature virtual void setupActionLook( QAction* actionToSetup ); private: - RimWellLogPlotTrack* selectedWellLogPlotTrack() const; + RimWellLogTrack* selectedWellLogPlotTrack() const; RimWellPath* selectedWellPath() const; bool caseAvailable() const; }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp index 2fbcb81055..c75ba4ab8f 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp @@ -56,7 +56,7 @@ bool RicNewWellLogFileCurveFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicNewWellLogFileCurveFeature::onActionTriggered(bool isChecked) { - RimWellLogPlotTrack* wellLogPlotTrack = selectedWellLogPlotTrack(); + RimWellLogTrack* wellLogPlotTrack = selectedWellLogPlotTrack(); if (wellLogPlotTrack) { addCurve(wellLogPlotTrack); @@ -66,7 +66,7 @@ void RicNewWellLogFileCurveFeature::onActionTriggered(bool isChecked) RimWellPath* wellPath = selectedWellPathWithLogFile(); if (wellPath) { - RimWellLogPlotTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); + RimWellLogTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); RimWellLogFileCurve* plotCurve = addCurve(wellLogPlotTrack); plotCurve->setWellPath(wellPath); plotCurve->updateConnectedEditors(); @@ -85,9 +85,9 @@ void RicNewWellLogFileCurveFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotTrack* RicNewWellLogFileCurveFeature::selectedWellLogPlotTrack() const +RimWellLogTrack* RicNewWellLogFileCurveFeature::selectedWellLogPlotTrack() const { - std::vector selection; + std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); return selection.size() > 0 ? selection[0] : NULL; } @@ -140,7 +140,7 @@ bool RicNewWellLogFileCurveFeature::wellLogFilesAvailable() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogFileCurve* RicNewWellLogFileCurveFeature::addCurve(RimWellLogPlotTrack* plotTrack) +RimWellLogFileCurve* RicNewWellLogFileCurveFeature::addCurve(RimWellLogTrack* plotTrack) { CVF_ASSERT(plotTrack); @@ -162,7 +162,7 @@ RimWellLogFileCurve* RicNewWellLogFileCurveFeature::addCurve(RimWellLogPlotTrack //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicNewWellLogFileCurveFeature::addWellLogChannelsToPlotTrack(RimWellLogPlotTrack* plotTrack, const std::vector& wellLogFileChannels) +void RicNewWellLogFileCurveFeature::addWellLogChannelsToPlotTrack(RimWellLogTrack* plotTrack, const std::vector& wellLogFileChannels) { for (size_t cIdx = 0; cIdx < wellLogFileChannels.size(); cIdx++) { diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h index 0c42f4a19c..d5991817c2 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h @@ -23,7 +23,7 @@ #include -class RimWellLogPlotTrack; +class RimWellLogTrack; class RimWellLogFileCurve; class RimWellPath; class RimWellLogFileChannel; @@ -37,9 +37,9 @@ class RicNewWellLogFileCurveFeature : public caf::CmdFeature CAF_CMD_HEADER_INIT; public: - static RimWellLogFileCurve* addCurve(RimWellLogPlotTrack* plotTrack); + static RimWellLogFileCurve* addCurve(RimWellLogTrack* plotTrack); - static void addWellLogChannelsToPlotTrack(RimWellLogPlotTrack* plotTrack, const std::vector& wellLogFileChannels); + static void addWellLogChannelsToPlotTrack(RimWellLogTrack* plotTrack, const std::vector& wellLogFileChannels); protected: // Overrides @@ -48,7 +48,7 @@ class RicNewWellLogFileCurveFeature : public caf::CmdFeature virtual void setupActionLook( QAction* actionToSetup ); private: - RimWellLogPlotTrack* selectedWellLogPlotTrack() const; + RimWellLogTrack* selectedWellLogPlotTrack() const; RimWellPath* selectedWellPathWithLogFile() const; bool wellLogFilesAvailable() const; }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp index 3f90c9d037..e456116c1e 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp @@ -50,7 +50,7 @@ bool RicNewWellLogPlotFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicNewWellLogPlotFeature::onActionTriggered(bool isChecked) { - RimWellLogPlotTrack* plotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); + RimWellLogTrack* plotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); RicNewWellLogCurveExtractionFeature::addCurve(plotTrack, NULL, NULL); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp index bc5cf34067..7e7671ddf0 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp @@ -83,11 +83,11 @@ RimWellLogPlot* RicNewWellLogPlotFeatureImpl::createWellLogPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotTrack* RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack() +RimWellLogTrack* RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack() { RimWellLogPlot* plot = createWellLogPlot(); - RimWellLogPlotTrack* plotTrack = new RimWellLogPlotTrack(); + RimWellLogTrack* plotTrack = new RimWellLogTrack(); plot->addTrack(plotTrack); plotTrack->setDescription(QString("Track %1").arg(plot->trackCount())); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h index f681dc1998..c50de7d82a 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h @@ -22,7 +22,7 @@ class RimMainPlotCollection; class RimWellLogPlotCollection; class RimWellLogPlot; -class RimWellLogPlotTrack; +class RimWellLogTrack; //================================================================================================== /// @@ -34,5 +34,5 @@ class RicNewWellLogPlotFeatureImpl static RimMainPlotCollection* mainPlotCollection(); static RimWellLogPlotCollection* wellLogPlotCollection(); static RimWellLogPlot* createWellLogPlot(); - static RimWellLogPlotTrack* createWellLogPlotTrack(); + static RimWellLogTrack* createWellLogPlotTrack(); }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp index f988a934bb..446798da8b 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp @@ -49,7 +49,7 @@ void RicNewWellLogPlotTrackFeature::onActionTriggered(bool isChecked) RimWellLogPlot* wellLogPlot = selectedWellLogPlot(); if (wellLogPlot) { - RimWellLogPlotTrack* plotTrack = new RimWellLogPlotTrack; + RimWellLogTrack* plotTrack = new RimWellLogTrack; wellLogPlot->addTrack(plotTrack); plotTrack->setDescription(QString("Track %1").arg(wellLogPlot->trackCount())); diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp index 3d69d234ce..24dad36f64 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp @@ -30,20 +30,20 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogPlotTrack* destTrack, +void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogTrack* destTrack, const std::vector& curves, RimWellLogPlotCurve* curveToInsertAfter) { CVF_ASSERT(destTrack ); - std::set srcTracks; + std::set srcTracks; std::set srcPlots; for (size_t cIdx = 0; cIdx < curves.size(); cIdx++) { RimWellLogPlotCurve* curve = curves[cIdx]; - RimWellLogPlotTrack* wellLogPlotTrack; + RimWellLogTrack* wellLogPlotTrack; curve->firstAnchestorOrThisOfType(wellLogPlotTrack); if (wellLogPlotTrack) { @@ -69,7 +69,7 @@ void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogPlot (*pIt)->calculateAvailableDepthRange(); } - for (std::set::iterator tIt = srcTracks.begin(); tIt != srcTracks.end(); ++tIt) + for (std::set::iterator tIt = srcTracks.begin(); tIt != srcTracks.end(); ++tIt) { (*tIt)->zoomAllXAndZoomAllDepthOnOwnerPlot(); } @@ -83,8 +83,8 @@ void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogPlot /// //-------------------------------------------------------------------------------------------------- void RicWellLogPlotTrackFeatureImpl::moveTracksToWellLogPlot(RimWellLogPlot* dstWellLogPlot, - const std::vector& tracksToMove, - RimWellLogPlotTrack* trackToInsertAfter) + const std::vector& tracksToMove, + RimWellLogTrack* trackToInsertAfter) { CVF_ASSERT(dstWellLogPlot); @@ -92,7 +92,7 @@ void RicWellLogPlotTrackFeatureImpl::moveTracksToWellLogPlot(RimWellLogPlot* dst for (size_t tIdx = 0; tIdx < tracksToMove.size(); tIdx++) { - RimWellLogPlotTrack* track = tracksToMove[tIdx]; + RimWellLogTrack* track = tracksToMove[tIdx]; RimWellLogPlot* srcPlot; track->firstAnchestorOrThisOfType(srcPlot); diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h index 2f4fdaf71d..e9eee75395 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h @@ -22,7 +22,7 @@ #include class RimWellLogPlot; -class RimWellLogPlotTrack; +class RimWellLogTrack; class RimWellLogPlotCurve; //================================================================================================== @@ -32,10 +32,10 @@ class RicWellLogPlotTrackFeatureImpl { public: - static void moveCurvesToWellLogPlotTrack(RimWellLogPlotTrack* dstTrack, + static void moveCurvesToWellLogPlotTrack(RimWellLogTrack* dstTrack, const std::vector& curves, RimWellLogPlotCurve* insertAfterCurve); static void moveTracksToWellLogPlot(RimWellLogPlot* wellLogPlot, - const std::vector& tracks, - RimWellLogPlotTrack* trackToInsertAfter); + const std::vector& tracks, + RimWellLogTrack* trackToInsertAfter); }; diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index f0c24a21ff..045bb8adff 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -814,7 +814,7 @@ void RimProject::actionsBasedOnSelection(QMenu& contextMenu) commandIds << "RicNewWellLogPlotTrackFeature"; commandIds << "RicDeleteItemFeature"; } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) { commandIds << "RicNewWellLogCurveExtractionFeature"; commandIds << "RicNewWellLogFileCurveFeature"; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index cccff5c598..be6dbb6727 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -167,7 +167,7 @@ caf::PdmFieldHandle* RimWellLogPlot::objectToggleField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::addTrack(RimWellLogPlotTrack* track) +void RimWellLogPlot::addTrack(RimWellLogTrack* track) { m_tracks.push_back(track); if (m_viewer) @@ -182,7 +182,7 @@ void RimWellLogPlot::addTrack(RimWellLogPlotTrack* track) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::insertTrack(RimWellLogPlotTrack* track, size_t index) +void RimWellLogPlot::insertTrack(RimWellLogTrack* track, size_t index) { m_tracks.insert(index, track); @@ -198,7 +198,7 @@ void RimWellLogPlot::insertTrack(RimWellLogPlotTrack* track, size_t index) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::removeTrack(RimWellLogPlotTrack* track) +void RimWellLogPlot::removeTrack(RimWellLogTrack* track) { if (track) { @@ -210,11 +210,11 @@ void RimWellLogPlot::removeTrack(RimWellLogPlotTrack* track) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::moveTracks(RimWellLogPlotTrack* insertAfterTrack, const std::vector& tracksToMove) +void RimWellLogPlot::moveTracks(RimWellLogTrack* insertAfterTrack, const std::vector& tracksToMove) { for (size_t tIdx = 0; tIdx < tracksToMove.size(); tIdx++) { - RimWellLogPlotTrack* track = tracksToMove[tIdx]; + RimWellLogTrack* track = tracksToMove[tIdx]; RimWellLogPlot* wellLogPlot; track->firstAnchestorOrThisOfType(wellLogPlot); @@ -534,7 +534,7 @@ QString RimWellLogPlot::depthPlotTitle() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RimWellLogPlot::trackIndex(RimWellLogPlotTrack* track) +size_t RimWellLogPlot::trackIndex(RimWellLogTrack* track) { return m_tracks.index(track); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index 3f86ca434a..544c1befc3 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -27,7 +27,7 @@ #include class RiuWellLogPlot; -class RimWellLogPlotTrack; +class RimWellLogTrack; //================================================================================================== @@ -56,12 +56,12 @@ class RimWellLogPlot : public caf::PdmObject caf::PdmField< std::vector > windowGeometry; - void addTrack(RimWellLogPlotTrack* track); - void insertTrack(RimWellLogPlotTrack* track, size_t index); + void addTrack(RimWellLogTrack* track); + void insertTrack(RimWellLogTrack* track, size_t index); size_t trackCount() { return m_tracks.size();} - void removeTrack(RimWellLogPlotTrack* track); - size_t trackIndex(RimWellLogPlotTrack* track); - void moveTracks(RimWellLogPlotTrack* insertAfterTrack, const std::vector& tracksToMove); + void removeTrack(RimWellLogTrack* track); + size_t trackIndex(RimWellLogTrack* track); + void moveTracks(RimWellLogTrack* insertAfterTrack, const std::vector& tracksToMove); void loadDataAndUpdate(); void updateTracks(); @@ -101,7 +101,7 @@ class RimWellLogPlot : public caf::PdmObject caf::PdmField m_showWindow; caf::PdmField m_userName; caf::PdmField< caf::AppEnum< DepthTypeEnum > > m_depthType; - caf::PdmChildArrayField m_tracks; + caf::PdmChildArrayField m_tracks; caf::PdmField m_minVisibleDepth; caf::PdmField m_maxVisibleDepth; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp index 04c0895339..203059d253 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp @@ -132,7 +132,7 @@ void RimWellLogPlotCurve::updateCurveVisibility() wellLogPlot->calculateAvailableDepthRange(); } - RimWellLogPlotTrack* wellLogPlotTrack; + RimWellLogTrack* wellLogPlotTrack; this->firstAnchestorOrThisOfType(wellLogPlotTrack); if (wellLogPlotTrack) { @@ -157,7 +157,7 @@ void RimWellLogPlotCurve::updatePlotConfiguration() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::setQwtTrack(RiuWellLogTrackPlot* plot) +void RimWellLogPlotCurve::setQwtTrack(RiuWellLogTrack* plot) { m_ownerQwtTrack = plot; if (m_showCurve) @@ -274,7 +274,7 @@ void RimWellLogPlotCurve::zoomAllOwnerTrackAndPlot() wellLogPlot->zoomAllDepth(); } - RimWellLogPlotTrack* plotTrack; + RimWellLogTrack* plotTrack; firstAnchestorOrThisOfType(plotTrack); if (plotTrack) { diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h index 3ecccc9ba6..da8b95d383 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h @@ -28,7 +28,7 @@ #include class RigWellLogCurveData; -class RiuWellLogTrackPlot; +class RiuWellLogTrack; class RiuWellLogPlotCurve; class QwtPlotCurve; class QString; @@ -49,7 +49,7 @@ class RimWellLogPlotCurve : public caf::PdmObject bool depthRange(double* minimumDepth, double* maximumDepth) const; bool valueRange(double* minimumValue, double* maximumValue) const; - void setQwtTrack(RiuWellLogTrackPlot* plot); + void setQwtTrack(RiuWellLogTrack* plot); void detachQwtCurve(); bool isCurveVisible() const; @@ -81,7 +81,7 @@ class RimWellLogPlotCurve : public caf::PdmObject virtual void initAfterRead(); - QPointer m_ownerQwtTrack; + QPointer m_ownerQwtTrack; RiuWellLogPlotCurve* m_qwtPlotCurve; cvf::ref m_curveData; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp index d7b21d941f..6cd3ed2441 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp @@ -35,12 +35,12 @@ #define RI_LOGPLOTTRACK_MAXX_DEFAULT 100.0 -CAF_PDM_SOURCE_INIT(RimWellLogPlotTrack, "WellLogPlotTrack"); +CAF_PDM_SOURCE_INIT(RimWellLogTrack, "WellLogPlotTrack"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotTrack::RimWellLogPlotTrack() +RimWellLogTrack::RimWellLogTrack() { CAF_PDM_InitObject("Track", ":/WellLogTrack16x16.png", "", ""); @@ -60,7 +60,7 @@ RimWellLogPlotTrack::RimWellLogPlotTrack() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotTrack::~RimWellLogPlotTrack() +RimWellLogTrack::~RimWellLogTrack() { delete m_wellLogTrackPlotWidget; } @@ -68,7 +68,7 @@ RimWellLogPlotTrack::~RimWellLogPlotTrack() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::setDescription(const QString& description) +void RimWellLogTrack::setDescription(const QString& description) { m_userName = description; } @@ -76,7 +76,7 @@ void RimWellLogPlotTrack::setDescription(const QString& description) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { if (changedField == &m_show) { @@ -104,7 +104,7 @@ void RimWellLogPlotTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedFie //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimWellLogPlotTrack::objectToggleField() +caf::PdmFieldHandle* RimWellLogTrack::objectToggleField() { return &m_show; } @@ -112,7 +112,7 @@ caf::PdmFieldHandle* RimWellLogPlotTrack::objectToggleField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimWellLogPlotTrack::userDescriptionField() +caf::PdmFieldHandle* RimWellLogTrack::userDescriptionField() { return &m_userName; } @@ -120,7 +120,7 @@ caf::PdmFieldHandle* RimWellLogPlotTrack::userDescriptionField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::addCurve(RimWellLogPlotCurve* curve) +void RimWellLogTrack::addCurve(RimWellLogPlotCurve* curve) { curves.push_back(curve); @@ -133,7 +133,7 @@ void RimWellLogPlotTrack::addCurve(RimWellLogPlotCurve* curve) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::insertCurve(RimWellLogPlotCurve* curve, size_t index) +void RimWellLogTrack::insertCurve(RimWellLogPlotCurve* curve, size_t index) { curves.insert(index, curve); // Todo: Mark curve data to use either TVD or MD @@ -147,7 +147,7 @@ void RimWellLogPlotTrack::insertCurve(RimWellLogPlotCurve* curve, size_t index) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::removeCurve(RimWellLogPlotCurve* curve) +void RimWellLogTrack::removeCurve(RimWellLogPlotCurve* curve) { size_t index = curves.index(curve); if ( index < curves.size()) @@ -161,7 +161,7 @@ void RimWellLogPlotTrack::removeCurve(RimWellLogPlotCurve* curve) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogTrackPlot* RimWellLogPlotTrack::viewer() +RiuWellLogTrack* RimWellLogTrack::viewer() { return m_wellLogTrackPlotWidget; } @@ -169,7 +169,7 @@ RiuWellLogTrackPlot* RimWellLogPlotTrack::viewer() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::availableDepthRange(double* minimumDepth, double* maximumDepth) +void RimWellLogTrack::availableDepthRange(double* minimumDepth, double* maximumDepth) { double minDepth = HUGE_VAL; double maxDepth = -HUGE_VAL; @@ -202,7 +202,7 @@ void RimWellLogPlotTrack::availableDepthRange(double* minimumDepth, double* maxi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::loadDataAndUpdate() +void RimWellLogTrack::loadDataAndUpdate() { CVF_ASSERT(m_wellLogTrackPlotWidget); @@ -222,11 +222,11 @@ void RimWellLogPlotTrack::loadDataAndUpdate() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::recreateViewer() +void RimWellLogTrack::recreateViewer() { if (m_wellLogTrackPlotWidget == NULL) { - m_wellLogTrackPlotWidget = new RiuWellLogTrackPlot(this); + m_wellLogTrackPlotWidget = new RiuWellLogTrack(this); for (size_t cIdx = 0; cIdx < curves.size(); ++cIdx) { @@ -238,7 +238,7 @@ void RimWellLogPlotTrack::recreateViewer() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::detachAllCurves() +void RimWellLogTrack::detachAllCurves() { for (size_t cIdx = 0; cIdx < curves.size(); ++cIdx) { @@ -249,7 +249,7 @@ void RimWellLogPlotTrack::detachAllCurves() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() +void RimWellLogTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() { if (m_wellLogTrackPlotWidget) { @@ -269,7 +269,7 @@ void RimWellLogPlotTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::alignDepthZoomToPlotAndZoomAllX() +void RimWellLogTrack::alignDepthZoomToPlotAndZoomAllX() { if (m_wellLogTrackPlotWidget) { @@ -292,7 +292,7 @@ void RimWellLogPlotTrack::alignDepthZoomToPlotAndZoomAllX() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::zoomAllXAxis() +void RimWellLogTrack::zoomAllXAxis() { double minValue = HUGE_VAL; double maxValue = -HUGE_VAL; @@ -333,7 +333,7 @@ void RimWellLogPlotTrack::zoomAllXAxis() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotCurve* RimWellLogPlotTrack::curveDefinitionFromCurve(const QwtPlotCurve* curve) const +RimWellLogPlotCurve* RimWellLogTrack::curveDefinitionFromCurve(const QwtPlotCurve* curve) const { for (size_t idx = 0; idx < curves.size(); idx++) { @@ -349,7 +349,7 @@ RimWellLogPlotCurve* RimWellLogPlotTrack::curveDefinitionFromCurve(const QwtPlot //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +void RimWellLogTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&m_userName); @@ -361,7 +361,7 @@ void RimWellLogPlotTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RimWellLogPlotTrack::curveIndex(RimWellLogPlotCurve* curve) +size_t RimWellLogTrack::curveIndex(RimWellLogPlotCurve* curve) { return curves.index(curve); } @@ -369,7 +369,7 @@ size_t RimWellLogPlotTrack::curveIndex(RimWellLogPlotCurve* curve) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimWellLogPlotTrack::isVisible() +bool RimWellLogTrack::isVisible() { return m_show; } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h index d106e0b3c4..66f4119e44 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h @@ -28,7 +28,7 @@ #include class RimWellLogPlotCurve; -class RiuWellLogTrackPlot; +class RiuWellLogTrack; class QwtPlotCurve; @@ -36,12 +36,12 @@ class QwtPlotCurve; /// /// //================================================================================================== -class RimWellLogPlotTrack : public caf::PdmObject +class RimWellLogTrack : public caf::PdmObject { CAF_PDM_HEADER_INIT; public: - RimWellLogPlotTrack(); - virtual ~RimWellLogPlotTrack(); + RimWellLogTrack(); + virtual ~RimWellLogTrack(); void setDescription(const QString& description); bool isVisible(); @@ -61,7 +61,7 @@ class RimWellLogPlotTrack : public caf::PdmObject void alignDepthZoomToPlotAndZoomAllX(); void zoomAllXAxis(); - RiuWellLogTrackPlot* viewer(); + RiuWellLogTrack* viewer(); RimWellLogPlotCurve* curveDefinitionFromCurve(const QwtPlotCurve* curve) const; @@ -81,5 +81,5 @@ class RimWellLogPlotTrack : public caf::PdmObject caf::PdmField m_visibleXRangeMin; caf::PdmField m_visibleXRangeMax; - QPointer m_wellLogTrackPlotWidget; + QPointer m_wellLogTrackPlotWidget; }; diff --git a/ApplicationCode/UserInterface/RiuDragDrop.cpp b/ApplicationCode/UserInterface/RiuDragDrop.cpp index f5aea1513b..070cce6287 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.cpp +++ b/ApplicationCode/UserInterface/RiuDragDrop.cpp @@ -150,7 +150,7 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const if (dynamic_cast(uiItem) || dynamic_cast(uiItem) || dynamic_cast(uiItem) || - dynamic_cast(uiItem)) + dynamic_cast(uiItem)) { // TODO: Remember to handle reservoir holding the main grid itemflags |= Qt::ItemIsDragEnabled; @@ -167,18 +167,18 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const { if (dynamic_cast(uiItem)) { - if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) + if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { itemflags |= Qt::ItemIsDropEnabled; } } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) { if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { itemflags |= Qt::ItemIsDropEnabled; } - else if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) + else if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { itemflags |= Qt::ItemIsDropEnabled; } @@ -193,7 +193,7 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const } else if (m_proposedDropAction == Qt::CopyAction) { - if (dynamic_cast(uiItem)) + if (dynamic_cast(uiItem)) { if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { @@ -248,7 +248,7 @@ bool RiuDragDrop::dropMimeData(const QMimeData *data, Qt::DropAction action, int return handleWellLogPlotCurveDrop(action, draggedObjects, wellLogPlotCurve); } - RimWellLogPlotTrack* wellLogPlotTrack; + RimWellLogTrack* wellLogPlotTrack; dropTarget->firstAnchestorOrThisOfType(wellLogPlotTrack); if (wellLogPlotTrack) { @@ -333,7 +333,7 @@ bool RiuDragDrop::handleGridCaseGroupDrop(Qt::DropAction action, caf::PdmObjectG //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiuDragDrop::handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObjectGroup& draggedObjects, RimWellLogPlotTrack* trackTarget) +bool RiuDragDrop::handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObjectGroup& draggedObjects, RimWellLogTrack* trackTarget) { std::vector wellLogFileChannels = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); if (wellLogFileChannels.size() > 0) @@ -355,7 +355,7 @@ bool RiuDragDrop::handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObje } } - std::vector wellLogPlotTracks = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); + std::vector wellLogPlotTracks = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); if (wellLogPlotTracks.size() > 0) { if (action == Qt::MoveAction) @@ -380,7 +380,7 @@ bool RiuDragDrop::handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObje { if (action == Qt::MoveAction) { - RimWellLogPlotTrack* wellLogPlotTrack; + RimWellLogTrack* wellLogPlotTrack; curveDropTarget->firstAnchestorOrThisOfType(wellLogPlotTrack); RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(wellLogPlotTrack, wellLogPlotCurves, curveDropTarget); @@ -396,7 +396,7 @@ bool RiuDragDrop::handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObje //-------------------------------------------------------------------------------------------------- bool RiuDragDrop::handleWellLogPlotDrop(Qt::DropAction action, caf::PdmObjectGroup& draggedObjects, RimWellLogPlot* wellLogPlotTarget) { - std::vector wellLogPlotTracks = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); + std::vector wellLogPlotTracks = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); if (wellLogPlotTracks.size() > 0) { if (action == Qt::MoveAction) diff --git a/ApplicationCode/UserInterface/RiuDragDrop.h b/ApplicationCode/UserInterface/RiuDragDrop.h index 203251dc72..c9d6764e5c 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.h +++ b/ApplicationCode/UserInterface/RiuDragDrop.h @@ -32,7 +32,7 @@ namespace caf class RimIdenticalGridCaseGroup; class RimWellLogPlot; -class RimWellLogPlotTrack; +class RimWellLogTrack; class RimWellLogPlotCurve; //-------------------------------------------------------------------------------------------------- @@ -57,7 +57,7 @@ class RiuDragDrop : public caf::PdmUiDragDropInterface private: void moveCasesToGridGroup(caf::PdmObjectGroup& objectGroup, RimIdenticalGridCaseGroup* gridCaseGroup); bool handleGridCaseGroupDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimIdenticalGridCaseGroup* gridCaseGroup); - bool handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogPlotTrack* wellLogPlotTrack); + bool handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogTrack* wellLogPlotTrack); bool handleWellLogPlotDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogPlot* wellLogPlot); bool handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogPlotCurve* wellLogPlotCurve); diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index 8fff877713..8bf2e048ef 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -73,7 +73,7 @@ RiuWellLogPlot::~RiuWellLogPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlot::addTrackPlot(RiuWellLogTrackPlot* trackPlot) +void RiuWellLogPlot::addTrackPlot(RiuWellLogTrack* trackPlot) { // Insert the plot to the left of the scroll bar insertTrackPlot(trackPlot, m_trackPlots.size()); @@ -82,7 +82,7 @@ void RiuWellLogPlot::addTrackPlot(RiuWellLogTrackPlot* trackPlot) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlot::insertTrackPlot(RiuWellLogTrackPlot* trackPlot, size_t index) +void RiuWellLogPlot::insertTrackPlot(RiuWellLogTrack* trackPlot, size_t index) { trackPlot->setParent(this); @@ -113,7 +113,7 @@ void RiuWellLogPlot::insertTrackPlot(RiuWellLogTrackPlot* trackPlot, size_t inde //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlot::removeTrackPlot(RiuWellLogTrackPlot* trackPlot) +void RiuWellLogPlot::removeTrackPlot(RiuWellLogTrack* trackPlot) { if (!trackPlot) return; diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.h b/ApplicationCode/UserInterface/RiuWellLogPlot.h index 749fb1b1c5..b88398c527 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.h +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.h @@ -24,7 +24,7 @@ #include "cafPdmPointer.h" class RimWellLogPlot; -class RiuWellLogTrackPlot; +class RiuWellLogTrack; class QHBoxLayout; class QScrollBar; @@ -46,9 +46,9 @@ class RiuWellLogPlot : public QWidget RimWellLogPlot* ownerPlotDefinition(); - void addTrackPlot(RiuWellLogTrackPlot* trackPlot); - void insertTrackPlot(RiuWellLogTrackPlot* trackPlot, size_t index); - void removeTrackPlot(RiuWellLogTrackPlot* trackPlot); + void addTrackPlot(RiuWellLogTrack* trackPlot); + void insertTrackPlot(RiuWellLogTrack* trackPlot, size_t index); + void removeTrackPlot(RiuWellLogTrack* trackPlot); void setDepthZoomAndReplot(double minDepth, double maxDepth); @@ -73,7 +73,7 @@ private slots: QHBoxLayout* m_layout; QScrollBar* m_scrollBar; QList m_legends; - QList m_trackPlots; + QList m_trackPlots; caf::PdmPointer m_plotDefinition; QTimer* m_scheduleUpdateChildrenLayoutTimer; }; diff --git a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp index 170e74ce57..99ac238534 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp @@ -48,7 +48,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogTrackPlot::RiuWellLogTrackPlot(RimWellLogPlotTrack* plotTrackDefinition, QWidget* parent) +RiuWellLogTrack::RiuWellLogTrack(RimWellLogTrack* plotTrackDefinition, QWidget* parent) : QwtPlot(parent) { Q_ASSERT(plotTrackDefinition); @@ -64,7 +64,7 @@ RiuWellLogTrackPlot::RiuWellLogTrackPlot(RimWellLogPlotTrack* plotTrackDefinitio //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogTrackPlot::~RiuWellLogTrackPlot() +RiuWellLogTrack::~RiuWellLogTrack() { m_grid->detach(); delete m_grid; @@ -73,7 +73,7 @@ RiuWellLogTrackPlot::~RiuWellLogTrackPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::setDefaults() +void RiuWellLogTrack::setDefaults() { QPalette newPalette(palette()); newPalette.setColor(QPalette::Background, Qt::white); @@ -130,7 +130,7 @@ void RiuWellLogTrackPlot::setDefaults() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::setDepthZoom(double minDepth, double maxDepth) +void RiuWellLogTrack::setDepthZoom(double minDepth, double maxDepth) { // Note: Y-axis is inverted setAxisScale(QwtPlot::yLeft, maxDepth, minDepth); @@ -139,7 +139,7 @@ void RiuWellLogTrackPlot::setDepthZoom(double minDepth, double maxDepth) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::setXRange(double min, double max) +void RiuWellLogTrack::setXRange(double min, double max) { setAxisScale(QwtPlot::xTop, min, max); setAxisScale(QwtPlot::xBottom, min, max); @@ -148,7 +148,7 @@ void RiuWellLogTrackPlot::setXRange(double min, double max) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::setDepthTitle(const QString& title) +void RiuWellLogTrack::setDepthTitle(const QString& title) { QwtText axisTitleY = axisTitle(QwtPlot::yLeft); axisTitleY.setText(title); @@ -158,7 +158,7 @@ void RiuWellLogTrackPlot::setDepthTitle(const QString& title) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiuWellLogTrackPlot::eventFilter(QObject* watched, QEvent* event) +bool RiuWellLogTrack::eventFilter(QObject* watched, QEvent* event) { if (watched == canvas()) { @@ -218,7 +218,7 @@ bool RiuWellLogTrackPlot::eventFilter(QObject* watched, QEvent* event) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::focusInEvent(QFocusEvent* event) +void RiuWellLogTrack::focusInEvent(QFocusEvent* event) { if (m_plotTrackDefinition) { @@ -230,7 +230,7 @@ void RiuWellLogTrackPlot::focusInEvent(QFocusEvent* event) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogTrackPlot::selectClosestCurve(const QPoint& pos) +void RiuWellLogTrack::selectClosestCurve(const QPoint& pos) { QwtPlotCurve* closestCurve = NULL; double distMin = DBL_MAX; @@ -264,7 +264,7 @@ void RiuWellLogTrackPlot::selectClosestCurve(const QPoint& pos) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QSize RiuWellLogTrackPlot::sizeHint() const +QSize RiuWellLogTrack::sizeHint() const { return QSize(0, 0); } @@ -272,7 +272,7 @@ QSize RiuWellLogTrackPlot::sizeHint() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QSize RiuWellLogTrackPlot::minimumSizeHint() const +QSize RiuWellLogTrack::minimumSizeHint() const { return QSize(0, 0); } @@ -280,7 +280,7 @@ QSize RiuWellLogTrackPlot::minimumSizeHint() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiuWellLogTrackPlot::isRimTrackVisible() +bool RiuWellLogTrack::isRimTrackVisible() { if (m_plotTrackDefinition) { diff --git a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.h b/ApplicationCode/UserInterface/RiuWellLogTrackPlot.h index a32e35afa6..9378144688 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.h +++ b/ApplicationCode/UserInterface/RiuWellLogTrackPlot.h @@ -22,7 +22,7 @@ #include "qwt_plot.h" #include "cafPdmPointer.h" -class RimWellLogPlotTrack; +class RimWellLogTrack; class QwtPlotGrid; class QwtLegend; @@ -33,13 +33,13 @@ class QEvent; // // //================================================================================================== -class RiuWellLogTrackPlot : public QwtPlot +class RiuWellLogTrack : public QwtPlot { Q_OBJECT public: - RiuWellLogTrackPlot(RimWellLogPlotTrack* plotTrackDefinition, QWidget* parent = NULL); - virtual ~RiuWellLogTrackPlot(); + RiuWellLogTrack(RimWellLogTrack* plotTrackDefinition, QWidget* parent = NULL); + virtual ~RiuWellLogTrack(); void setDepthZoom(double minDepth, double maxDepth); void setDepthTitle(const QString& title); @@ -59,7 +59,7 @@ class RiuWellLogTrackPlot : public QwtPlot void selectClosestCurve(const QPoint& pos); private: - caf::PdmPointer m_plotTrackDefinition; + caf::PdmPointer m_plotTrackDefinition; QwtPlotGrid* m_grid; }; From 10582750ab170fc87707e38d86ee7a0abe933fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 16:14:42 +0100 Subject: [PATCH 005/290] Renamed files PlotTrack/TrackPlot -> Track --- ApplicationCode/CMakeLists.txt | 6 +++--- ApplicationCode/Commands/RicDeleteItemExec.cpp | 2 +- ApplicationCode/Commands/RicDeleteItemFeature.cpp | 2 +- .../Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp | 4 ++-- .../WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp | 2 +- .../WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp | 2 +- .../WellLogCommands/RicNewWellLogFileCurveFeature.cpp | 2 +- .../Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp | 2 +- .../WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp | 2 +- .../WellLogCommands/RicNewWellLogPlotTrackFeature.cpp | 2 +- .../WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp | 2 +- ApplicationCode/ProjectDataModel/CMakeLists_files.cmake | 4 ++-- ApplicationCode/ProjectDataModel/RimProject.cpp | 2 +- .../ProjectDataModel/RimWellLogExtractionCurve.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp | 4 ++-- .../{RimWellLogPlotTrack.cpp => RimWellLogTrack.cpp} | 4 ++-- .../{RimWellLogPlotTrack.h => RimWellLogTrack.h} | 0 ApplicationCode/UserInterface/RiuDragDrop.cpp | 4 ++-- ApplicationCode/UserInterface/RiuWellLogPlot.cpp | 4 ++-- .../{RiuWellLogTrackPlot.cpp => RiuWellLogTrack.cpp} | 4 ++-- .../{RiuWellLogTrackPlot.h => RiuWellLogTrack.h} | 0 23 files changed, 33 insertions(+), 33 deletions(-) rename ApplicationCode/ProjectDataModel/{RimWellLogPlotTrack.cpp => RimWellLogTrack.cpp} (99%) rename ApplicationCode/ProjectDataModel/{RimWellLogPlotTrack.h => RimWellLogTrack.h} (100%) rename ApplicationCode/UserInterface/{RiuWellLogTrackPlot.cpp => RiuWellLogTrack.cpp} (99%) rename ApplicationCode/UserInterface/{RiuWellLogTrackPlot.h => RiuWellLogTrack.h} (100%) diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 46be7f3dce..e1a80d6e3f 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -86,8 +86,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuWellLogPlot.h UserInterface/RiuWellLogPlotCurve.cpp UserInterface/RiuWellLogPlotCurve.h - UserInterface/RiuWellLogTrackPlot.cpp - UserInterface/RiuWellLogTrackPlot.h + UserInterface/RiuWellLogTrack.cpp + UserInterface/RiuWellLogTrack.h UserInterface/RiuProjectPropertyView.h UserInterface/RiuProjectPropertyView.cpp ) @@ -182,7 +182,7 @@ set ( QT_MOC_HEADERS UserInterface/RiuViewerCommands.h UserInterface/RiuTreeViewEventFilter.h UserInterface/RiuWellLogPlot.h - UserInterface/RiuWellLogTrackPlot.h + UserInterface/RiuWellLogTrack.h ) qt4_wrap_cpp( MOC_FILES_CPP ${QT_MOC_HEADERS} ) diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 85ae9a4c80..6b335c716c 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -29,7 +29,7 @@ #include "RimViewLinkerCollection.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellPathCollection.h" #include "cafNotificationCenter.h" diff --git a/ApplicationCode/Commands/RicDeleteItemFeature.cpp b/ApplicationCode/Commands/RicDeleteItemFeature.cpp index 6e9a9fe65b..387fc7be26 100644 --- a/ApplicationCode/Commands/RicDeleteItemFeature.cpp +++ b/ApplicationCode/Commands/RicDeleteItemFeature.cpp @@ -22,7 +22,7 @@ #include "RicDeleteItemExecData.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "cafCmdExecCommandManager.h" #include "cafCmdSelectionHelper.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index 9d70eec660..2ae4694c36 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -25,7 +25,7 @@ #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogFileCurve.h" #include "RimProject.h" #include "RimMainPlotCollection.h" @@ -37,7 +37,7 @@ #include "RiaApplication.h" #include "RiuMainWindow.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "cafSelectionManager.h" #include "cafPdmUiTreeView.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp index 12bca0e1e7..b5a89d10ce 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp @@ -19,7 +19,7 @@ #include "RicDeleteWellLogPlotTrackFeature.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlot.h" #include "cafSelectionManager.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index e4cbdfb00a..4241d7f526 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -22,7 +22,7 @@ #include "RicWellLogPlotCurveFeatureImpl.h" #include "RicNewWellLogPlotFeatureImpl.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogExtractionCurve.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp index c75ba4ab8f..96855dfde5 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp @@ -23,7 +23,7 @@ #include "RicNewWellLogPlotFeatureImpl.h" #include "RimWellLogFileCurve.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" #include "RimWellPath.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp index e456116c1e..4888ce4d2a 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp @@ -25,7 +25,7 @@ #include "RimProject.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlotCurve.h" #include "RiaApplication.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp index 7e7671ddf0..f993a6b376 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp @@ -23,7 +23,7 @@ #include "RimMainPlotCollection.h" #include "RimWellLogPlotCollection.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RiaApplication.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp index 446798da8b..56fc5b51a7 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotTrackFeature.cpp @@ -20,7 +20,7 @@ #include "RicNewWellLogPlotTrackFeature.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp index 24dad36f64..db45f26819 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp @@ -20,7 +20,7 @@ #include "RicWellLogPlotTrackFeatureImpl.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlotCurve.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index 1e61fa84d9..b7cf593110 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -63,7 +63,7 @@ ${CEE_CURRENT_LIST_DIR}RimViewController.h ${CEE_CURRENT_LIST_DIR}RimMainPlotCollection.h ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCollection.h ${CEE_CURRENT_LIST_DIR}RimWellLogPlot.h -${CEE_CURRENT_LIST_DIR}RimWellLogPlotTrack.h +${CEE_CURRENT_LIST_DIR}RimWellLogTrack.h ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCurve.h ${CEE_CURRENT_LIST_DIR}RimViewLinker.h ${CEE_CURRENT_LIST_DIR}RimViewLinkerCollection.h @@ -132,7 +132,7 @@ ${CEE_CURRENT_LIST_DIR}RimViewController.cpp ${CEE_CURRENT_LIST_DIR}RimMainPlotCollection.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCollection.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogPlot.cpp -${CEE_CURRENT_LIST_DIR}RimWellLogPlotTrack.cpp +${CEE_CURRENT_LIST_DIR}RimWellLogTrack.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCurve.cpp ${CEE_CURRENT_LIST_DIR}RimViewLinker.cpp ${CEE_CURRENT_LIST_DIR}RimViewLinkerCollection.cpp diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 045bb8adff..802a8e765f 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -625,7 +625,7 @@ void RimProject::computeUtmAreaOfInterest() #include "RimEclipseCellColors.h" #include "RimEclipseFaultColors.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlotCurve.h" #include "RimWellLogFileChannel.h" #include diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 647da20dec..c742c926b0 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -38,7 +38,7 @@ #include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" #include "RimWellLogPlotCurve.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimEclipseView.h" @@ -47,7 +47,7 @@ #include "RimGeoMechCellColors.h" #include "RiuWellLogPlotCurve.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "cafPdmUiTreeOrdering.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index b648aa9ba5..b42536c63a 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -25,10 +25,10 @@ #include "RimWellPath.h" #include "RimWellLogFileChannel.h" #include "RimWellLogFile.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlot.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "RiuWellLogPlotCurve.h" #include "RiaApplication.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index be6dbb6727..b2627f34b4 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -19,10 +19,10 @@ #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RiuWellLogPlot.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "RiuMainWindow.h" #include "cafPdmUiTreeView.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp index 203059d253..1e5998da57 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp @@ -21,10 +21,10 @@ #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RiuWellLogPlotCurve.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "cvfAssert.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp similarity index 99% rename from ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp rename to ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 6cd3ed2441..b55600b5b4 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -17,12 +17,12 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotCurve.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "RiuWellLogPlot.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h similarity index 100% rename from ApplicationCode/ProjectDataModel/RimWellLogPlotTrack.h rename to ApplicationCode/ProjectDataModel/RimWellLogTrack.h diff --git a/ApplicationCode/UserInterface/RiuDragDrop.cpp b/ApplicationCode/UserInterface/RiuDragDrop.cpp index 070cce6287..e4598bc0fb 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.cpp +++ b/ApplicationCode/UserInterface/RiuDragDrop.cpp @@ -30,11 +30,11 @@ #include "RimIdenticalGridCaseGroup.h" #include "RimMimeData.h" #include "RimWellLogFileChannel.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlotCurve.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RiuMainWindow.h" #include "cafPdmUiTreeView.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index 8bf2e048ef..d3e88d8720 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -19,11 +19,11 @@ #include "RiuWellLogPlot.h" -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "RiuMainWindow.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "cafPdmUiTreeView.h" #include "cvfAssert.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp similarity index 99% rename from ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp rename to ApplicationCode/UserInterface/RiuWellLogTrack.cpp index 99ac238534..32b276ec27 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp @@ -17,10 +17,10 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RiuWellLogTrackPlot.h" +#include "RiuWellLogTrack.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotTrack.h" +#include "RimWellLogTrack.h" #include "RimWellLogPlotCurve.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogTrackPlot.h b/ApplicationCode/UserInterface/RiuWellLogTrack.h similarity index 100% rename from ApplicationCode/UserInterface/RiuWellLogTrackPlot.h rename to ApplicationCode/UserInterface/RiuWellLogTrack.h From 7b7ecf2f26fc3f7108080047362e4b5c634d51dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 16:19:38 +0100 Subject: [PATCH 006/290] Renamed PlotCurve -> Curve --- .../Commands/RicExportToLasFileFeature.cpp | 6 +-- .../Commands/RicExportToLasFileFeature.h | 4 +- .../RicWellLogPlotTrackFeatureImpl.cpp | 6 +-- .../RicWellLogPlotTrackFeatureImpl.h | 6 +-- .../RimEclipseResultDefinition.cpp | 4 +- .../RimGeoMechResultDefinition.cpp | 2 +- .../ProjectDataModel/RimProject.cpp | 2 +- .../RimWellLogExtractionCurve.cpp | 6 +-- .../RimWellLogExtractionCurve.h | 2 +- .../ProjectDataModel/RimWellLogFileCurve.cpp | 4 +- .../ProjectDataModel/RimWellLogFileCurve.h | 2 +- .../ProjectDataModel/RimWellLogPlotCurve.cpp | 44 +++++++++---------- .../ProjectDataModel/RimWellLogPlotCurve.h | 10 ++--- .../ProjectDataModel/RimWellLogTrack.cpp | 10 ++--- .../ProjectDataModel/RimWellLogTrack.h | 14 +++--- .../ReservoirDataModel/RigWellLogFile.cpp | 2 +- .../ReservoirDataModel/RigWellLogFile.h | 4 +- ApplicationCode/UserInterface/RiuDragDrop.cpp | 18 ++++---- ApplicationCode/UserInterface/RiuDragDrop.h | 4 +- .../UserInterface/RiuWellLogPlotCurve.cpp | 8 ++-- .../UserInterface/RiuWellLogPlotCurve.h | 6 +-- .../UserInterface/RiuWellLogTrack.cpp | 2 +- 22 files changed, 83 insertions(+), 83 deletions(-) diff --git a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp index 17c45bf7c0..ed4c9d0135 100644 --- a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp +++ b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp @@ -46,7 +46,7 @@ bool RicExportToLasFileFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicExportToLasFileFeature::onActionTriggered(bool isChecked) { - RimWellLogPlotCurve* curve = selectedWellLogPlotCurve(); + RimWellLogCurve* curve = selectedWellLogPlotCurve(); if (curve) { QString defaultDir = RiaApplication::instance()->defaultFileDialogDirectory("WELL_LOGS_DIR"); @@ -77,9 +77,9 @@ void RicExportToLasFileFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotCurve* RicExportToLasFileFeature::selectedWellLogPlotCurve() const +RimWellLogCurve* RicExportToLasFileFeature::selectedWellLogPlotCurve() const { - std::vector selection; + std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); if (selection.size() > 0) diff --git a/ApplicationCode/Commands/RicExportToLasFileFeature.h b/ApplicationCode/Commands/RicExportToLasFileFeature.h index 527fb64169..78ab3603b9 100644 --- a/ApplicationCode/Commands/RicExportToLasFileFeature.h +++ b/ApplicationCode/Commands/RicExportToLasFileFeature.h @@ -23,7 +23,7 @@ #include -class RimWellLogPlotCurve; +class RimWellLogCurve; //================================================================================================== /// @@ -39,7 +39,7 @@ class RicExportToLasFileFeature : public caf::CmdFeature virtual void setupActionLook( QAction* actionToSetup ); private: - RimWellLogPlotCurve* selectedWellLogPlotCurve() const; + RimWellLogCurve* selectedWellLogPlotCurve() const; }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp index db45f26819..e23bc60938 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp @@ -31,8 +31,8 @@ /// //-------------------------------------------------------------------------------------------------- void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogTrack* destTrack, - const std::vector& curves, - RimWellLogPlotCurve* curveToInsertAfter) + const std::vector& curves, + RimWellLogCurve* curveToInsertAfter) { CVF_ASSERT(destTrack ); @@ -41,7 +41,7 @@ void RicWellLogPlotTrackFeatureImpl::moveCurvesToWellLogPlotTrack(RimWellLogTrac for (size_t cIdx = 0; cIdx < curves.size(); cIdx++) { - RimWellLogPlotCurve* curve = curves[cIdx]; + RimWellLogCurve* curve = curves[cIdx]; RimWellLogTrack* wellLogPlotTrack; curve->firstAnchestorOrThisOfType(wellLogPlotTrack); diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h index e9eee75395..6eb2135d31 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.h @@ -23,7 +23,7 @@ class RimWellLogPlot; class RimWellLogTrack; -class RimWellLogPlotCurve; +class RimWellLogCurve; //================================================================================================== /// @@ -33,8 +33,8 @@ class RicWellLogPlotTrackFeatureImpl public: static void moveCurvesToWellLogPlotTrack(RimWellLogTrack* dstTrack, - const std::vector& curves, - RimWellLogPlotCurve* insertAfterCurve); + const std::vector& curves, + RimWellLogCurve* insertAfterCurve); static void moveTracksToWellLogPlot(RimWellLogPlot* wellLogPlot, const std::vector& tracks, RimWellLogTrack* trackToInsertAfter); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp index 8ed6e0aa43..f6142e0aa3 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -128,7 +128,7 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha RimEclipsePropertyFilter* propFilter = dynamic_cast(this->parentField()->ownerObject()); RimView* view = NULL; this->firstAnchestorOrThisOfType(view); - RimWellLogPlotCurve* curve = NULL; + RimWellLogCurve* curve = NULL; this->firstAnchestorOrThisOfType(curve); if (&m_resultVariableUiField == changedField) @@ -194,7 +194,7 @@ QList RimEclipseResultDefinition::calculateValueOptions( { QList optionItems = calculateValueOptionsForSpecifiedDerivedListPosition(false, fieldNeedingOptions, useOptionsOnly); - RimWellLogPlotCurve* curve = NULL; + RimWellLogCurve* curve = NULL; this->firstAnchestorOrThisOfType(curve); RimEclipsePropertyFilter* propFilter = dynamic_cast(this->parentField()->ownerObject()); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp index 1ea9ba925d..4f65e507a0 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp @@ -150,7 +150,7 @@ void RimGeoMechResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha RimGeoMechPropertyFilter* propFilter = dynamic_cast(this->parentField()->ownerObject()); RimView* view = NULL; this->firstAnchestorOrThisOfType(view); - RimWellLogPlotCurve* curve = NULL; + RimWellLogCurve* curve = NULL; this->firstAnchestorOrThisOfType(curve); diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 802a8e765f..047e93f5f6 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -820,7 +820,7 @@ void RimProject::actionsBasedOnSelection(QMenu& contextMenu) commandIds << "RicNewWellLogFileCurveFeature"; commandIds << "RicDeleteWellLogPlotTrackFeature"; } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) { commandIds << "RicExportToLasFileFeature"; commandIds << "RicDeleteItemFeature"; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index c742c926b0..77ebfa5041 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -145,7 +145,7 @@ void RimWellLogExtractionCurve::setPropertiesFromView(RimView* view) //-------------------------------------------------------------------------------------------------- void RimWellLogExtractionCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { - RimWellLogPlotCurve::fieldChangedByUi(changedField, oldValue, newValue); + RimWellLogCurve::fieldChangedByUi(changedField, oldValue, newValue); if (changedField == &m_case) { @@ -177,7 +177,7 @@ void RimWellLogExtractionCurve::fieldChangedByUi(const caf::PdmFieldHandle* chan //-------------------------------------------------------------------------------------------------- void RimWellLogExtractionCurve::updatePlotData() { - RimWellLogPlotCurve::updatePlotConfiguration(); + RimWellLogCurve::updatePlotConfiguration(); if (isCurveVisible()) { @@ -378,7 +378,7 @@ void RimWellLogExtractionCurve::defineUiOrdering(QString uiConfigName, caf::PdmU //-------------------------------------------------------------------------------------------------- void RimWellLogExtractionCurve::initAfterRead() { - RimWellLogPlotCurve::initAfterRead(); + RimWellLogCurve::initAfterRead(); RimGeoMechCase* geomCase = dynamic_cast(m_case.value()); RimEclipseCase* eclipseCase = dynamic_cast(m_case.value()); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index ae9774523a..0c5bcdad60 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -34,7 +34,7 @@ class RimView; /// /// //================================================================================================== -class RimWellLogExtractionCurve : public RimWellLogPlotCurve +class RimWellLogExtractionCurve : public RimWellLogCurve { CAF_PDM_HEADER_INIT; public: diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index b42536c63a..b925080d82 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -70,7 +70,7 @@ RimWellLogFileCurve::~RimWellLogFileCurve() //-------------------------------------------------------------------------------------------------- void RimWellLogFileCurve::updatePlotData() { - RimWellLogPlotCurve::updatePlotConfiguration(); + RimWellLogCurve::updatePlotConfiguration(); if (isCurveVisible()) { @@ -143,7 +143,7 @@ void RimWellLogFileCurve::setWellLogChannelName(const QString& name) //-------------------------------------------------------------------------------------------------- void RimWellLogFileCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { - RimWellLogPlotCurve::fieldChangedByUi(changedField, oldValue, newValue); + RimWellLogCurve::fieldChangedByUi(changedField, oldValue, newValue); if (changedField == &m_wellPath) { diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h index 9b493a8a40..5c89e5778d 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h @@ -33,7 +33,7 @@ class RimWellLogFileChannel; /// /// //================================================================================================== -class RimWellLogFileCurve : public RimWellLogPlotCurve +class RimWellLogFileCurve : public RimWellLogCurve { CAF_PDM_HEADER_INIT; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp index 1e5998da57..a95175eb8c 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp @@ -29,12 +29,12 @@ #include "cvfAssert.h" // NB! Special macro for pure virtual class -CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimWellLogPlotCurve, "WellLogPlotCurve"); +CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimWellLogCurve, "WellLogPlotCurve"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotCurve::RimWellLogPlotCurve() +RimWellLogCurve::RimWellLogCurve() { CAF_PDM_InitObject("Curve", ":/WellLogCurve16x16.png", "", ""); @@ -49,7 +49,7 @@ RimWellLogPlotCurve::RimWellLogPlotCurve() CAF_PDM_InitField(&m_curveColor, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", ""); - m_qwtPlotCurve = new RiuWellLogPlotCurve; + m_qwtPlotCurve = new RiuWellLogCurve; m_qwtPlotCurve->setXAxis(QwtPlot::xTop); m_qwtPlotCurve->setYAxis(QwtPlot::yLeft); @@ -59,7 +59,7 @@ RimWellLogPlotCurve::RimWellLogPlotCurve() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotCurve::~RimWellLogPlotCurve() +RimWellLogCurve::~RimWellLogCurve() { m_qwtPlotCurve->detach(); delete m_qwtPlotCurve; @@ -73,7 +73,7 @@ RimWellLogPlotCurve::~RimWellLogPlotCurve() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void RimWellLogCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { if (changedField == &m_showCurve) { @@ -106,7 +106,7 @@ void RimWellLogPlotCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedFie //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimWellLogPlotCurve::objectToggleField() +caf::PdmFieldHandle* RimWellLogCurve::objectToggleField() { return &m_showCurve; } @@ -114,7 +114,7 @@ caf::PdmFieldHandle* RimWellLogPlotCurve::objectToggleField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::updateCurveVisibility() +void RimWellLogCurve::updateCurveVisibility() { if (m_showCurve() && m_ownerQwtTrack) { @@ -144,7 +144,7 @@ void RimWellLogPlotCurve::updateCurveVisibility() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::updatePlotConfiguration() +void RimWellLogCurve::updatePlotConfiguration() { this->updateCurveVisibility(); this->updateCurveName(); @@ -157,7 +157,7 @@ void RimWellLogPlotCurve::updatePlotConfiguration() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::setQwtTrack(RiuWellLogTrack* plot) +void RimWellLogCurve::setQwtTrack(RiuWellLogTrack* plot) { m_ownerQwtTrack = plot; if (m_showCurve) @@ -170,7 +170,7 @@ void RimWellLogPlotCurve::setQwtTrack(RiuWellLogTrack* plot) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimWellLogPlotCurve::userDescriptionField() +caf::PdmFieldHandle* RimWellLogCurve::userDescriptionField() { return &m_curveName; } @@ -178,7 +178,7 @@ caf::PdmFieldHandle* RimWellLogPlotCurve::userDescriptionField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimWellLogPlotCurve::depthRange(double* minimumDepth, double* maximumDepth) const +bool RimWellLogCurve::depthRange(double* minimumDepth, double* maximumDepth) const { CVF_ASSERT(minimumDepth && maximumDepth); CVF_ASSERT(m_qwtPlotCurve); @@ -197,7 +197,7 @@ bool RimWellLogPlotCurve::depthRange(double* minimumDepth, double* maximumDepth) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimWellLogPlotCurve::valueRange(double* minimumValue, double* maximumValue) const +bool RimWellLogCurve::valueRange(double* minimumValue, double* maximumValue) const { CVF_ASSERT(minimumValue && maximumValue); CVF_ASSERT(m_qwtPlotCurve); @@ -216,7 +216,7 @@ bool RimWellLogPlotCurve::valueRange(double* minimumValue, double* maximumValue) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::setColor(const cvf::Color3f& color) +void RimWellLogCurve::setColor(const cvf::Color3f& color) { m_curveColor = color; } @@ -224,7 +224,7 @@ void RimWellLogPlotCurve::setColor(const cvf::Color3f& color) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::detachQwtCurve() +void RimWellLogCurve::detachQwtCurve() { m_qwtPlotCurve->detach(); } @@ -232,7 +232,7 @@ void RimWellLogPlotCurve::detachQwtCurve() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QwtPlotCurve* RimWellLogPlotCurve::plotCurve() const +QwtPlotCurve* RimWellLogCurve::plotCurve() const { return m_qwtPlotCurve; } @@ -240,7 +240,7 @@ QwtPlotCurve* RimWellLogPlotCurve::plotCurve() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::updatePlotTitle() +void RimWellLogCurve::updatePlotTitle() { m_qwtPlotCurve->setTitle(m_curveName); } @@ -248,7 +248,7 @@ void RimWellLogPlotCurve::updatePlotTitle() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimWellLogPlotCurve::isCurveVisible() const +bool RimWellLogCurve::isCurveVisible() const { return m_showCurve; } @@ -256,7 +256,7 @@ bool RimWellLogPlotCurve::isCurveVisible() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::initAfterRead() +void RimWellLogCurve::initAfterRead() { updateOptionSensitivity(); } @@ -264,7 +264,7 @@ void RimWellLogPlotCurve::initAfterRead() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::zoomAllOwnerTrackAndPlot() +void RimWellLogCurve::zoomAllOwnerTrackAndPlot() { RimWellLogPlot* wellLogPlot; firstAnchestorOrThisOfType(wellLogPlot); @@ -285,7 +285,7 @@ void RimWellLogPlotCurve::zoomAllOwnerTrackAndPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::updateCurveName() +void RimWellLogCurve::updateCurveName() { if (m_autoName) { @@ -300,7 +300,7 @@ void RimWellLogPlotCurve::updateCurveName() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlotCurve::updateOptionSensitivity() +void RimWellLogCurve::updateOptionSensitivity() { m_curveName.uiCapability()->setUiReadOnly(m_autoName); } @@ -308,7 +308,7 @@ void RimWellLogPlotCurve::updateOptionSensitivity() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const RigWellLogCurveData* RimWellLogPlotCurve::curveData() const +const RigWellLogCurveData* RimWellLogCurve::curveData() const { return m_curveData.p(); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h index da8b95d383..cb4780bc34 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h @@ -29,7 +29,7 @@ class RigWellLogCurveData; class RiuWellLogTrack; -class RiuWellLogPlotCurve; +class RiuWellLogCurve; class QwtPlotCurve; class QString; @@ -37,12 +37,12 @@ class QString; /// /// //================================================================================================== -class RimWellLogPlotCurve : public caf::PdmObject +class RimWellLogCurve : public caf::PdmObject { CAF_PDM_HEADER_INIT; public: - RimWellLogPlotCurve(); - virtual ~RimWellLogPlotCurve(); + RimWellLogCurve(); + virtual ~RimWellLogCurve(); void setColor(const cvf::Color3f& color); @@ -82,7 +82,7 @@ class RimWellLogPlotCurve : public caf::PdmObject QPointer m_ownerQwtTrack; - RiuWellLogPlotCurve* m_qwtPlotCurve; + RiuWellLogCurve* m_qwtPlotCurve; cvf::ref m_curveData; caf::PdmField m_showCurve; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index b55600b5b4..d92c049e2f 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -120,7 +120,7 @@ caf::PdmFieldHandle* RimWellLogTrack::userDescriptionField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::addCurve(RimWellLogPlotCurve* curve) +void RimWellLogTrack::addCurve(RimWellLogCurve* curve) { curves.push_back(curve); @@ -133,7 +133,7 @@ void RimWellLogTrack::addCurve(RimWellLogPlotCurve* curve) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::insertCurve(RimWellLogPlotCurve* curve, size_t index) +void RimWellLogTrack::insertCurve(RimWellLogCurve* curve, size_t index) { curves.insert(index, curve); // Todo: Mark curve data to use either TVD or MD @@ -147,7 +147,7 @@ void RimWellLogTrack::insertCurve(RimWellLogPlotCurve* curve, size_t index) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::removeCurve(RimWellLogPlotCurve* curve) +void RimWellLogTrack::removeCurve(RimWellLogCurve* curve) { size_t index = curves.index(curve); if ( index < curves.size()) @@ -333,7 +333,7 @@ void RimWellLogTrack::zoomAllXAxis() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimWellLogPlotCurve* RimWellLogTrack::curveDefinitionFromCurve(const QwtPlotCurve* curve) const +RimWellLogCurve* RimWellLogTrack::curveDefinitionFromCurve(const QwtPlotCurve* curve) const { for (size_t idx = 0; idx < curves.size(); idx++) { @@ -361,7 +361,7 @@ void RimWellLogTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RimWellLogTrack::curveIndex(RimWellLogPlotCurve* curve) +size_t RimWellLogTrack::curveIndex(RimWellLogCurve* curve) { return curves.index(curve); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index 66f4119e44..ca49f14f51 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -27,7 +27,7 @@ #include -class RimWellLogPlotCurve; +class RimWellLogCurve; class RiuWellLogTrack; class QwtPlotCurve; @@ -45,10 +45,10 @@ class RimWellLogTrack : public caf::PdmObject void setDescription(const QString& description); bool isVisible(); - void addCurve(RimWellLogPlotCurve* curve); - void insertCurve(RimWellLogPlotCurve* curve, size_t index); - void removeCurve(RimWellLogPlotCurve* curve); - size_t curveIndex(RimWellLogPlotCurve* curve); + void addCurve(RimWellLogCurve* curve); + void insertCurve(RimWellLogCurve* curve, size_t index); + void removeCurve(RimWellLogCurve* curve); + size_t curveIndex(RimWellLogCurve* curve); size_t curveCount() { return curves.size(); } void recreateViewer(); @@ -63,7 +63,7 @@ class RimWellLogTrack : public caf::PdmObject RiuWellLogTrack* viewer(); - RimWellLogPlotCurve* curveDefinitionFromCurve(const QwtPlotCurve* curve) const; + RimWellLogCurve* curveDefinitionFromCurve(const QwtPlotCurve* curve) const; protected: @@ -77,7 +77,7 @@ class RimWellLogTrack : public caf::PdmObject private: caf::PdmField m_show; caf::PdmField m_userName; - caf::PdmChildArrayField curves; + caf::PdmChildArrayField curves; caf::PdmField m_visibleXRangeMin; caf::PdmField m_visibleXRangeMax; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index 1e4dc6b751..c4c2b2b906 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -245,7 +245,7 @@ QString RigWellLogFile::wellLogChannelUnit(const QString& wellLogChannelName) co //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RigWellLogFile::exportToLasFile(const RimWellLogPlotCurve* curve, const QString& fileName) +bool RigWellLogFile::exportToLasFile(const RimWellLogCurve* curve, const QString& fileName) { CVF_ASSERT(curve); diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h index 348e1da03f..6db1694344 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h @@ -30,7 +30,7 @@ namespace NRLib class Well; } -class RimWellLogPlotCurve; +class RimWellLogCurve; //================================================================================================== /// @@ -52,7 +52,7 @@ class RigWellLogFile : public cvf::Object QString depthUnit() const; QString wellLogChannelUnit(const QString& wellLogChannelName) const; - static bool exportToLasFile(const RimWellLogPlotCurve* curve, const QString& fileName); + static bool exportToLasFile(const RimWellLogCurve* curve, const QString& fileName); private: void close(); diff --git a/ApplicationCode/UserInterface/RiuDragDrop.cpp b/ApplicationCode/UserInterface/RiuDragDrop.cpp index e4598bc0fb..b90ae79f5c 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.cpp +++ b/ApplicationCode/UserInterface/RiuDragDrop.cpp @@ -148,7 +148,7 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const caf::PdmUiItem* uiItem = uiTreeView->uiItemFromModelIndex(index); if (dynamic_cast(uiItem) || - dynamic_cast(uiItem) || + dynamic_cast(uiItem) || dynamic_cast(uiItem) || dynamic_cast(uiItem)) { @@ -174,7 +174,7 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const } else if (dynamic_cast(uiItem)) { - if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) + if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { itemflags |= Qt::ItemIsDropEnabled; } @@ -183,9 +183,9 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const itemflags |= Qt::ItemIsDropEnabled; } } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) { - if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) + if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { itemflags |= Qt::ItemIsDropEnabled; } @@ -200,7 +200,7 @@ Qt::ItemFlags RiuDragDrop::flags(const QModelIndex &index) const itemflags |= Qt::ItemIsDropEnabled; } } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) { if (RiuTypedPdmObjects::containsTypedObjects(m_dragItems)) { @@ -241,7 +241,7 @@ bool RiuDragDrop::dropMimeData(const QMimeData *data, Qt::DropAction action, int return handleGridCaseGroupDrop(action, draggedObjects, gridCaseGroup); } - RimWellLogPlotCurve* wellLogPlotCurve; + RimWellLogCurve* wellLogPlotCurve; dropTarget->firstAnchestorOrThisOfType(wellLogPlotCurve); if (wellLogPlotCurve) { @@ -345,7 +345,7 @@ bool RiuDragDrop::handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObje } } - std::vector wellLogPlotCurves = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); + std::vector wellLogPlotCurves = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); if (wellLogPlotCurves.size() > 0) { if (action == Qt::MoveAction) @@ -373,9 +373,9 @@ bool RiuDragDrop::handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObje //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiuDragDrop::handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObjectGroup& draggedObjects, RimWellLogPlotCurve* curveDropTarget) +bool RiuDragDrop::handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObjectGroup& draggedObjects, RimWellLogCurve* curveDropTarget) { - std::vector wellLogPlotCurves = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); + std::vector wellLogPlotCurves = RiuTypedPdmObjects::typedObjectsFromGroup(draggedObjects); if (wellLogPlotCurves.size() > 0) { if (action == Qt::MoveAction) diff --git a/ApplicationCode/UserInterface/RiuDragDrop.h b/ApplicationCode/UserInterface/RiuDragDrop.h index c9d6764e5c..d5a75c28dc 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.h +++ b/ApplicationCode/UserInterface/RiuDragDrop.h @@ -33,7 +33,7 @@ namespace caf class RimIdenticalGridCaseGroup; class RimWellLogPlot; class RimWellLogTrack; -class RimWellLogPlotCurve; +class RimWellLogCurve; //-------------------------------------------------------------------------------------------------- /// @@ -59,7 +59,7 @@ class RiuDragDrop : public caf::PdmUiDragDropInterface bool handleGridCaseGroupDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimIdenticalGridCaseGroup* gridCaseGroup); bool handleWellLogPlotTrackDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogTrack* wellLogPlotTrack); bool handleWellLogPlotDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogPlot* wellLogPlot); - bool handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogPlotCurve* wellLogPlotCurve); + bool handleWellLogPlotCurveDrop(Qt::DropAction action, caf::PdmObjectGroup& objectGroup, RimWellLogCurve* wellLogPlotCurve); static void objectGroupFromModelIndexes(caf::PdmObjectGroup* objectGroup, const QModelIndexList &indexes); static std::vector > objectHandlesFromSelection(); diff --git a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp b/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp index 5c2a2e116c..3afeb1c20b 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp @@ -25,21 +25,21 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogPlotCurve::RiuWellLogPlotCurve() +RiuWellLogCurve::RiuWellLogCurve() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogPlotCurve::~RiuWellLogPlotCurve() +RiuWellLogCurve::~RiuWellLogCurve() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlotCurve::drawCurve(QPainter* p, int style, +void RiuWellLogCurve::drawCurve(QPainter* p, int style, const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QRectF& canvasRect, int from, int to) const { @@ -57,7 +57,7 @@ void RiuWellLogPlotCurve::drawCurve(QPainter* p, int style, //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlotCurve::setCurveData(const RigWellLogCurveData* curveData) +void RiuWellLogCurve::setCurveData(const RigWellLogCurveData* curveData) { CVF_ASSERT(curveData); diff --git a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.h b/ApplicationCode/UserInterface/RiuWellLogPlotCurve.h index d7b5b25dd6..e08122864f 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.h +++ b/ApplicationCode/UserInterface/RiuWellLogPlotCurve.h @@ -29,12 +29,12 @@ class RigWellLogCurveData; /// /// //================================================================================================== -class RiuWellLogPlotCurve : public QwtPlotCurve +class RiuWellLogCurve : public QwtPlotCurve { public: - RiuWellLogPlotCurve(); - virtual ~RiuWellLogPlotCurve(); + RiuWellLogCurve(); + virtual ~RiuWellLogCurve(); void setCurveData(const RigWellLogCurveData* curveData); diff --git a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp index 32b276ec27..4863c33dbe 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp @@ -253,7 +253,7 @@ void RiuWellLogTrack::selectClosestCurve(const QPoint& pos) if (closestCurve && distMin < 20) { - RimWellLogPlotCurve* selectedCurve = m_plotTrackDefinition->curveDefinitionFromCurve(closestCurve); + RimWellLogCurve* selectedCurve = m_plotTrackDefinition->curveDefinitionFromCurve(closestCurve); if (selectedCurve) { RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(selectedCurve); From 4388f391753f771709a025a02c8eda0da02325b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 4 Nov 2015 16:22:53 +0100 Subject: [PATCH 007/290] Renamed files PlotCurve->Curve --- ApplicationCode/CMakeLists.txt | 4 ++-- ApplicationCode/Commands/RicExportToLasFileFeature.cpp | 2 +- .../Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp | 2 +- .../WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp | 2 +- ApplicationCode/ProjectDataModel/CMakeLists_files.cmake | 4 ++-- .../ProjectDataModel/RimEclipseResultDefinition.cpp | 2 +- .../ProjectDataModel/RimGeoMechResultDefinition.cpp | 2 +- ApplicationCode/ProjectDataModel/RimProject.cpp | 2 +- .../{RimWellLogPlotCurve.cpp => RimWellLogCurve.cpp} | 4 ++-- .../{RimWellLogPlotCurve.h => RimWellLogCurve.h} | 0 .../ProjectDataModel/RimWellLogExtractionCurve.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h | 2 +- ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp | 2 +- ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h | 2 +- ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp | 2 +- ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp | 2 +- ApplicationCode/UserInterface/RiuDragDrop.cpp | 2 +- .../{RiuWellLogPlotCurve.cpp => RiuWellLogCurve.cpp} | 2 +- .../{RiuWellLogPlotCurve.h => RiuWellLogCurve.h} | 0 ApplicationCode/UserInterface/RiuWellLogTrack.cpp | 2 +- 20 files changed, 22 insertions(+), 22 deletions(-) rename ApplicationCode/ProjectDataModel/{RimWellLogPlotCurve.cpp => RimWellLogCurve.cpp} (99%) rename ApplicationCode/ProjectDataModel/{RimWellLogPlotCurve.h => RimWellLogCurve.h} (100%) rename ApplicationCode/UserInterface/{RiuWellLogPlotCurve.cpp => RiuWellLogCurve.cpp} (98%) rename ApplicationCode/UserInterface/{RiuWellLogPlotCurve.h => RiuWellLogCurve.h} (100%) diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index e1a80d6e3f..0ec9defc82 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -84,8 +84,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuTreeViewEventFilter.h UserInterface/RiuWellLogPlot.cpp UserInterface/RiuWellLogPlot.h - UserInterface/RiuWellLogPlotCurve.cpp - UserInterface/RiuWellLogPlotCurve.h + UserInterface/RiuWellLogCurve.cpp + UserInterface/RiuWellLogCurve.h UserInterface/RiuWellLogTrack.cpp UserInterface/RiuWellLogTrack.h UserInterface/RiuProjectPropertyView.h diff --git a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp index ed4c9d0135..51c635f6b8 100644 --- a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp +++ b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp @@ -19,7 +19,7 @@ #include "RicExportToLasFileFeature.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RigWellLogFile.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp index 4888ce4d2a..484664d25f 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeature.cpp @@ -26,7 +26,7 @@ #include "RimProject.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RiaApplication.h" diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp index e23bc60938..f7341ee6b1 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp @@ -21,7 +21,7 @@ #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RiuMainWindow.h" diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index b7cf593110..8ef43ea022 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -64,7 +64,7 @@ ${CEE_CURRENT_LIST_DIR}RimMainPlotCollection.h ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCollection.h ${CEE_CURRENT_LIST_DIR}RimWellLogPlot.h ${CEE_CURRENT_LIST_DIR}RimWellLogTrack.h -${CEE_CURRENT_LIST_DIR}RimWellLogPlotCurve.h +${CEE_CURRENT_LIST_DIR}RimWellLogCurve.h ${CEE_CURRENT_LIST_DIR}RimViewLinker.h ${CEE_CURRENT_LIST_DIR}RimViewLinkerCollection.h ${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurve.h @@ -133,7 +133,7 @@ ${CEE_CURRENT_LIST_DIR}RimMainPlotCollection.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogPlotCollection.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogPlot.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogTrack.cpp -${CEE_CURRENT_LIST_DIR}RimWellLogPlotCurve.cpp +${CEE_CURRENT_LIST_DIR}RimWellLogCurve.cpp ${CEE_CURRENT_LIST_DIR}RimViewLinker.cpp ${CEE_CURRENT_LIST_DIR}RimViewLinkerCollection.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurve.cpp diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp index f6142e0aa3..7d59856114 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -31,7 +31,7 @@ #include "RimReservoirCellResultsStorage.h" #include "RimView.h" #include "RimViewLinker.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "cafPdmUiListEditor.h" diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp index 4f65e507a0..c813f5f263 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp @@ -31,7 +31,7 @@ #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechView.h" #include "RimViewLinker.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "cafPdmUiListEditor.h" diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 047e93f5f6..0d63a23332 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -626,7 +626,7 @@ void RimProject::computeUtmAreaOfInterest() #include "RimEclipseFaultColors.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RimWellLogFileChannel.h" #include diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp similarity index 99% rename from ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp rename to ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index a95175eb8c..144b5021d8 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -17,13 +17,13 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" -#include "RiuWellLogPlotCurve.h" +#include "RiuWellLogCurve.h" #include "RiuWellLogTrack.h" #include "cvfAssert.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h similarity index 100% rename from ApplicationCode/ProjectDataModel/RimWellLogPlotCurve.h rename to ApplicationCode/ProjectDataModel/RimWellLogCurve.h diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 77ebfa5041..16193b5098 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -37,7 +37,7 @@ #include "RimProject.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" @@ -46,7 +46,7 @@ #include "RimGeoMechView.h" #include "RimGeoMechCellColors.h" -#include "RiuWellLogPlotCurve.h" +#include "RiuWellLogCurve.h" #include "RiuWellLogTrack.h" #include "cafPdmUiTreeOrdering.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index 0c5bcdad60..9f0428f412 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -19,7 +19,7 @@ #pragma once -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "cafPdmPtrField.h" #include "cafPdmChildField.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index b925080d82..46aca9455b 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -29,7 +29,7 @@ #include "RimWellLogPlot.h" #include "RiuWellLogTrack.h" -#include "RiuWellLogPlotCurve.h" +#include "RiuWellLogCurve.h" #include "RiaApplication.h" #include "RiaPreferences.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h index 5c89e5778d..c2c99be728 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.h @@ -19,7 +19,7 @@ #pragma once -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "cafPdmPtrField.h" #include "cafPdmField.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index d92c049e2f..2fb419c114 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -20,7 +20,7 @@ #include "RimWellLogTrack.h" #include "RimWellLogPlot.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RiuWellLogTrack.h" #include "RiuWellLogPlot.h" diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index c4c2b2b906..6148816dac 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -19,7 +19,7 @@ #include "RigWellLogFile.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "well.hpp" #include "laswell.hpp" diff --git a/ApplicationCode/UserInterface/RiuDragDrop.cpp b/ApplicationCode/UserInterface/RiuDragDrop.cpp index b90ae79f5c..7f239b72ff 100644 --- a/ApplicationCode/UserInterface/RiuDragDrop.cpp +++ b/ApplicationCode/UserInterface/RiuDragDrop.cpp @@ -31,7 +31,7 @@ #include "RimMimeData.h" #include "RimWellLogFileChannel.h" #include "RimWellLogTrack.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp b/ApplicationCode/UserInterface/RiuWellLogCurve.cpp similarity index 98% rename from ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp rename to ApplicationCode/UserInterface/RiuWellLogCurve.cpp index 3afeb1c20b..a4ec3ea0e2 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogCurve.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RiuWellLogPlotCurve.h" +#include "RiuWellLogCurve.h" #include "RigWellLogCurveData.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogPlotCurve.h b/ApplicationCode/UserInterface/RiuWellLogCurve.h similarity index 100% rename from ApplicationCode/UserInterface/RiuWellLogPlotCurve.h rename to ApplicationCode/UserInterface/RiuWellLogCurve.h diff --git a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp index 4863c33dbe..4447a3af8b 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp @@ -21,7 +21,7 @@ #include "RimWellLogPlot.h" #include "RimWellLogTrack.h" -#include "RimWellLogPlotCurve.h" +#include "RimWellLogCurve.h" #include "RiuMainWindow.h" From 30adb2661e7a1471bd1635c30469ffbe854f99c2 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 4 Nov 2015 09:39:55 +0100 Subject: [PATCH 008/290] (#612) Added time history plot as a dockwidget --- ApplicationCode/CMakeLists.txt | 2 + .../UserInterface/RiuMainWindow.cpp | 21 +-- ApplicationCode/UserInterface/RiuMainWindow.h | 3 + .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 158 ++++++++++++++++++ .../UserInterface/RiuTimeHistoryQwtPlot.h | 46 +++++ 5 files changed, 218 insertions(+), 12 deletions(-) create mode 100644 ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp create mode 100644 ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 0ec9defc82..a8c4061212 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -90,6 +90,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuWellLogTrack.h UserInterface/RiuProjectPropertyView.h UserInterface/RiuProjectPropertyView.cpp + UserInterface/RiuTimeHistoryQwtPlot.h + UserInterface/RiuTimeHistoryQwtPlot.cpp ) set( SOCKET_INTERFACE_FILES diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index b57ba4f65d..3dc6efce43 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -58,6 +58,7 @@ #include "RiuProcessMonitor.h" #include "RiuProjectPropertyView.h" #include "RiuResultInfoPanel.h" +#include "RiuTimeHistoryQwtPlot.h" #include "RiuTreeViewEventFilter.h" #include "RiuViewer.h" #include "RiuWellImportWizard.h" @@ -661,19 +662,15 @@ void RiuMainWindow::createDockPanels() addDockWidget(Qt::BottomDockWidgetArea, dockPanel); } - // Test - create well log viewer in a dock widget - // TODO: remove after making MDI widgets for well log viewers -// { -// QDockWidget* dockPanel = new QDockWidget("TEST - Well Log Viewer", this); -// dockPanel->setObjectName("dockWellLogViewer"); -// dockPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); -// -// RiuWellLogViewer* wellLogViewer = new RiuWellLogViewer(dockPanel); -// dockPanel->setWidget(wellLogViewer); -// -// addDockWidget(Qt::BottomDockWidgetArea, dockPanel); -// } + { + QDockWidget* dockPanel = new QDockWidget("Time History Plot", this); + dockPanel->setObjectName("dockTimeHistoryPanel"); + dockPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); + m_timeHistoryQwtPlot = new RiuTimeHistoryQwtPlot(dockPanel); + dockPanel->setWidget(m_timeHistoryQwtPlot); + addDockWidget(Qt::RightDockWidgetArea, dockPanel); + } setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea); diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index a6db88f08b..ea0553c699 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -42,6 +42,7 @@ class RiuProcessMonitor; class RiuResultInfoPanel; class RiuViewer; class RiuWellLogPlot; +class RiuTimeHistoryQwtPlot; namespace caf { @@ -198,6 +199,8 @@ class RiuMainWindow : public QMainWindow RiuResultInfoPanel* m_resultInfoPanel; RiuProcessMonitor* m_processMonitor; + RiuTimeHistoryQwtPlot* m_timeHistoryQwtPlot; + QMenu* m_windowMenu; diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp new file mode 100644 index 0000000000..c75a047e28 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -0,0 +1,158 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuTimeHistoryQwtPlot.h" + +#include "cvfAssert.h" + +#include "qwt_legend.h" +#include "qwt_plot_curve.h" +#include "qwt_plot_layout.h" +#include "qwt_scale_engine.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) + : QwtPlot(parent) +{ +/* + setFocusPolicy(Qt::ClickFocus); +*/ + setDefaults(); + + std::vector xValues; + std::vector yValues; + + xValues.push_back(1); + xValues.push_back(2); + xValues.push_back(3); + xValues.push_back(4); + + yValues.push_back(10); + yValues.push_back(12); + yValues.push_back(15); + yValues.push_back(11); + + addCurve("Test", xValues, yValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() +{ + deleteAllCurves(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& xValues, const std::vector& yValues) +{ + CVF_ASSERT(xValues.size() == yValues.size()); + + QwtPlotCurve* plotCurve = new QwtPlotCurve("Curve 1"); + plotCurve->setSamples(xValues.data(), yValues.data(), (int) xValues.size()); + plotCurve->setTitle(curveName); + + plotCurve->attach(this); + m_plotCurves.push_back(plotCurve); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTimeHistoryQwtPlot::deleteAllCurves() +{ + for (size_t i = 0; i < m_plotCurves.size(); i++) + { + m_plotCurves[i]->detach(); + delete m_plotCurves[i]; + } + + m_plotCurves.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTimeHistoryQwtPlot::setDefaults() +{ + QPalette newPalette(palette()); + newPalette.setColor(QPalette::Background, Qt::white); + setPalette(newPalette); + + setAutoFillBackground(true); + setCanvasBackground(Qt::white); + + QFrame* canvasFrame = dynamic_cast(canvas()); + if (canvasFrame) + { + canvasFrame->setFrameShape(QFrame::NoFrame); + } + + canvas()->setMouseTracking(true); + canvas()->installEventFilter(this); + +/* + QPen gridPen(Qt::SolidLine); + gridPen.setColor(Qt::lightGray); + m_grid->setPen(gridPen); +*/ + + enableAxis(QwtPlot::xTop, true); + enableAxis(QwtPlot::yLeft, true); + enableAxis(QwtPlot::xBottom, false); + enableAxis(QwtPlot::yRight, false); + + plotLayout()->setAlignCanvasToScales(true); + + axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Inverted, true); + + // Align the canvas with the actual min and max values of the curves + axisScaleEngine(QwtPlot::xTop)->setAttribute(QwtScaleEngine::Floating, true); + axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating, true); + setAxisScale(QwtPlot::yLeft, 1000, 0); + setAxisScale(QwtPlot::xTop, -10, 100); + + QFont xAxisFont = axisFont(QwtPlot::xTop); + xAxisFont.setPixelSize(9); + setAxisFont(QwtPlot::xTop, xAxisFont); + + QFont yAxisFont = axisFont(QwtPlot::yLeft); + yAxisFont.setPixelSize(9); + setAxisFont(QwtPlot::yLeft, yAxisFont); + + QwtText axisTitleY = axisTitle(QwtPlot::yLeft); + QFont yAxisTitleFont = axisTitleY.font(); + yAxisTitleFont.setPixelSize(9); + yAxisTitleFont.setBold(false); + axisTitleY.setFont(yAxisTitleFont); + axisTitleY.setRenderFlags(Qt::AlignRight); + setAxisTitle(QwtPlot::yLeft, axisTitleY); + + + + QwtLegend* legend = new QwtLegend(this); + + // The legend will be deleted in the destructor of the plot or when + // another legend is inserted. + this->insertLegend(legend, BottomLegend); +} diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h new file mode 100644 index 0000000000..af3073e3ed --- /dev/null +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "qwt_plot.h" + +class QwtPlotCurve; + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuTimeHistoryQwtPlot : public QwtPlot +{ +public: + RiuTimeHistoryQwtPlot(QWidget* parent = NULL); + virtual ~RiuTimeHistoryQwtPlot(); + + void addCurve(const QString& curveName, const std::vector& xValues, const std::vector& yValues); + void deleteAllCurves(); + +private: + void setDefaults(); + +private: + std::vector m_plotCurves; +}; + From 0011f090deaa70afc9f469b30f29509502e8cbd0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 4 Nov 2015 14:18:52 +0100 Subject: [PATCH 009/290] (#612) Time history result accessor and display of curve from selection --- .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../RigTimeHistoryResultAccessor.cpp | 118 ++++++++++++++++++ .../RigTimeHistoryResultAccessor.h | 58 +++++++++ .../UserInterface/RiuMainWindow.cpp | 8 ++ ApplicationCode/UserInterface/RiuMainWindow.h | 2 + .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 67 ++++------ .../UserInterface/RiuTimeHistoryQwtPlot.h | 2 +- .../UserInterface/RiuViewerCommands.cpp | 38 ++++++ .../UserInterface/RiuViewerCommands.h | 2 + 9 files changed, 256 insertions(+), 41 deletions(-) create mode 100644 ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp create mode 100644 ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 33f6106e01..4fa870d18c 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -37,6 +37,7 @@ ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.h +${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -68,6 +69,7 @@ ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.cpp +${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp new file mode 100644 index 0000000000..3b0f7283ee --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp @@ -0,0 +1,118 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigTimeHistoryResultAccessor.h" + +#include // Needed for HUGE_VAL on Linux + +#include "RigCaseData.h" +#include "RigResultAccessor.h" +#include "RigResultAccessorFactory.h" +#include "RigCaseCellResultsData.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigTimeHistoryResultAccessor::RigTimeHistoryResultAccessor(RigCaseData* eclipseCaseData, size_t gridIndex, size_t cellIndex, size_t scalarResultIndex, RifReaderInterface::PorosityModelResultType porosityModel) + : m_eclipseCaseData(eclipseCaseData), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex), + m_scalarResultIndex(scalarResultIndex), + m_porosityModel(porosityModel) +{ + m_face = cvf::StructGridInterface::NO_FACE; + m_nncIndex = cvf::UNDEFINED_SIZE_T; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryResultAccessor::setFace(cvf::StructGridInterface::FaceType face) +{ + m_face = face; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryResultAccessor::setNncIndex(size_t nncIndex) +{ + m_nncIndex = nncIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigTimeHistoryResultAccessor::yValues() const +{ + return m_yValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigTimeHistoryResultAccessor::topologyText() +{ + QString text; + + if (m_eclipseCaseData) + { + if (m_cellIndex != cvf::UNDEFINED_SIZE_T) + { + size_t i = 0; + size_t j = 0; + size_t k = 0; + if (m_eclipseCaseData->grid(m_gridIndex)->ijkFromCellIndex(m_cellIndex, &i, &j, &k)) + { + // Adjust to 1-based Eclipse indexing + i++; + j++; + k++; + + cvf::StructGridInterface::FaceEnum faceEnum(m_face); + + text += QString("Cell : [%1, %2, %3]").arg(i).arg(j).arg(k); + } + } + } + + return text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTimeHistoryResultAccessor::computeCurveData() +{ + if (m_yValues.size() != 0) return; + + if (m_eclipseCaseData) + { + size_t timeStepCount = m_eclipseCaseData->results(m_porosityModel)->timeStepCount(m_scalarResultIndex); + + for (size_t i = 0; i < timeStepCount; i++) + { + cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(m_eclipseCaseData, m_gridIndex, m_porosityModel, i, m_scalarResultIndex); + + m_yValues.push_back(resultAccessor->cellScalar(m_cellIndex)); + } + } +} + diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h new file mode 100644 index 0000000000..928a627741 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h @@ -0,0 +1,58 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfStructGrid.h" +#include "RifReaderInterface.h" + +class RigCaseData; + + +class RigTimeHistoryResultAccessor +{ +public: + RigTimeHistoryResultAccessor(RigCaseData* eclipseCaseData, size_t gridIndex, size_t cellIndex, size_t scalarResultIndex, RifReaderInterface::PorosityModelResultType porosityModel); + + void setFace(cvf::StructGridInterface::FaceType face); + void setNncIndex(size_t nncIndex); + + void computeCurveData(); + QString topologyText(); + + QString curveName() const; + std::vector yValues() const; + +private: + + +private: + RigCaseData* m_eclipseCaseData; + + size_t m_gridIndex; + size_t m_cellIndex; + size_t m_nncIndex; + size_t m_scalarResultIndex; + + cvf::StructGridInterface::FaceType m_face; + RifReaderInterface::PorosityModelResultType m_porosityModel; + + std::vector m_yValues; +}; + diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 3dc6efce43..5e5f3c0d8b 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1165,6 +1165,14 @@ QMdiSubWindow* RiuMainWindow::findMdiSubWindow(QWidget* viewer) return NULL; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuTimeHistoryQwtPlot* RiuMainWindow::timeHistoryPlot() +{ + return m_timeHistoryQwtPlot; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index ea0553c699..d2755cffd5 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -113,6 +113,8 @@ class RiuMainWindow : public QMainWindow bool isAnyMdiSubWindowVisible(); QMdiSubWindow* findMdiSubWindow(QWidget* viewer); + RiuTimeHistoryQwtPlot* timeHistoryPlot(); + protected: virtual void closeEvent(QCloseEvent* event); diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index c75a047e28..40f9151a10 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -25,6 +25,8 @@ #include "qwt_plot_curve.h" #include "qwt_plot_layout.h" #include "qwt_scale_engine.h" +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" //-------------------------------------------------------------------------------------------------- /// @@ -32,25 +34,7 @@ RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) : QwtPlot(parent) { -/* - setFocusPolicy(Qt::ClickFocus); -*/ setDefaults(); - - std::vector xValues; - std::vector yValues; - - xValues.push_back(1); - xValues.push_back(2); - xValues.push_back(3); - xValues.push_back(4); - - yValues.push_back(10); - yValues.push_back(12); - yValues.push_back(15); - yValues.push_back(11); - - addCurve("Test", xValues, yValues); } //-------------------------------------------------------------------------------------------------- @@ -64,16 +48,28 @@ RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& xValues, const std::vector& yValues) +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& yValues) { - CVF_ASSERT(xValues.size() == yValues.size()); + CVF_ASSERT(dateTimes.size() == yValues.size()); QwtPlotCurve* plotCurve = new QwtPlotCurve("Curve 1"); - plotCurve->setSamples(xValues.data(), yValues.data(), (int) xValues.size()); + + QPolygonF points; + for (int i = 0; i < dateTimes.size(); i++) + { + double milliSecSinceEpoch = QwtDate::toDouble(dateTimes[i]); + points << QPointF(milliSecSinceEpoch, yValues[i]); + } + + plotCurve->setSamples(points); plotCurve->setTitle(curveName); plotCurve->attach(this); m_plotCurves.push_back(plotCurve); + + this->setAxisScale( QwtPlot::xTop, QwtDate::toDouble(dateTimes.front()), QwtDate::toDouble(dateTimes.back())); + + this->replot(); } //-------------------------------------------------------------------------------------------------- @@ -111,30 +107,23 @@ void RiuTimeHistoryQwtPlot::setDefaults() canvas()->setMouseTracking(true); canvas()->installEventFilter(this); -/* - QPen gridPen(Qt::SolidLine); - gridPen.setColor(Qt::lightGray); - m_grid->setPen(gridPen); -*/ - - enableAxis(QwtPlot::xTop, true); + enableAxis(QwtPlot::xBottom, true); enableAxis(QwtPlot::yLeft, true); - enableAxis(QwtPlot::xBottom, false); + enableAxis(QwtPlot::xTop, false); enableAxis(QwtPlot::yRight, false); plotLayout()->setAlignCanvasToScales(true); - axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Inverted, true); + QwtDateScaleDraw* scaleDraw = new QwtDateScaleDraw(Qt::UTC); + scaleDraw->setDateFormat(QwtDate::Year, QString("dd-MM-yyyy")); + + QwtDateScaleEngine* scaleEngine = new QwtDateScaleEngine(Qt::UTC); + setAxisScaleEngine(QwtPlot::xBottom, scaleEngine); + setAxisScaleDraw(QwtPlot::xBottom, scaleDraw); - // Align the canvas with the actual min and max values of the curves - axisScaleEngine(QwtPlot::xTop)->setAttribute(QwtScaleEngine::Floating, true); - axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating, true); - setAxisScale(QwtPlot::yLeft, 1000, 0); - setAxisScale(QwtPlot::xTop, -10, 100); - - QFont xAxisFont = axisFont(QwtPlot::xTop); + QFont xAxisFont = axisFont(QwtPlot::xBottom); xAxisFont.setPixelSize(9); - setAxisFont(QwtPlot::xTop, xAxisFont); + setAxisFont(QwtPlot::xBottom, xAxisFont); QFont yAxisFont = axisFont(QwtPlot::yLeft); yAxisFont.setPixelSize(9); @@ -149,9 +138,7 @@ void RiuTimeHistoryQwtPlot::setDefaults() setAxisTitle(QwtPlot::yLeft, axisTitleY); - QwtLegend* legend = new QwtLegend(this); - // The legend will be deleted in the destructor of the plot or when // another legend is inserted. this->insertLegend(legend, BottomLegend); diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h index af3073e3ed..95323c9d88 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -34,7 +34,7 @@ class RiuTimeHistoryQwtPlot : public QwtPlot RiuTimeHistoryQwtPlot(QWidget* parent = NULL); virtual ~RiuTimeHistoryQwtPlot(); - void addCurve(const QString& curveName, const std::vector& xValues, const std::vector& yValues); + void addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& yValues); void deleteAllCurves(); private: diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 6a9735e731..f246365420 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -26,9 +26,11 @@ #include "Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h" #include "RigCaseData.h" +#include "RigCaseCellResultsData.h" #include "RigFemPartCollection.h" #include "RigFemPartGrid.h" #include "RigGeoMechCaseData.h" +#include "RigTimeHistoryResultAccessor.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" @@ -55,6 +57,7 @@ #include "RiuFemResultTextBuilder.h" #include "RiuMainWindow.h" #include "RiuResultTextBuilder.h" +#include "RiuTimeHistoryQwtPlot.h" #include "RiuViewer.h" #include "RivFemPartGeometryGenerator.h" @@ -489,6 +492,13 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) resultInfo = textBuilder.mainResultText(); pickInfo = textBuilder.topologyText(", "); + + if (eclipseView->cellResult()->hasDynamicResult() && + eclipseView->eclipseCase() && + eclipseView->eclipseCase()->reservoirData()) + { + addTimeHistoryCurve(eclipseView, gridIndex, cellIndex); + } } else if (geomView) { @@ -517,6 +527,34 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) mainWnd->setResultInfo(resultInfo); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex) +{ + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); + + std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); + + RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); + timeHistResultAccessor.computeCurveData(); + + QString curveName = eclipseView->eclipseCase()->caseUserDescription(); + curveName += " - Result : "; + curveName += eclipseView->cellResult()->resultVariable(); + curveName += " - "; + curveName += timeHistResultAccessor.topologyText(); + + std::vector yValues = timeHistResultAccessor.yValues(); + + CVF_ASSERT(timeStepDates.size() == yValues.size()); + + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + + mainWnd->timeHistoryPlot()->deleteAllCurves(); + mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, yValues); +} + //-------------------------------------------------------------------------------------------------- /// Perform picking and return the index of the face that was hit, if a drawable geo was hit //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index edb0bff949..856079754c 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -49,6 +49,7 @@ class RiuViewerCommands: public QObject void displayContextMenu(QMouseEvent* event); void handlePickAction(int winPosX, int winPosY); + private slots: void slotRangeFilterI(); void slotRangeFilterJ(); @@ -62,6 +63,7 @@ private slots: void createSliceRangeFilter(int ijOrk); void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); void updateSelectionFromPickedPart(cvf::Part* part); + void addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex); size_t m_currentGridIdx; size_t m_currentCellIndex; From 7db6835075ae16008f16b2ef3aa0f07cbedd4877 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 5 Nov 2015 07:27:04 +0100 Subject: [PATCH 010/290] (#612) Append new curves on cell click, clear when no cell is hit --- .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 6 ++++++ .../UserInterface/RiuViewerCommands.cpp | 14 ++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index 40f9151a10..bb318a2602 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -19,7 +19,10 @@ #include "RiuTimeHistoryQwtPlot.h" +#include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" + #include "cvfAssert.h" +#include "cvfColor3.h" #include "qwt_legend.h" #include "qwt_plot_curve.h" @@ -64,6 +67,9 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector plotCurve->setSamples(points); plotCurve->setTitle(curveName); + cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); + plotCurve->setPen(QPen(QColor(curveColor.rByte(), curveColor.gByte(), curveColor.bByte()))); + plotCurve->attach(this); m_plotCurves.push_back(plotCurve); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index f246365420..bb651890d3 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -472,6 +472,9 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) } } + + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + // Compose a info text regarding the hit QString pickInfo = "No hits"; @@ -512,17 +515,17 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) pickInfo = textBuilder.topologyText(", "); } } + else + { + // Delete all curves if no cell is hit + mainWnd->timeHistoryPlot()->deleteAllCurves(); + } if (wellPath) { pickInfo = QString("Well path hit: %1").arg(wellPath->name()); } - // Display the text - - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (!mainWnd) return; - mainWnd->statusBar()->showMessage(pickInfo); mainWnd->setResultInfo(resultInfo); } @@ -551,7 +554,6 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t RiuMainWindow* mainWnd = RiuMainWindow::instance(); - mainWnd->timeHistoryPlot()->deleteAllCurves(); mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, yValues); } From b30604edd166d8f780470cf4da984cda7dafaaf2 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 5 Nov 2015 09:03:57 +0100 Subject: [PATCH 011/290] Rename --- .../RigTimeHistoryResultAccessor.cpp | 23 ++++++++----------- .../RigTimeHistoryResultAccessor.h | 16 ++++--------- .../UserInterface/RiuViewerCommands.cpp | 4 ++-- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp index 3b0f7283ee..2a1bb6aaa4 100644 --- a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.cpp @@ -38,7 +38,8 @@ RigTimeHistoryResultAccessor::RigTimeHistoryResultAccessor(RigCaseData* eclipseC m_porosityModel(porosityModel) { m_face = cvf::StructGridInterface::NO_FACE; - m_nncIndex = cvf::UNDEFINED_SIZE_T; + + computeTimeHistoryData(); } //-------------------------------------------------------------------------------------------------- @@ -47,28 +48,22 @@ RigTimeHistoryResultAccessor::RigTimeHistoryResultAccessor(RigCaseData* eclipseC void RigTimeHistoryResultAccessor::setFace(cvf::StructGridInterface::FaceType face) { m_face = face; -} -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigTimeHistoryResultAccessor::setNncIndex(size_t nncIndex) -{ - m_nncIndex = nncIndex; + computeTimeHistoryData(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RigTimeHistoryResultAccessor::yValues() const +std::vector RigTimeHistoryResultAccessor::timeHistoryValues() const { - return m_yValues; + return m_timeHistoryValues; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RigTimeHistoryResultAccessor::topologyText() +QString RigTimeHistoryResultAccessor::topologyText() const { QString text; @@ -99,9 +94,9 @@ QString RigTimeHistoryResultAccessor::topologyText() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigTimeHistoryResultAccessor::computeCurveData() +void RigTimeHistoryResultAccessor::computeTimeHistoryData() { - if (m_yValues.size() != 0) return; + m_timeHistoryValues.clear(); if (m_eclipseCaseData) { @@ -111,7 +106,7 @@ void RigTimeHistoryResultAccessor::computeCurveData() { cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(m_eclipseCaseData, m_gridIndex, m_porosityModel, i, m_scalarResultIndex); - m_yValues.push_back(resultAccessor->cellScalar(m_cellIndex)); + m_timeHistoryValues.push_back(resultAccessor->cellScalar(m_cellIndex)); } } } diff --git a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h index 928a627741..1caacfb575 100644 --- a/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h +++ b/ApplicationCode/ReservoirDataModel/RigTimeHistoryResultAccessor.h @@ -29,30 +29,24 @@ class RigTimeHistoryResultAccessor { public: RigTimeHistoryResultAccessor(RigCaseData* eclipseCaseData, size_t gridIndex, size_t cellIndex, size_t scalarResultIndex, RifReaderInterface::PorosityModelResultType porosityModel); - void setFace(cvf::StructGridInterface::FaceType face); - void setNncIndex(size_t nncIndex); - - void computeCurveData(); - QString topologyText(); - QString curveName() const; - std::vector yValues() const; + QString topologyText() const; + std::vector timeHistoryValues() const; private: - + void computeTimeHistoryData(); private: - RigCaseData* m_eclipseCaseData; + RigCaseData* m_eclipseCaseData; size_t m_gridIndex; size_t m_cellIndex; - size_t m_nncIndex; size_t m_scalarResultIndex; cvf::StructGridInterface::FaceType m_face; RifReaderInterface::PorosityModelResultType m_porosityModel; - std::vector m_yValues; + std::vector m_timeHistoryValues; }; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index bb651890d3..4631782a85 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -540,7 +540,7 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); - timeHistResultAccessor.computeCurveData(); + timeHistResultAccessor.computeTimeHistoryData(); QString curveName = eclipseView->eclipseCase()->caseUserDescription(); curveName += " - Result : "; @@ -548,7 +548,7 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t curveName += " - "; curveName += timeHistResultAccessor.topologyText(); - std::vector yValues = timeHistResultAccessor.yValues(); + std::vector yValues = timeHistResultAccessor.timeHistoryValues(); CVF_ASSERT(timeStepDates.size() == yValues.size()); From ff6e2755aab14a332b648b2a97ab6f4ad4e4ded7 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 5 Nov 2015 11:45:18 +0100 Subject: [PATCH 012/290] Added time history plot for geo mech models --- .../GeoMech/GeoMechDataModel/CMakeLists.txt | 2 + .../RigFemTimeHistoryResultAccessor.cpp | 148 ++++++++++++++++++ .../RigFemTimeHistoryResultAccessor.h | 54 +++++++ .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 21 ++- .../UserInterface/RiuTimeHistoryQwtPlot.h | 4 +- .../UserInterface/RiuViewerCommands.cpp | 49 +++++- .../UserInterface/RiuViewerCommands.h | 1 + 7 files changed, 271 insertions(+), 8 deletions(-) create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.cpp create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.h diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt index b7fbf20e04..530de2fb36 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt +++ b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt @@ -32,6 +32,8 @@ add_library( ${PROJECT_NAME} RigFemPartGrid.cpp RigFemResultAddress.h RigFemResultPosEnum.h + RigFemTimeHistoryResultAccessor.h + RigFemTimeHistoryResultAccessor.cpp ) target_link_libraries( ${PROJECT_NAME} LibCore cafTensor ResultStatisticsCache) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.cpp new file mode 100644 index 0000000000..a06bb96463 --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.cpp @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigFemTimeHistoryResultAccessor.h" + +#include "RigFemPart.h" +#include "RigFemPartCollection.h" +#include "RigFemPartGrid.h" +#include "RigFemPartResultsCollection.h" +#include "RigFemTypes.h" +#include "RigGeoMechCaseData.h" + +#include // Needed for HUGE_VAL on Linux + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFemTimeHistoryResultAccessor::RigFemTimeHistoryResultAccessor(RigGeoMechCaseData* geomData, RigFemResultAddress femResultAddress, + size_t gridIndex, size_t cellIndex, const cvf::Vec3d& intersectionPoint) + : m_geoMechCaseData(geomData), + m_femResultAddress(femResultAddress), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex), + m_intersectionPoint(intersectionPoint) +{ + computeTimeHistoryData(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RigFemTimeHistoryResultAccessor::topologyText() const +{ + QString text; + + if (m_geoMechCaseData) + { + RigFemPart* femPart = m_geoMechCaseData->femParts()->part(m_gridIndex); + int elementId = femPart->elmId(m_cellIndex); + text += QString("Element : Id[%1]").arg(elementId); + + size_t i = 0; + size_t j = 0; + size_t k = 0; + if (m_geoMechCaseData->femParts()->part(m_gridIndex)->structGrid()->ijkFromCellIndex(m_cellIndex, &i, &j, &k)) + { + // Adjust to 1-based Eclipse indexing + i++; + j++; + k++; + + cvf::Vec3d domainCoord = m_intersectionPoint; + text += QString(", ijk[%1, %2, %3]").arg(i).arg(j).arg(k); + + QString formattedText; + formattedText.sprintf("Intersection point : [E: %.2f, N: %.2f, Depth: %.2f]", domainCoord.x(), domainCoord.y(), -domainCoord.z()); + + text += formattedText; + } + } + + return text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigFemTimeHistoryResultAccessor::timeHistoryValues() const +{ + return m_timeHistoryValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemTimeHistoryResultAccessor::computeTimeHistoryData() +{ + m_timeHistoryValues.clear(); + + size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; + + // Compute scalar result index from geometry + { + RigFemPart* femPart = m_geoMechCaseData->femParts()->part(m_gridIndex); + RigElementType elmType = femPart->elementType(m_cellIndex); + const int* elmentConn = femPart->connectivities(m_cellIndex); + int elmNodeCount = RigFemTypes::elmentNodeCount(elmType); + + // Find the closest node + int closestLocalNode = -1; + float minDist = std::numeric_limits::infinity(); + for (int lNodeIdx = 0; lNodeIdx < elmNodeCount; ++lNodeIdx) + { + int nodeIdx = elmentConn[lNodeIdx]; + cvf::Vec3f nodePos = femPart->nodes().coordinates[nodeIdx]; + float dist = (nodePos - cvf::Vec3f(m_intersectionPoint)).lengthSquared(); + if (dist < minDist) + { + closestLocalNode = lNodeIdx; + minDist = dist; + } + } + + // Create a text showing the results from the closest node + if (closestLocalNode >= 0) + { + int nodeIdx = elmentConn[closestLocalNode]; + if (m_femResultAddress.resultPosType == RIG_NODAL) + { + scalarResultIndex = static_cast(nodeIdx); + } + else + { + scalarResultIndex = femPart->elementNodeResultIdx(static_cast(m_cellIndex), closestLocalNode); + } + } + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) return; + + RigFemPartResultsCollection* femPartResultsColl = m_geoMechCaseData->femPartResults(); + for (int frameIdx = 0; frameIdx < femPartResultsColl->frameCount(); frameIdx++) + { + const std::vector& scalarResults = m_geoMechCaseData->femPartResults()->resultValues(m_femResultAddress, static_cast(m_gridIndex), frameIdx); + if (scalarResults.size()) + { + float scalarValue = scalarResults[scalarResultIndex]; + + m_timeHistoryValues.push_back(scalarValue); + } + } +} diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.h new file mode 100644 index 0000000000..cb47556c2a --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemTimeHistoryResultAccessor.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigFemResultAddress.h" + +#include "cvfStructGrid.h" +#include "cvfVector3.h" + +class RigGeoMechCaseData; + + +class RigFemTimeHistoryResultAccessor +{ +public: + RigFemTimeHistoryResultAccessor(RigGeoMechCaseData* geomData, RigFemResultAddress femResultAddress, + size_t gridIndex, size_t cellIndex, const cvf::Vec3d& intersectionPoint); + + QString topologyText() const; + std::vector timeHistoryValues() const; + +private: + void computeTimeHistoryData(); + +private: + RigGeoMechCaseData* m_geoMechCaseData; + RigFemResultAddress m_femResultAddress; + + size_t m_gridIndex; + size_t m_cellIndex; + size_t m_scalarResultIndex; + + cvf::Vec3d m_intersectionPoint; + + std::vector m_timeHistoryValues; +}; + diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index bb318a2602..d0f8f285fc 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -51,9 +51,9 @@ RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& yValues) +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& timeHistoryValues) { - CVF_ASSERT(dateTimes.size() == yValues.size()); + CVF_ASSERT(dateTimes.size() == timeHistoryValues.size()); QwtPlotCurve* plotCurve = new QwtPlotCurve("Curve 1"); @@ -61,7 +61,7 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector for (int i = 0; i < dateTimes.size(); i++) { double milliSecSinceEpoch = QwtDate::toDouble(dateTimes[i]); - points << QPointF(milliSecSinceEpoch, yValues[i]); + points << QPointF(milliSecSinceEpoch, timeHistoryValues[i]); } plotCurve->setSamples(points); @@ -78,6 +78,21 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector this->replot(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& frameTimes, const std::vector& timeHistoryValues) +{ + std::vector dateTimes; + + for (size_t i = 0; i < frameTimes.size(); i++) + { + dateTimes.push_back(QwtDate::toDateTime(frameTimes[i])); + } + + addCurve(curveName, dateTimes, timeHistoryValues); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h index 95323c9d88..1caff45db1 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -34,7 +34,9 @@ class RiuTimeHistoryQwtPlot : public QwtPlot RiuTimeHistoryQwtPlot(QWidget* parent = NULL); virtual ~RiuTimeHistoryQwtPlot(); - void addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& yValues); + void addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& timeHistoryValues); + void addCurve(const QString& curveName, const std::vector& frameTimes, const std::vector& timeHistoryValues); + void deleteAllCurves(); private: diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 4631782a85..84592b9c97 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -77,6 +77,7 @@ #include #include #include +#include "RigFemTimeHistoryResultAccessor.h" //================================================================================================== // @@ -513,6 +514,12 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) resultInfo = textBuilder.mainResultText(); pickInfo = textBuilder.topologyText(", "); + + if (geomView->cellResult() && + geomView->cellResult()->hasResult()) + { + addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint); + } } } else @@ -540,7 +547,6 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); - timeHistResultAccessor.computeTimeHistoryData(); QString curveName = eclipseView->eclipseCase()->caseUserDescription(); curveName += " - Result : "; @@ -548,13 +554,48 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t curveName += " - "; curveName += timeHistResultAccessor.topologyText(); - std::vector yValues = timeHistResultAccessor.timeHistoryValues(); + std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - CVF_ASSERT(timeStepDates.size() == yValues.size()); + CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); RiuMainWindow* mainWnd = RiuMainWindow::instance(); - mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, yValues); + mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, timeHistoryValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint) +{ + if (geoMechView && + geoMechView->cellResult() && + geoMechView->geoMechCase() && + geoMechView->geoMechCase()->geoMechData()) + { + RigFemTimeHistoryResultAccessor timeHistResultAccessor(geoMechView->geoMechCase()->geoMechData(), geoMechView->cellResult->resultAddress(), gridIndex, cellIndex, localIntersectionPoint); + + QString curveName; + curveName.append(geoMechView->geoMechCase()->caseUserDescription() + ", "); + + caf::AppEnum resPosAppEnum = geoMechView->cellResult()->resultPositionType(); + curveName.append(resPosAppEnum.uiText() + ", "); + curveName.append(geoMechView->cellResult()->resultFieldUiName()+ ", ") ; + curveName.append(geoMechView->cellResult()->resultComponentUiName() + ":\n"); + curveName.append(timeHistResultAccessor.topologyText()); + + std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); + std::vector frameTimes; + for (size_t i = 0; i < timeHistoryValues.size(); i++) + { + frameTimes.push_back(i); + } + + CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); + + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + mainWnd->timeHistoryPlot()->addCurve(curveName, frameTimes, timeHistoryValues); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 856079754c..2a8de9e20d 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -64,6 +64,7 @@ private slots: void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); void updateSelectionFromPickedPart(cvf::Part* part); void addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex); + void addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint); size_t m_currentGridIdx; size_t m_currentCellIndex; From e3d76be0aab77c1cac5c33222775e55407933876 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 5 Nov 2015 12:32:29 +0100 Subject: [PATCH 013/290] (#612) Improved user interaction for adding/deleting curves When time hist plot is visible, CTRL + mouse click on a cell adds curve to plot Mouse click outside clears curve plot --- ApplicationCode/UserInterface/RiuViewer.cpp | 2 +- .../UserInterface/RiuViewerCommands.cpp | 75 +++++++++++-------- .../UserInterface/RiuViewerCommands.h | 2 +- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 73d8aa347e..c913390f03 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -225,7 +225,7 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { - m_viewerCommands->handlePickAction(event->x(), event->y()); + m_viewerCommands->handlePickAction(event->x(), event->y(), event->modifiers()); return; } else if (event->button() == Qt::RightButton) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 84592b9c97..f5ede535b6 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -404,9 +404,8 @@ void RiuViewerCommands::slotAddGeoMechPropertyFilter() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) +void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers) { - size_t gridIndex = cvf::UNDEFINED_SIZE_T; size_t cellIndex = cvf::UNDEFINED_SIZE_T; size_t nncIndex = cvf::UNDEFINED_SIZE_T; @@ -474,13 +473,18 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) } - RiuMainWindow* mainWnd = RiuMainWindow::instance(); // Compose a info text regarding the hit QString pickInfo = "No hits"; QString resultInfo = ""; + bool addCurveToTimeHistoryPlot = false; + if (keyboardModifiers & Qt::ControlModifier) + { + addCurveToTimeHistoryPlot = true; + } + if (cellIndex != cvf::UNDEFINED_SIZE_T || nncIndex != cvf::UNDEFINED_SIZE_T) { RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); @@ -497,12 +501,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) pickInfo = textBuilder.topologyText(", "); - if (eclipseView->cellResult()->hasDynamicResult() && - eclipseView->eclipseCase() && - eclipseView->eclipseCase()->reservoirData()) - { - addTimeHistoryCurve(eclipseView, gridIndex, cellIndex); - } + if (addCurveToTimeHistoryPlot) addTimeHistoryCurve(eclipseView, gridIndex, cellIndex); } else if (geomView) { @@ -515,22 +514,24 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) pickInfo = textBuilder.topologyText(", "); - if (geomView->cellResult() && - geomView->cellResult()->hasResult()) - { - addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint); - } + if (addCurveToTimeHistoryPlot) addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint); } } - else + + if (wellPath) { - // Delete all curves if no cell is hit - mainWnd->timeHistoryPlot()->deleteAllCurves(); + pickInfo = QString("Well path hit: %1").arg(wellPath->name()); } - if (wellPath) + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + if (cellIndex == cvf::UNDEFINED_SIZE_T && + !(keyboardModifiers & Qt::ControlModifier)) { - pickInfo = QString("Well path hit: %1").arg(wellPath->name()); + if (mainWnd->timeHistoryPlot()->isVisible()) + { + // Delete all curves if no cell is hit + mainWnd->timeHistoryPlot()->deleteAllCurves(); + } } mainWnd->statusBar()->showMessage(pickInfo); @@ -542,25 +543,33 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY) //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex) { - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + if (!mainWnd->timeHistoryPlot()->isVisible()) return; - std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); + if (eclipseView->cellResult()->hasDynamicResult() && + eclipseView->eclipseCase() && + eclipseView->eclipseCase()->reservoirData()) + { + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); - RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); + std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); - QString curveName = eclipseView->eclipseCase()->caseUserDescription(); - curveName += " - Result : "; - curveName += eclipseView->cellResult()->resultVariable(); - curveName += " - "; - curveName += timeHistResultAccessor.topologyText(); + RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); - std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); + QString curveName = eclipseView->eclipseCase()->caseUserDescription(); + curveName += ", "; + curveName += eclipseView->cellResult()->resultVariable(); + curveName += ", "; + curveName += QString("Grid index %1").arg(gridIndex); + curveName += ", "; + curveName += timeHistResultAccessor.topologyText(); - CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); + std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - RiuMainWindow* mainWnd = RiuMainWindow::instance(); + CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); - mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, timeHistoryValues); + mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, timeHistoryValues); + } } //-------------------------------------------------------------------------------------------------- @@ -568,8 +577,12 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint) { + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + if (!mainWnd->timeHistoryPlot()->isVisible()) return; + if (geoMechView && geoMechView->cellResult() && + geoMechView->cellResult()->hasResult() && geoMechView->geoMechCase() && geoMechView->geoMechCase()->geoMechData()) { diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 2a8de9e20d..3a3dcd44be 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -47,7 +47,7 @@ class RiuViewerCommands: public QObject void setOwnerView(RimView * owner); void displayContextMenu(QMouseEvent* event); - void handlePickAction(int winPosX, int winPosY); + void handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers); private slots: From cef31b2c4ad116e26f173ffe57fc4b82df0f3dc1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 5 Nov 2015 14:12:49 +0100 Subject: [PATCH 014/290] (#612) Make sure time step dates are taken from scalar dataset with highest time step count --- ApplicationCode/UserInterface/RiuViewerCommands.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index f5ede535b6..465681d3d3 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -552,7 +552,9 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t { RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); - std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(eclipseView->cellResult()->scalarResultIndex()); + size_t scalarIndexWithMaxTimeStepCount = cvf::UNDEFINED_SIZE_T; + eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->maxTimeStepCount(&scalarIndexWithMaxTimeStepCount); + std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(scalarIndexWithMaxTimeStepCount); RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); From 3c00a8394d19bf12dd352aa426061978cec38983 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 6 Nov 2015 08:32:58 +0100 Subject: [PATCH 015/290] Refactored and renamed to RuiLineSegmentQwtPlotCurve --- .../ProjectDataModel/RimWellLogCurve.cpp | 4 +-- .../ProjectDataModel/RimWellLogCurve.h | 4 +-- .../RimWellLogExtractionCurve.cpp | 2 +- .../ProjectDataModel/RimWellLogFileCurve.cpp | 2 +- ...rve.cpp => RiuLineSegmentQwtPlotCurve.cpp} | 24 ++++++++++------ ...ogCurve.h => RiuLineSegmentQwtPlotCurve.h} | 28 ++++++++++++++----- 6 files changed, 42 insertions(+), 22 deletions(-) rename ApplicationCode/UserInterface/{RiuWellLogCurve.cpp => RiuLineSegmentQwtPlotCurve.cpp} (70%) rename ApplicationCode/UserInterface/{RiuWellLogCurve.h => RiuLineSegmentQwtPlotCurve.h} (60%) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 144b5021d8..1ff66f5720 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -23,7 +23,7 @@ #include "RimWellLogTrack.h" -#include "RiuWellLogCurve.h" +#include "RiuLineSegmentQwtPlotCurve.h" #include "RiuWellLogTrack.h" #include "cvfAssert.h" @@ -49,7 +49,7 @@ RimWellLogCurve::RimWellLogCurve() CAF_PDM_InitField(&m_curveColor, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", ""); - m_qwtPlotCurve = new RiuWellLogCurve; + m_qwtPlotCurve = new RiuLineSegmentQwtPlotCurve; m_qwtPlotCurve->setXAxis(QwtPlot::xTop); m_qwtPlotCurve->setYAxis(QwtPlot::yLeft); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index cb4780bc34..c7ff0a6e43 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -29,7 +29,7 @@ class RigWellLogCurveData; class RiuWellLogTrack; -class RiuWellLogCurve; +class RiuLineSegmentQwtPlotCurve; class QwtPlotCurve; class QString; @@ -82,7 +82,7 @@ class RimWellLogCurve : public caf::PdmObject QPointer m_ownerQwtTrack; - RiuWellLogCurve* m_qwtPlotCurve; + RiuLineSegmentQwtPlotCurve* m_qwtPlotCurve; cvf::ref m_curveData; caf::PdmField m_showCurve; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 16193b5098..fbca8f08ba 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -46,7 +46,7 @@ #include "RimGeoMechView.h" #include "RimGeoMechCellColors.h" -#include "RiuWellLogCurve.h" +#include "RiuLineSegmentQwtPlotCurve.h" #include "RiuWellLogTrack.h" #include "cafPdmUiTreeOrdering.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index 46aca9455b..ca8abfa5f5 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -29,7 +29,7 @@ #include "RimWellLogPlot.h" #include "RiuWellLogTrack.h" -#include "RiuWellLogCurve.h" +#include "RiuLineSegmentQwtPlotCurve.h" #include "RiaApplication.h" #include "RiaPreferences.h" diff --git a/ApplicationCode/UserInterface/RiuWellLogCurve.cpp b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp similarity index 70% rename from ApplicationCode/UserInterface/RiuWellLogCurve.cpp rename to ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp index a4ec3ea0e2..25ab39b761 100644 --- a/ApplicationCode/UserInterface/RiuWellLogCurve.cpp +++ b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RiuWellLogCurve.h" +#include "RiuLineSegmentQwtPlotCurve.h" #include "RigWellLogCurveData.h" @@ -25,21 +25,21 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogCurve::RiuWellLogCurve() +RiuLineSegmentQwtPlotCurve::RiuLineSegmentQwtPlotCurve() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWellLogCurve::~RiuWellLogCurve() +RiuLineSegmentQwtPlotCurve::~RiuLineSegmentQwtPlotCurve() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogCurve::drawCurve(QPainter* p, int style, +void RiuLineSegmentQwtPlotCurve::drawCurve(QPainter* p, int style, const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QRectF& canvasRect, int from, int to) const { @@ -57,13 +57,19 @@ void RiuWellLogCurve::drawCurve(QPainter* p, int style, //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogCurve::setCurveData(const RigWellLogCurveData* curveData) +void RiuLineSegmentQwtPlotCurve::setCurveData(const RigWellLogCurveData* curveData) { CVF_ASSERT(curveData); - std::vector validXValues = curveData->xPlotValues(); - std::vector validYValues = curveData->depthPlotValues(); + setCurveData(curveData->xPlotValues(), curveData->depthPlotValues(), curveData->polylineStartStopIndices()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuLineSegmentQwtPlotCurve::setCurveData(const std::vector& xValues, const std::vector& yValues, const std::vector< std::pair >& lineSegmentStartStopIndices) +{ + setSamples(xValues.data(), yValues.data(), static_cast(xValues.size())); - setSamples(validXValues.data(), validYValues.data(), (int) validXValues.size()); - m_polyLineStartStopIndices = curveData->polylineStartStopIndices(); + m_polyLineStartStopIndices = lineSegmentStartStopIndices; } diff --git a/ApplicationCode/UserInterface/RiuWellLogCurve.h b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h similarity index 60% rename from ApplicationCode/UserInterface/RiuWellLogCurve.h rename to ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h index e08122864f..dd40ad1de7 100644 --- a/ApplicationCode/UserInterface/RiuWellLogCurve.h +++ b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h @@ -26,20 +26,34 @@ class RigWellLogCurveData; //================================================================================================== -/// -/// +// +// The PlotCurve class is able to draw a curve using line segments. If inf data is present +// in the curve data, Qwt is not able to draw a nice curve. This class assumes that inf data is removed, +// and segments to be draw are indicated by start/stop indices into curve data. +// +// Here you can see the curve segments visualized. Curve segments are drawn between vector indices. +// +// 0 - 1 +// 5 - 7 +// 9 -10 +// +// * * +// / / \ +// Curve * * * *---* +// +// Values 1.0|2.0|inf|inf|inf|1.0|2.0|1.0|inf|1.0|1.0 +// Vec index 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 //================================================================================================== -class RiuWellLogCurve : public QwtPlotCurve +class RiuLineSegmentQwtPlotCurve : public QwtPlotCurve { public: - - RiuWellLogCurve(); - virtual ~RiuWellLogCurve(); + RiuLineSegmentQwtPlotCurve(); + virtual ~RiuLineSegmentQwtPlotCurve(); void setCurveData(const RigWellLogCurveData* curveData); + void setCurveData(const std::vector& xValues, const std::vector& yValues, const std::vector< std::pair >& lineSegmentStartStopIndices); protected: - virtual void drawCurve(QPainter* p, int style, const QwtScaleMap& xMap, const QwtScaleMap& yMap, const QRectF& canvasRect, int from, int to) const; From ab3c5c029abcc8451a9c289bb358b25ea2b9a26b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 6 Nov 2015 10:08:35 +0100 Subject: [PATCH 016/290] Refactored RiuLineSegmnetQwtPlotCurve Removed domain specific code Created RigCurveDataTools Use symbol to draw single values --- ApplicationCode/CMakeLists.txt | 4 +- .../RimWellLogExtractionCurveImpl-Test.cpp | 6 +- .../RimWellLogExtractionCurve.cpp | 4 +- .../ProjectDataModel/RimWellLogFileCurve.cpp | 3 +- .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../ReservoirDataModel/RigCurveDataTools.cpp | 82 +++++++++++++++++ .../ReservoirDataModel/RigCurveDataTools.h | 54 ++++++++++++ .../RigWellLogCurveData.cpp | 88 ++----------------- .../ReservoirDataModel/RigWellLogCurveData.h | 22 ----- .../RiuLineSegmentQwtPlotCurve.cpp | 39 ++++---- .../RiuLineSegmentQwtPlotCurve.h | 26 +++--- .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 26 +++++- 12 files changed, 210 insertions(+), 146 deletions(-) create mode 100644 ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp create mode 100644 ApplicationCode/ReservoirDataModel/RigCurveDataTools.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index a8c4061212..57b5c2d616 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -84,8 +84,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuTreeViewEventFilter.h UserInterface/RiuWellLogPlot.cpp UserInterface/RiuWellLogPlot.h - UserInterface/RiuWellLogCurve.cpp - UserInterface/RiuWellLogCurve.h + UserInterface/RiuLineSegmentQwtPlotCurve.cpp + UserInterface/RiuLineSegmentQwtPlotCurve.h UserInterface/RiuWellLogTrack.cpp UserInterface/RiuWellLogTrack.h UserInterface/RiuProjectPropertyView.h diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp index 1597263404..f38c69b79c 100644 --- a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp +++ b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp @@ -1,6 +1,6 @@ #include "gtest/gtest.h" -#include "RigWellLogCurveData.h" +#include "RigCurveDataTools.h" #include // Needed for HUGE_VAL on Linux @@ -19,7 +19,7 @@ TEST(RimWellLogExtractionCurveImplTest, StripOffInvalidValAtEndsOfVector) values.push_back(HUGE_VAL); std::vector< std::pair > valuesIntervals; - RigWellLogCurveDataTestInterface::calculateIntervalsOfValidValues(values, &valuesIntervals); + RigCurveDataTools::calculateIntervalsOfValidValues(values, &valuesIntervals); EXPECT_EQ(1, static_cast(valuesIntervals.size())); EXPECT_EQ(2, static_cast(valuesIntervals[0].first)); @@ -43,7 +43,7 @@ TEST(RimWellLogExtractionCurveImplTest, StripOffHugeValAtEndsAndInteriorOfVector values.push_back(HUGE_VAL); std::vector< std::pair > valuesIntervals; - RigWellLogCurveDataTestInterface::calculateIntervalsOfValidValues(values, &valuesIntervals); + RigCurveDataTools::calculateIntervalsOfValidValues(values, &valuesIntervals); EXPECT_EQ(2, static_cast(valuesIntervals.size())); EXPECT_EQ(2, static_cast(valuesIntervals[0].first)); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index fbca8f08ba..fc7ffc48cb 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -255,7 +255,9 @@ void RimWellLogExtractionCurve::updatePlotData() } } - m_qwtPlotCurve->setCurveData(m_curveData.p()); + m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues().data(), static_cast(m_curveData->xPlotValues().size())); + m_qwtPlotCurve->setLineSegmentStartStopIndices(m_curveData->polylineStartStopIndices()); + zoomAllOwnerTrackAndPlot(); if (m_ownerQwtTrack) m_ownerQwtTrack->replot(); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index ca8abfa5f5..d7678531f8 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -114,7 +114,8 @@ void RimWellLogFileCurve::updatePlotData() } } - m_qwtPlotCurve->setCurveData(m_curveData.p()); + m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues().data(), static_cast(m_curveData->xPlotValues().size())); + m_qwtPlotCurve->setLineSegmentStartStopIndices(m_curveData->polylineStartStopIndices()); zoomAllOwnerTrackAndPlot(); diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 4fa870d18c..68d64de050 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -38,6 +38,7 @@ ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.h ${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.h +${CEE_CURRENT_LIST_DIR}RigCurveDataTools.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -70,6 +71,7 @@ ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.cpp ${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.cpp +${CEE_CURRENT_LIST_DIR}RigCurveDataTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp new file mode 100644 index 0000000000..b9a856afa4 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.cpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigCurveDataTools.h" + +#include + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCurveDataTools::calculateIntervalsOfValidValues(const std::vector& values, std::vector< std::pair >* intervals) +{ + CVF_ASSERT(intervals); + + int startIdx = -1; + size_t vIdx = 0; + + size_t valueCount = values.size(); + while (vIdx < valueCount) + { + double value = values[vIdx]; + if (value == HUGE_VAL || value == -HUGE_VAL || value != value) + { + if (startIdx >= 0) + { + intervals->push_back(std::make_pair(startIdx, vIdx - 1)); + startIdx = -1; + } + } + else if (startIdx < 0) + { + startIdx = (int)vIdx; + } + + vIdx++; + } + + if (startIdx >= 0 && startIdx < ((int)valueCount)) + { + intervals->push_back(std::make_pair(startIdx, valueCount - 1)); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCurveDataTools::computePolyLineStartStopIndices(const std::vector< std::pair >& intervals, + std::vector< std::pair >* fltrIntervals) +{ + CVF_ASSERT(fltrIntervals); + + const size_t intervalCount = intervals.size(); + if (intervalCount < 1) return; + + size_t index = 0; + for (size_t intIdx = 0; intIdx < intervalCount; intIdx++) + { + size_t intervalSize = intervals[intIdx].second - intervals[intIdx].first + 1; + fltrIntervals->push_back(std::make_pair(index, index + intervalSize - 1)); + + index += intervalSize; + } +} + diff --git a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h new file mode 100644 index 0000000000..deec6c889a --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfAssert.h" + +#include + + +//================================================================================================== +/// +//================================================================================================== +class RigCurveDataTools +{ +public: + static void calculateIntervalsOfValidValues(const std::vector& values, + std::vector< std::pair >* intervals); + + template + static void getValuesByIntervals(const std::vector& values, + const std::vector< std::pair >& intervals, + std::vector* filteredValues) + { + CVF_ASSERT(filteredValues); + + for (size_t intIdx = 0; intIdx < intervals.size(); intIdx++) + { + for (size_t vIdx = intervals[intIdx].first; vIdx <= intervals[intIdx].second; vIdx++) + { + filteredValues->push_back(values[vIdx]); + } + } + } + + static void computePolyLineStartStopIndices(const std::vector< std::pair >& intervals, + std::vector< std::pair >* filteredIntervals); +}; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp index e11cf920a7..79971dbcee 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp @@ -19,6 +19,8 @@ #include "RigWellLogCurveData.h" +#include "RigCurveDataTools.h" + #include "cvfMath.h" #include "cvfAssert.h" @@ -101,7 +103,7 @@ const std::vector& RigWellLogCurveData::measuredDepths() const std::vector RigWellLogCurveData::xPlotValues() const { std::vector filteredValues; - getValuesByIntervals(m_xValues, m_intervalsOfContinousValidValues, &filteredValues); + RigCurveDataTools::getValuesByIntervals(m_xValues, m_intervalsOfContinousValidValues, &filteredValues); return filteredValues; } @@ -114,11 +116,11 @@ std::vector RigWellLogCurveData::depthPlotValues() const std::vector filteredValues; if (m_tvDepths.size()) { - getValuesByIntervals(m_tvDepths, m_intervalsOfContinousValidValues, &filteredValues); + RigCurveDataTools::getValuesByIntervals(m_tvDepths, m_intervalsOfContinousValidValues, &filteredValues); } else { - getValuesByIntervals(m_measuredDepths, m_intervalsOfContinousValidValues, &filteredValues); + RigCurveDataTools::getValuesByIntervals(m_measuredDepths, m_intervalsOfContinousValidValues, &filteredValues); } return filteredValues; @@ -130,7 +132,7 @@ std::vector RigWellLogCurveData::depthPlotValues() const std::vector< std::pair > RigWellLogCurveData::polylineStartStopIndices() const { std::vector< std::pair > lineStartStopIndices; - computePolyLineStartStopIndices(m_intervalsOfContinousValidValues, &lineStartStopIndices); + RigCurveDataTools::computePolyLineStartStopIndices(m_intervalsOfContinousValidValues, &lineStartStopIndices); return lineStartStopIndices; } @@ -142,7 +144,7 @@ std::vector< std::pair > RigWellLogCurveData::polylineStartStopI void RigWellLogCurveData::calculateIntervalsOfContinousValidValues() { std::vector< std::pair > intervalsOfValidValues; - calculateIntervalsOfValidValues(m_xValues, &intervalsOfValidValues); + RigCurveDataTools::calculateIntervalsOfValidValues(m_xValues, &intervalsOfValidValues); m_intervalsOfContinousValidValues.clear(); @@ -168,42 +170,6 @@ void RigWellLogCurveData::calculateIntervalsOfContinousValidValues() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigWellLogCurveData::calculateIntervalsOfValidValues(const std::vector& values, std::vector< std::pair >* intervals) -{ - CVF_ASSERT(intervals); - - int startIdx = -1; - size_t vIdx = 0; - - size_t valueCount = values.size(); - while (vIdx < valueCount) - { - double value = values[vIdx]; - if (value == HUGE_VAL || value == -HUGE_VAL || value != value) - { - if (startIdx >= 0) - { - intervals->push_back(std::make_pair(startIdx, vIdx - 1)); - startIdx = -1; - } - } - else if (startIdx < 0) - { - startIdx = (int)vIdx; - } - - vIdx++; - } - - if (startIdx >= 0 && startIdx < ((int)valueCount)) - { - intervals->push_back(std::make_pair(startIdx, valueCount - 1)); - } -} - //-------------------------------------------------------------------------------------------------- /// Splits the start stop interval between cells that are not close enough. /// The depth values are expected to contain pair of depths: Depth at cell enter, and cell leave @@ -242,46 +208,6 @@ void RigWellLogCurveData::splitIntervalAtEmptySpace(const std::vector& d } } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigWellLogCurveData::getValuesByIntervals(const std::vector& values, - const std::vector< std::pair >& intervals, - std::vector* filteredValues) -{ - CVF_ASSERT(filteredValues); - - for (size_t intIdx = 0; intIdx < intervals.size(); intIdx++) - { - for (size_t vIdx = intervals[intIdx].first; vIdx <= intervals[intIdx].second; vIdx++) - { - filteredValues->push_back(values[vIdx]); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigWellLogCurveData::computePolyLineStartStopIndices(const std::vector< std::pair >& intervals, - std::vector< std::pair >* fltrIntervals) -{ - CVF_ASSERT(fltrIntervals); - - const size_t intervalCount = intervals.size(); - if (intervalCount < 1) return; - - size_t index = 0; - for (size_t intIdx = 0; intIdx < intervalCount; intIdx++) - { - size_t intervalSize = intervals[intIdx].second - intervals[intIdx].first + 1; - fltrIntervals->push_back(std::make_pair(index, index + intervalSize - 1)); - - index += intervalSize; - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h index a5025ec98b..6ce38c8026 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h @@ -53,18 +53,9 @@ class RigWellLogCurveData : public cvf::Object private: void calculateIntervalsOfContinousValidValues(); - static void calculateIntervalsOfValidValues(const std::vector& values, - std::vector< std::pair >* intervals); static void splitIntervalAtEmptySpace(const std::vector& depthValues, size_t startIdx, size_t stopIdx, std::vector< std::pair >* intervals); - - static void getValuesByIntervals(const std::vector& values, - const std::vector< std::pair >& intervals, - std::vector* filteredValues); - static void computePolyLineStartStopIndices(const std::vector< std::pair >& intervals, - std::vector< std::pair >* filteredIntervals); - private: std::vector m_xValues; std::vector m_measuredDepths; @@ -72,18 +63,5 @@ class RigWellLogCurveData : public cvf::Object bool m_isExtractionCurve; std::vector< std::pair > m_intervalsOfContinousValidValues; - - friend class RigWellLogCurveDataTestInterface; }; -//================================================================================================== -/// -//================================================================================================== -class RigWellLogCurveDataTestInterface -{ -public: - static void calculateIntervalsOfValidValues(const std::vector& values, std::vector< std::pair >* intervals) - { - RigWellLogCurveData::calculateIntervalsOfValidValues(values, intervals); - } -}; diff --git a/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp index 25ab39b761..2716093d55 100644 --- a/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.cpp @@ -19,13 +19,14 @@ #include "RiuLineSegmentQwtPlotCurve.h" -#include "RigWellLogCurveData.h" +#include "qwt_symbol.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuLineSegmentQwtPlotCurve::RiuLineSegmentQwtPlotCurve() +RiuLineSegmentQwtPlotCurve::RiuLineSegmentQwtPlotCurve(const QString &title) + : QwtPlotCurve(title) { } @@ -48,28 +49,32 @@ void RiuLineSegmentQwtPlotCurve::drawCurve(QPainter* p, int style, { for (size_t intIdx = 0; intIdx < intervalCount; intIdx++) { - QwtPlotCurve::drawCurve(p, style, xMap, yMap, canvasRect, (int) m_polyLineStartStopIndices[intIdx].first, (int) m_polyLineStartStopIndices[intIdx].second); + if (m_polyLineStartStopIndices[intIdx].first == m_polyLineStartStopIndices[intIdx].second) + { + // Use a symbol to draw a single value, as a single value will not be visible + // when using QwtPlotCurve::drawCurve without symbols activated + + QwtSymbol symbol(QwtSymbol::XCross); + symbol.setSize(10, 10); + + QwtPlotCurve::drawSymbols(p, symbol, xMap, yMap, canvasRect, (int) m_polyLineStartStopIndices[intIdx].first, (int) m_polyLineStartStopIndices[intIdx].second); + } + else + { + QwtPlotCurve::drawCurve(p, style, xMap, yMap, canvasRect, (int) m_polyLineStartStopIndices[intIdx].first, (int) m_polyLineStartStopIndices[intIdx].second); + } } } - else QwtPlotCurve::drawCurve(p, style, xMap, yMap, canvasRect, from, to); + else + { + QwtPlotCurve::drawCurve(p, style, xMap, yMap, canvasRect, from, to); + } }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuLineSegmentQwtPlotCurve::setCurveData(const RigWellLogCurveData* curveData) -{ - CVF_ASSERT(curveData); - - setCurveData(curveData->xPlotValues(), curveData->depthPlotValues(), curveData->polylineStartStopIndices()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuLineSegmentQwtPlotCurve::setCurveData(const std::vector& xValues, const std::vector& yValues, const std::vector< std::pair >& lineSegmentStartStopIndices) +void RiuLineSegmentQwtPlotCurve::setLineSegmentStartStopIndices(const std::vector< std::pair >& lineSegmentStartStopIndices) { - setSamples(xValues.data(), yValues.data(), static_cast(xValues.size())); - m_polyLineStartStopIndices = lineSegmentStartStopIndices; } diff --git a/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h index dd40ad1de7..084eb376d9 100644 --- a/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h +++ b/ApplicationCode/UserInterface/RiuLineSegmentQwtPlotCurve.h @@ -21,15 +21,12 @@ #include "qwt_plot_curve.h" -#include - -class RigWellLogCurveData; - //================================================================================================== // -// The PlotCurve class is able to draw a curve using line segments. If inf data is present -// in the curve data, Qwt is not able to draw a nice curve. This class assumes that inf data is removed, -// and segments to be draw are indicated by start/stop indices into curve data. +// If infinite data is present in the curve data, Qwt is not able to draw a nice curve. +// This class assumes that inf data is removed, and segments to be draw are indicated by start/stop indices into curve data. +// +// Single values in the curve are drawn using a CrossX symbol // // Here you can see the curve segments visualized. Curve segments are drawn between vector indices. // @@ -37,21 +34,20 @@ class RigWellLogCurveData; // 5 - 7 // 9 -10 // -// * * +// / ^ // / / \ -// Curve * * * *---* +// Curve / / \ ----- X // -// Values 1.0|2.0|inf|inf|inf|1.0|2.0|1.0|inf|1.0|1.0 -// Vec index 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 +// Values 1.0|2.0|inf|inf|inf|1.0|2.0|1.0|inf|1.0|1.0|inf|1.0|inf +// Vec index 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13 //================================================================================================== class RiuLineSegmentQwtPlotCurve : public QwtPlotCurve { public: - RiuLineSegmentQwtPlotCurve(); + explicit RiuLineSegmentQwtPlotCurve(const QString &title = QString::null); virtual ~RiuLineSegmentQwtPlotCurve(); - void setCurveData(const RigWellLogCurveData* curveData); - void setCurveData(const std::vector& xValues, const std::vector& yValues, const std::vector< std::pair >& lineSegmentStartStopIndices); + void setLineSegmentStartStopIndices(const std::vector< std::pair >& lineSegmentStartStopIndices); protected: virtual void drawCurve(QPainter* p, int style, @@ -59,5 +55,5 @@ class RiuLineSegmentQwtPlotCurve : public QwtPlotCurve const QRectF& canvasRect, int from, int to) const; private: - std::vector< std::pair > m_polyLineStartStopIndices; + std::vector< std::pair > m_polyLineStartStopIndices; }; diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index d0f8f285fc..8c3551f3ad 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -19,8 +19,12 @@ #include "RiuTimeHistoryQwtPlot.h" +#include "RigCurveDataTools.h" + #include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" +#include "RiuLineSegmentQwtPlotCurve.h" + #include "cvfAssert.h" #include "cvfColor3.h" @@ -31,6 +35,7 @@ #include "qwt_date_scale_draw.h" #include "qwt_date_scale_engine.h" + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -55,16 +60,29 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector { CVF_ASSERT(dateTimes.size() == timeHistoryValues.size()); - QwtPlotCurve* plotCurve = new QwtPlotCurve("Curve 1"); + std::vector< std::pair > intervalsOfValidValues; + RigCurveDataTools::calculateIntervalsOfValidValues(timeHistoryValues, &intervalsOfValidValues); + + std::vector filteredTimeHistoryValues; + RigCurveDataTools::getValuesByIntervals(timeHistoryValues, intervalsOfValidValues, &filteredTimeHistoryValues); + + std::vector filteredDateTimes; + RigCurveDataTools::getValuesByIntervals(dateTimes, intervalsOfValidValues, &filteredDateTimes); + + std::vector< std::pair > filteredIntervals; + RigCurveDataTools::computePolyLineStartStopIndices(intervalsOfValidValues, &filteredIntervals); + + RiuLineSegmentQwtPlotCurve* plotCurve = new RiuLineSegmentQwtPlotCurve("Curve 1"); QPolygonF points; - for (int i = 0; i < dateTimes.size(); i++) + for (int i = 0; i < filteredDateTimes.size(); i++) { - double milliSecSinceEpoch = QwtDate::toDouble(dateTimes[i]); - points << QPointF(milliSecSinceEpoch, timeHistoryValues[i]); + double milliSecSinceEpoch = QwtDate::toDouble(filteredDateTimes[i]); + points << QPointF(milliSecSinceEpoch, filteredTimeHistoryValues[i]); } plotCurve->setSamples(points); + plotCurve->setLineSegmentStartStopIndices(filteredIntervals); plotCurve->setTitle(curveName); cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); From 2adb9279cec715dd100a3a89743100f41f751077 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 6 Nov 2015 10:19:18 +0100 Subject: [PATCH 017/290] (#612) Added grid to QwtPlot --- .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 33 +++++++++++++------ .../UserInterface/RiuTimeHistoryQwtPlot.h | 4 ++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index 8c3551f3ad..09fe3bd589 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -28,12 +28,13 @@ #include "cvfAssert.h" #include "cvfColor3.h" +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" #include "qwt_legend.h" #include "qwt_plot_curve.h" +#include "qwt_plot_grid.h" #include "qwt_plot_layout.h" #include "qwt_scale_engine.h" -#include "qwt_date_scale_draw.h" -#include "qwt_date_scale_engine.h" //-------------------------------------------------------------------------------------------------- @@ -42,6 +43,9 @@ RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) : QwtPlot(parent) { + m_grid = new QwtPlotGrid; + m_grid->attach(this); + setDefaults(); } @@ -51,6 +55,9 @@ RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() { deleteAllCurves(); + + m_grid->detach(); + delete m_grid; } //-------------------------------------------------------------------------------------------------- @@ -60,17 +67,19 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector { CVF_ASSERT(dateTimes.size() == timeHistoryValues.size()); - std::vector< std::pair > intervalsOfValidValues; - RigCurveDataTools::calculateIntervalsOfValidValues(timeHistoryValues, &intervalsOfValidValues); - std::vector filteredTimeHistoryValues; - RigCurveDataTools::getValuesByIntervals(timeHistoryValues, intervalsOfValidValues, &filteredTimeHistoryValues); - std::vector filteredDateTimes; - RigCurveDataTools::getValuesByIntervals(dateTimes, intervalsOfValidValues, &filteredDateTimes); - std::vector< std::pair > filteredIntervals; - RigCurveDataTools::computePolyLineStartStopIndices(intervalsOfValidValues, &filteredIntervals); + + { + std::vector< std::pair > intervalsOfValidValues; + RigCurveDataTools::calculateIntervalsOfValidValues(timeHistoryValues, &intervalsOfValidValues); + + RigCurveDataTools::getValuesByIntervals(timeHistoryValues, intervalsOfValidValues, &filteredTimeHistoryValues); + RigCurveDataTools::getValuesByIntervals(dateTimes, intervalsOfValidValues, &filteredDateTimes); + + RigCurveDataTools::computePolyLineStartStopIndices(intervalsOfValidValues, &filteredIntervals); + } RiuLineSegmentQwtPlotCurve* plotCurve = new RiuLineSegmentQwtPlotCurve("Curve 1"); @@ -146,6 +155,10 @@ void RiuTimeHistoryQwtPlot::setDefaults() canvas()->setMouseTracking(true); canvas()->installEventFilter(this); + QPen gridPen(Qt::SolidLine); + gridPen.setColor(Qt::lightGray); + m_grid->setPen(gridPen); + enableAxis(QwtPlot::xBottom, true); enableAxis(QwtPlot::yLeft, true); enableAxis(QwtPlot::xTop, false); diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h index 1caff45db1..6f39124dc5 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -22,6 +22,7 @@ #include "qwt_plot.h" class QwtPlotCurve; +class QwtPlotGrid; //================================================================================================== // @@ -43,6 +44,7 @@ class RiuTimeHistoryQwtPlot : public QwtPlot void setDefaults(); private: - std::vector m_plotCurves; + std::vector m_plotCurves; + QwtPlotGrid* m_grid; }; From 0bd4f4a8f94b310bb9119aa33e1e6ec9533af4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 6 Nov 2015 10:18:55 +0100 Subject: [PATCH 018/290] (#606) (#607) Calculate visible cells statistics for geomech Refactored some in 3D info regarding geomech cases. --- .../GeoMech/GeoMechDataModel/CMakeLists.txt | 2 + .../GeoMechDataModel/RigFemNativeStatCalc.cpp | 8 +- .../RigFemNativeVisibleCellsStatCalc.cpp | 166 +++++++++++++ .../RigFemNativeVisibleCellsStatCalc.h | 106 +++++++++ .../RigFemPartResultsCollection.cpp | 8 + .../RigFemPartResultsCollection.h | 3 +- .../Rim3dOverlayInfoConfig.cpp | 224 +++++++++++------- .../ProjectDataModel/Rim3dOverlayInfoConfig.h | 3 + .../RigStatisticsDataCache.cpp | 62 ++--- .../RigStatisticsMath.cpp | 53 ++--- .../ResultStatisticsCache/RigStatisticsMath.h | 4 +- 11 files changed, 487 insertions(+), 152 deletions(-) create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp create mode 100644 ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt index 530de2fb36..c18640672a 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt +++ b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt @@ -27,6 +27,8 @@ add_library( ${PROJECT_NAME} RigFemScalarResultFrames.cpp RigFemNativeStatCalc.h RigFemNativeStatCalc.cpp + RigFemNativeVisibleCellsStatCalc.h + RigFemNativeVisibleCellsStatCalc.cpp RigFemFaceComparator.h RigFemPartGrid.h RigFemPartGrid.cpp diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp index 5642863662..ffca823228 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.cpp @@ -38,7 +38,7 @@ RigFemNativeStatCalc::RigFemNativeStatCalc(RigFemPartResultsCollection* femResul //-------------------------------------------------------------------------------------------------- void RigFemNativeStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) { - for (int pIdx = 0; pIdx < static_cast(m_resultsData->m_femPartResults.size()); ++pIdx) + for (int pIdx = 0; pIdx < m_resultsData->partCount(); ++pIdx) { const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, (int)timeStepIndex); @@ -68,7 +68,7 @@ void RigFemNativeStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& //-------------------------------------------------------------------------------------------------- void RigFemNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) { - for (int pIdx = 0; pIdx < static_cast(m_resultsData->m_femPartResults.size()); ++pIdx) + for (int pIdx = 0; pIdx < m_resultsData->partCount(); ++pIdx) { const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, (int)timeStepIndex); @@ -99,7 +99,7 @@ void RigFemNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos void RigFemNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) { int tsIdx = static_cast(timeStepIndex); - int partCount = static_cast(m_resultsData->m_femPartResults.size()); + int partCount = m_resultsData->partCount(); for (int pIdx = 0; pIdx < partCount; ++pIdx) { @@ -128,7 +128,7 @@ void RigFemNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& //-------------------------------------------------------------------------------------------------- void RigFemNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) { - int partCount = static_cast(m_resultsData->m_femPartResults.size()); + int partCount = m_resultsData->partCount(); for (int pIdx = 0; pIdx < partCount; ++pIdx) { const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, static_cast(timeStepIndex)); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp new file mode 100644 index 0000000000..cc7ed6b31c --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp @@ -0,0 +1,166 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RigFemNativeVisibleCellsStatCalc.h" +#include "RigFemScalarResultFrames.h" +#include "RigFemPartResultsCollection.h" + +#include +#include "RigStatisticsMath.h" +#include "RigGeoMechCaseData.h" +#include "RigFemPartCollection.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFemNativeVisibleCellsStatCalc::RigFemNativeVisibleCellsStatCalc(RigGeoMechCaseData* femCase, + const RigFemResultAddress& resVarAddr, + const cvf::UByteArray* cellVisibilities) +: m_caseData(femCase), m_resVarAddr(resVarAddr), m_cellVisibilities(cellVisibilities) +{ + m_resultsData = femCase->femPartResults(); +} + +class MinMaxAccumulator +{ +public: + MinMaxAccumulator(double initMin, double initMax): max(initMax), min(initMin) {} + void addValue(double value) + { + if (value == HUGE_VAL) // TODO + { + return; + } + + if (value < min) + { + min = value; + } + + if (value > max) + { + max = value; + } + } + + double max; + double min; +}; + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemNativeVisibleCellsStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +{ + MinMaxAccumulator acc(min, max); + traverseElementNodes(acc, timeStepIndex); + min = acc.min; + max = acc.max; +} + + +class PosNegAccumulator +{ +public: + PosNegAccumulator(double initPos, double initNeg): pos(initPos), neg(initNeg) {} + void addValue(double value) + { + if (value == HUGE_VAL) + { + return; + } + + if (value < pos && value > 0) + { + pos = value; + } + + if (value > neg && value < 0) + { + neg = value; + } + } + + double pos; + double neg; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemNativeVisibleCellsStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +{ + PosNegAccumulator acc(pos, neg); + traverseElementNodes(acc, timeStepIndex); + pos = acc.pos; + neg = acc.neg; + +} + +class SumCountAccumulator +{ +public: + SumCountAccumulator(double initSum, size_t initCount): valueSum(initSum), sampleCount(initCount) {} + + void addValue(double value) + { + if (value == HUGE_VAL || value != value) + { + return; + } + + valueSum += value; + ++sampleCount; + } + + double valueSum; + size_t sampleCount; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemNativeVisibleCellsStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +{ + SumCountAccumulator acc(valueSum, sampleCount); + traverseElementNodes(acc, timeStepIndex); + valueSum = acc.valueSum; + sampleCount = acc.sampleCount; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemNativeVisibleCellsStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +{ + traverseElementNodes(histogramCalculator, timeStepIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigFemNativeVisibleCellsStatCalc::timeStepCount() +{ + return m_resultsData->frameCount(); +} + + diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h new file mode 100644 index 0000000000..cc2eb0b342 --- /dev/null +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h @@ -0,0 +1,106 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + + +//================================================================================================== +/// +//================================================================================================== +#include "RigStatisticsCalculator.h" +#include "RigFemResultAddress.h" +#include "cvfArray.h" + +class RigGeoMechCaseData; +class RigFemPartResultsCollection; + + +class RigFemNativeVisibleCellsStatCalc : public RigStatisticsCalculator +{ +public: + RigFemNativeVisibleCellsStatCalc(RigGeoMechCaseData* femCase, + const RigFemResultAddress& resVarAddr, + const cvf::UByteArray* cellVisibilities); + + virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); + virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual size_t timeStepCount(); + +private: + RigGeoMechCaseData* m_caseData; + RigFemPartResultsCollection* m_resultsData; + RigFemResultAddress m_resVarAddr; + cvf::cref m_cellVisibilities; + + template + void traverseElementNodes(StatisticsAccumulator& accumulator, size_t timeStepIndex) + { + int partCount = m_caseData->femParts()->partCount(); + + if (m_resVarAddr.resultPosType == RIG_NODAL) + { + for (int pIdx = 0; pIdx < partCount; ++pIdx) + { + RigFemPart* part = m_caseData->femParts()->part(pIdx); + const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, (int)timeStepIndex); + int elmCount = part->elementCount(); + + for (int elmIdx = 0; elmIdx < elmCount; ++elmIdx) + { + if (!(*m_cellVisibilities)[elmIdx]) continue; + + int elmNodeCount = RigFemTypes::elmentNodeCount(part->elementType(elmIdx)); + for (int elmLocIdx = 0; elmLocIdx < elmNodeCount; ++elmLocIdx) + { + size_t elmNodeResIdx = part->elementNodeResultIdx(elmIdx, elmLocIdx); + int nodeIdx = part->nodeIdxFromElementNodeResultIdx(elmNodeResIdx); + accumulator.addValue(values[nodeIdx]); + } + } + } + } + else + { + for (int pIdx = 0; pIdx < partCount; ++pIdx) + { + RigFemPart* part = m_caseData->femParts()->part(pIdx); + const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, (int)timeStepIndex); + int elmCount = part->elementCount(); + + for (int elmIdx = 0; elmIdx < elmCount; ++elmIdx) + { + if (!(*m_cellVisibilities)[elmIdx]) continue; + + int elmNodeCount = RigFemTypes::elmentNodeCount(part->elementType(elmIdx)); + for (int elmLocIdx = 0; elmLocIdx < elmNodeCount; ++elmLocIdx) + { + size_t elmNodeResIdx = part->elementNodeResultIdx(elmIdx, elmLocIdx); + accumulator.addValue(values[elmNodeResIdx]); + } + } + } + } + } + +}; + + + diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp index 493f626c54..763ad3626a 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp @@ -821,3 +821,11 @@ const std::vector& RigFemPartResultsCollection::scalarValuesHistogram(co return this->statistics(resVarAddr)->cellScalarValuesHistogram(frameIndex); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RigFemPartResultsCollection::partCount() const +{ + return m_femParts->partCount(); +} + diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h index 8980de73c3..fe02ace9d8 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h @@ -43,7 +43,7 @@ class RigFemPartResultsCollection: public cvf::Object std::vector stepNames(); bool assertResultsLoaded(const RigFemResultAddress& resVarAddr); const std::vector& resultValues(const RigFemResultAddress& resVarAddr, int partIndex, int frameIndex); - + int partCount() const; int frameCount(); @@ -67,7 +67,6 @@ class RigFemPartResultsCollection: public cvf::Object RigFemScalarResultFrames* calculateBarConvertedResult(int partIndex, const RigFemResultAddress &convertedResultAddr, const std::string fieldNameToConvert); RigFemScalarResultFrames* calculateEnIpPorBarResult(int partIndex, const RigFemResultAddress &convertedResultAddr); - friend class RigFemNativeStatCalc; cvf::Collection m_femPartResults; cvf::ref m_readerInterface; cvf::cref m_femParts; diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index a22a6bf821..95e21c2632 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -42,6 +42,7 @@ #include "RigFemPartResultsCollection.h" #include "RigStatisticsDataCache.h" +#include "RigFemNativeVisibleCellsStatCalc.h" CAF_PDM_SOURCE_INIT(Rim3dOverlayInfoConfig, "View3dOverlayInfoConfig"); //-------------------------------------------------------------------------------------------------- @@ -89,7 +90,7 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsCellRange, "StatisticsCellRange", "Statistics Cell Range", "", "", ""); - m_statisticsCellRange.uiCapability()->setUiHidden(true); + //m_statisticsCellRange.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -143,6 +144,8 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_viewDef->viewer()->showInfoText(showInfoText()); m_viewDef->viewer()->showHistogram(false); m_viewDef->viewer()->showAnimationProgress(showAnimProgress()); + + m_isVisCellStatUpToDate = false; RimEclipseView * reservoirView = dynamic_cast(m_viewDef.p()); if (reservoirView) updateEclipse3DInfo(reservoirView); @@ -217,7 +220,8 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) { infoText += QString("Cell Property: %1 ").arg(propName); - // Wait until regression tests confirm new statisticks is ok infoText += QString("
Statistics for: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); + // Wait until regression tests confirm new statisticks is ok : + //infoText += QString("
Statistics for: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); if (m_statisticsCellRange == ALL_CELLS) { @@ -349,12 +353,74 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) { + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : NULL; + bool isResultsInfoRelevant = caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResult()->hasResult(); + + // Retreive result stats if needed + + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; + const std::vector* histogram = NULL; + + if (showInfoText() || showHistogram()) + { + if (isResultsInfoRelevant) + { + RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); + if (m_statisticsCellRange == ALL_CELLS) + { + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + caseData->femPartResults()->meanScalarValue(resAddress, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress, &min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); + + histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress)); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int timeStepIdx = geoMechView->currentTimeStep(); + caseData->femPartResults()->meanScalarValue(resAddress, timeStepIdx, &mean); + caseData->femPartResults()->minMaxScalarValues(resAddress, timeStepIdx, &min, &max); + caseData->femPartResults()->p10p90ScalarValues(resAddress, timeStepIdx, &p10, &p90); + + histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress, timeStepIdx)); + } + } + else if (m_statisticsCellRange == VISIBLE_CELLS) + { + this->updateVisCellStatsIfNeeded(); + + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + // TODO: Only valid if we have no dynamic property filter + m_visibleCellStatistics->meanCellScalarValues(mean); + m_visibleCellStatistics->minMaxCellScalarValues(min, max); + m_visibleCellStatistics->p10p90CellScalarValues(p10, p90); + + histogram = &(m_visibleCellStatistics->cellScalarValuesHistogram()); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int timeStepIdx = geoMechView->currentTimeStep(); + m_visibleCellStatistics->meanCellScalarValues(timeStepIdx, mean); + m_visibleCellStatistics->minMaxCellScalarValues(timeStepIdx, min, max); + m_visibleCellStatistics->p10p90CellScalarValues(timeStepIdx, p10, p90); + + histogram = &(m_visibleCellStatistics->cellScalarValuesHistogram(timeStepIdx)); + } + } + } + } + + // Compose text + if (showInfoText()) { QString infoText; - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : NULL; RigFemPartCollection* femParts = caseData ? caseData->femParts() : NULL; if (femParts) @@ -362,121 +428,101 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) QString caseName = geoMechCase->caseUserDescription(); QString cellCount = QString("%1").arg(femParts->totalElementCount()); QString zScale = QString::number(geoMechView->scaleZ()); - + infoText = QString( - "

-- %1 --

" - "Cell count: %2 Z-Scale: %3
").arg(caseName, cellCount, zScale); + "

-- %1 --

" + "Cell count: %2 Z-Scale: %3
").arg(caseName, cellCount, zScale); + } - if (geoMechView->hasUserRequestedAnimation() && geoMechView->cellResult()->hasResult()) + if (isResultsInfoRelevant) + { { QString resultPos; QString fieldName = geoMechView->cellResult()->resultFieldUiName(); QString compName = geoMechView->cellResult()->resultComponentUiName(); - if (!fieldName.isEmpty()) + switch (geoMechView->cellResult()->resultPositionType()) { - switch (geoMechView->cellResult()->resultPositionType()) - { - case RIG_NODAL: - resultPos = "Nodal"; - break; + case RIG_NODAL: + resultPos = "Nodal"; + break; - case RIG_ELEMENT_NODAL: - resultPos = "Element nodal"; - break; - - case RIG_INTEGRATION_POINT: - resultPos = "Integration point"; - break; - - default: - break; - } + case RIG_ELEMENT_NODAL: + resultPos = "Element nodal"; + break; - infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); + case RIG_INTEGRATION_POINT: + resultPos = "Integration point"; + break; - double min = HUGE_VAL, max = HUGE_VAL; - double p10 = HUGE_VAL, p90 = HUGE_VAL; - double mean = HUGE_VAL; + default: + break; + } - RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); + infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); + } + { - if (m_statisticsTimeRange == ALL_TIMESTEPS) - { - caseData->femPartResults()->meanScalarValue (resAddress, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress,&min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); - } - else if (m_statisticsTimeRange == CURRENT_TIMESTEP) - { - int timeStepIdx = geoMechView->currentTimeStep(); - caseData->femPartResults()->meanScalarValue (resAddress, timeStepIdx, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress, timeStepIdx, &min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, timeStepIdx, &p10, &p90); - } + infoText += QString("

Min P10 Mean P90 Max
" + "" + "" + "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - infoText += QString("" - "" - "" - "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - } - else - { - infoText += QString("
"); - } + } + { int currentTimeStep = geoMechView->currentTimeStep(); QString stepName = QString::fromStdString(caseData->femPartResults()->stepNames()[currentTimeStep]); infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(stepName); } } + geoMechView->viewer()->setInfoText(infoText); } + // Populate histogram + if (showHistogram()) { - if (geoMechView->hasUserRequestedAnimation() && geoMechView->cellResult()->hasResult()) + if (isResultsInfoRelevant) { geoMechView->viewer()->showHistogram(true); + geoMechView->viewer()->setHistogram(min, max, *histogram); + geoMechView->viewer()->setHistogramPercentiles(p10, p90, mean); + } + } +} - // ToDo: Implement statistics for geomech data - - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : NULL; - - if (caseData) - { - double min = HUGE_VAL, max = HUGE_VAL; - double p10 = HUGE_VAL, p90 = HUGE_VAL; - double mean = HUGE_VAL; - const std::vector* histogram = NULL; - - RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); - - if (m_statisticsTimeRange == ALL_TIMESTEPS) - { - caseData->femPartResults()->meanScalarValue(resAddress, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress, &min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, &p10, &p90); - histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress)); - } - else if (m_statisticsTimeRange == CURRENT_TIMESTEP) - { - int timeStepIdx = geoMechView->currentTimeStep(); - caseData->femPartResults()->meanScalarValue(resAddress, timeStepIdx, &mean); - caseData->femPartResults()->minMaxScalarValues(resAddress, timeStepIdx, &min, &max); - caseData->femPartResults()->p10p90ScalarValues(resAddress, timeStepIdx, &p10, &p90); - histogram = &(caseData->femPartResults()->scalarValuesHistogram(resAddress, timeStepIdx)); - } - else - { - CVF_ASSERT(false); - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() +{ + RimEclipseView * eclipseView = dynamic_cast(m_viewDef.p()); + RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); - geoMechView->viewer()->setHistogram(min, max, *histogram); - geoMechView->viewer()->setHistogramPercentiles(p10, p90, mean); - } + if (!m_isVisCellStatUpToDate) + { + cvf::ref calc; + if (geoMechView) + { + RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); + calc = new RigFemNativeVisibleCellsStatCalc(geoMechView->geoMechCase()->geoMechData(), + resAddress, + geoMechView->currentTotalCellVisibility().p()); + m_visibleCellStatistics = new RigStatisticsDataCache(calc.p()); + m_isVisCellStatUpToDate = true; } + else if (eclipseView) + { + // RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); + // cvf::ref calc = new RigEclipseNativeVisibleCellsStatCalc(geoMechView->geoMechCase()->geoMechData(), + // resAddress, + // geoMechView->currentTotalCellVisibility().p()); + } + + m_visibleCellStatistics = new RigStatisticsDataCache(calc.p()); + m_isVisCellStatUpToDate = true; } } diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h index 4391f3c393..ef291904e4 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h @@ -81,6 +81,9 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject cvf::Vec2ui m_position; + void updateVisCellStatsIfNeeded(); + + bool m_isVisCellStatUpToDate; cvf::ref m_visibleCellStatistics; }; diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp index dff04de95e..774278f324 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp @@ -31,6 +31,8 @@ RigStatisticsDataCache::RigStatisticsDataCache(RigStatisticsCalculator* statisticsCalculator) : m_statisticsCalculator(statisticsCalculator) { + CVF_ASSERT(m_statisticsCalculator.notNull()); + clearAllStatistics(); } @@ -153,75 +155,81 @@ void RigStatisticsDataCache::posNegClosestToZero(size_t timeStepIndex, double& p posNearZero = m_statsPrTs[timeStepIndex].m_posClosestToZero; negNearZero = m_statsPrTs[timeStepIndex].m_negClosestToZero; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram() +void RigStatisticsDataCache::meanCellScalarValues(double& meanValue) { - computeHistogramStatisticsIfNeeded(); + if (!m_statsAllTimesteps.m_isMeanCalculated) + { + m_statisticsCalculator->meanCellScalarValue(m_statsAllTimesteps.m_meanValue); - return m_statsAllTimesteps.m_histogram; + m_statsAllTimesteps.m_isMeanCalculated = true; + } + + meanValue = m_statsAllTimesteps.m_meanValue; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram(size_t timeStepIndex) +void RigStatisticsDataCache::meanCellScalarValues(size_t timeStepIndex, double& meanValue) { - computeHistogramStatisticsIfNeeded(timeStepIndex); + if (timeStepIndex >= m_statsPrTs.size()) + { + m_statsPrTs.resize(timeStepIndex + 1); + } - return m_statsPrTs[timeStepIndex].m_histogram; + if (!m_statsPrTs[timeStepIndex].m_isMeanCalculated) + { + m_statisticsCalculator->meanCellScalarValue(timeStepIndex, m_statsPrTs[timeStepIndex].m_meanValue); + m_statsPrTs[timeStepIndex].m_isMeanCalculated = true; + } + + meanValue = m_statsPrTs[timeStepIndex].m_meanValue; } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigStatisticsDataCache::p10p90CellScalarValues(double& p10, double& p90) +const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram() { computeHistogramStatisticsIfNeeded(); - p10 = m_statsAllTimesteps.m_p10; - p90 = m_statsAllTimesteps.m_p90; + return m_statsAllTimesteps.m_histogram; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigStatisticsDataCache::p10p90CellScalarValues(size_t timeStepIndex, double& p10, double& p90) +const std::vector& RigStatisticsDataCache::cellScalarValuesHistogram(size_t timeStepIndex) { computeHistogramStatisticsIfNeeded(timeStepIndex); - p10 = m_statsPrTs[timeStepIndex].m_p10; - p90 = m_statsPrTs[timeStepIndex].m_p90; + return m_statsPrTs[timeStepIndex].m_histogram; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigStatisticsDataCache::meanCellScalarValues(double& meanValue) +void RigStatisticsDataCache::p10p90CellScalarValues(double& p10, double& p90) { - if (!m_statsAllTimesteps.m_isMeanCalculated) - { - m_statisticsCalculator->meanCellScalarValue(m_statsAllTimesteps.m_meanValue); - m_statsAllTimesteps.m_isMeanCalculated = true; - } + computeHistogramStatisticsIfNeeded(); - meanValue = m_statsAllTimesteps.m_meanValue; + p10 = m_statsAllTimesteps.m_p10; + p90 = m_statsAllTimesteps.m_p90; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigStatisticsDataCache::meanCellScalarValues(size_t timeStepIndex, double& meanValue) +void RigStatisticsDataCache::p10p90CellScalarValues(size_t timeStepIndex, double& p10, double& p90) { - if (!m_statsPrTs[timeStepIndex].m_isMeanCalculated) - { - m_statisticsCalculator->meanCellScalarValue(timeStepIndex, m_statsPrTs[timeStepIndex].m_meanValue); - m_statsPrTs[timeStepIndex].m_isMeanCalculated = true; - } + computeHistogramStatisticsIfNeeded(timeStepIndex); - meanValue = m_statsPrTs[timeStepIndex].m_meanValue; + p10 = m_statsPrTs[timeStepIndex].m_p10; + p90 = m_statsPrTs[timeStepIndex].m_p90; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp index c63eed6991..dcaac02f1f 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp @@ -186,56 +186,51 @@ RigHistogramCalculator::RigHistogramCalculator(double min, double max, size_t nB for (size_t i = 0; i < m_histogram->size(); ++i) (*m_histogram)[i] = 0; m_range = max - min; - maxIndex = nBins-1; + m_maxIndex = nBins-1; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigHistogramCalculator::addData(const std::vector& data) +void RigHistogramCalculator::addValue(double value) { - assert(m_histogram); - for (size_t i = 0; i < data.size(); ++i) + if (value == HUGE_VAL || value != value) { - if (data[i] == HUGE_VAL) - { - continue; - } + return; + } - size_t index = 0; + size_t index = 0; - if (maxIndex > 0) index = (size_t)(maxIndex*(data[i] - m_min)/m_range); + if (m_maxIndex > 0) index = (size_t)(m_maxIndex*(value - m_min)/m_range); - if(index < m_histogram->size()) // Just clip to the max min range (-index will overflow to positive ) - { - (*m_histogram)[index]++; - m_observationCount++; - } + if (index < m_histogram->size()) // Just clip to the max min range (-index will overflow to positive ) + { + (*m_histogram)[index]++; + m_observationCount++; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigHistogramCalculator::addData(const std::vector& data) +void RigHistogramCalculator::addData(const std::vector& data) { assert(m_histogram); for (size_t i = 0; i < data.size(); ++i) { - if (data[i] == HUGE_VAL) - { - continue; - } - - size_t index = 0; - - if (maxIndex > 0) index = (size_t)(maxIndex*(data[i] - m_min)/m_range); + addValue(data[i]); + } +} - if(index < m_histogram->size()) // Just clip to the max min range (-index will overflow to positive ) - { - (*m_histogram)[index]++; - m_observationCount++; - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigHistogramCalculator::addData(const std::vector& data) +{ + assert(m_histogram); + for (size_t i = 0; i < data.size(); ++i) + { + addValue(data[i]); } } diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h index 59de3160ab..741edf2eb2 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h @@ -41,6 +41,8 @@ class RigHistogramCalculator void addData(const std::vector& data); void addData(const std::vector& data); + void addValue(double value); + /// Calculates the estimated percentile from the histogram. /// the percentile is the domain value at which pVal of the observations are below it. /// Will only consider observed values between min and max, as all other values are discarded from the histogram @@ -48,7 +50,7 @@ class RigHistogramCalculator double calculatePercentil(double pVal); private: - size_t maxIndex; + size_t m_maxIndex; double m_range; double m_min; size_t m_observationCount; From 67abe959db5d90bb8e6c6712e4f692471f933a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 6 Nov 2015 10:45:13 +0100 Subject: [PATCH 019/290] (#606) Made each node-result count only once --- .../RigFemNativeVisibleCellsStatCalc.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h index cc2eb0b342..3bc76dbadc 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h @@ -61,8 +61,12 @@ class RigFemNativeVisibleCellsStatCalc : public RigStatisticsCalculator { RigFemPart* part = m_caseData->femParts()->part(pIdx); const std::vector& values = m_resultsData->resultValues(m_resVarAddr, pIdx, (int)timeStepIndex); - int elmCount = part->elementCount(); + size_t nodeCount = values.size(); + cvf::UByteArray nodeVisibilities(nodeCount); + nodeVisibilities.setAll(false); + + int elmCount = part->elementCount(); for (int elmIdx = 0; elmIdx < elmCount; ++elmIdx) { if (!(*m_cellVisibilities)[elmIdx]) continue; @@ -72,6 +76,14 @@ class RigFemNativeVisibleCellsStatCalc : public RigStatisticsCalculator { size_t elmNodeResIdx = part->elementNodeResultIdx(elmIdx, elmLocIdx); int nodeIdx = part->nodeIdxFromElementNodeResultIdx(elmNodeResIdx); + nodeVisibilities[nodeIdx] = true; + } + } + + for (size_t nodeIdx = 0; nodeIdx < nodeCount; ++nodeIdx) + { + if (nodeVisibilities[nodeIdx]) + { accumulator.addValue(values[nodeIdx]); } } From 4f05c0d6b99bfdba60ea0986fd6c8d3a5a24deb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 6 Nov 2015 13:22:54 +0100 Subject: [PATCH 020/290] (#606) (#607) Added eclipse stats for visible cells --- .../RigFemNativeVisibleCellsStatCalc.cpp | 73 --------- .../Rim3dOverlayInfoConfig.cpp | 141 +++++++++--------- .../ReservoirDataModel/CMakeLists_files.cmake | 2 + .../RigEclipseNativeVisibleCellsStatCalc.cpp | 91 +++++++++++ .../RigEclipseNativeVisibleCellsStatCalc.h | 72 +++++++++ .../RigStatisticsDataCache.cpp | 2 +- .../ResultStatisticsCache/RigStatisticsMath.h | 75 ++++++++++ .../RiuSimpleHistogramWidget.cpp | 35 +++++ .../UserInterface/RiuSimpleHistogramWidget.h | 8 +- 9 files changed, 354 insertions(+), 145 deletions(-) create mode 100644 ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp create mode 100644 ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp index cc7ed6b31c..b60a5ba5a2 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.cpp @@ -37,33 +37,6 @@ RigFemNativeVisibleCellsStatCalc::RigFemNativeVisibleCellsStatCalc(RigGeoMechCas m_resultsData = femCase->femPartResults(); } -class MinMaxAccumulator -{ -public: - MinMaxAccumulator(double initMin, double initMax): max(initMax), min(initMin) {} - void addValue(double value) - { - if (value == HUGE_VAL) // TODO - { - return; - } - - if (value < min) - { - min = value; - } - - if (value > max) - { - max = value; - } - } - - double max; - double min; -}; - - //-------------------------------------------------------------------------------------------------- /// @@ -77,32 +50,6 @@ void RigFemNativeVisibleCellsStatCalc::minMaxCellScalarValues(size_t timeStepInd } -class PosNegAccumulator -{ -public: - PosNegAccumulator(double initPos, double initNeg): pos(initPos), neg(initNeg) {} - void addValue(double value) - { - if (value == HUGE_VAL) - { - return; - } - - if (value < pos && value > 0) - { - pos = value; - } - - if (value > neg && value < 0) - { - neg = value; - } - } - - double pos; - double neg; -}; - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -115,26 +62,6 @@ void RigFemNativeVisibleCellsStatCalc::posNegClosestToZero(size_t timeStepIndex, } -class SumCountAccumulator -{ -public: - SumCountAccumulator(double initSum, size_t initCount): valueSum(initSum), sampleCount(initCount) {} - - void addValue(double value) - { - if (value == HUGE_VAL || value != value) - { - return; - } - - valueSum += value; - ++sampleCount; - } - - double valueSum; - size_t sampleCount; -}; - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 95e21c2632..1ce6ef516f 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -43,6 +43,7 @@ #include "RigStatisticsDataCache.h" #include "RigFemNativeVisibleCellsStatCalc.h" +#include "RigEclipseNativeVisibleCellsStatCalc.h" CAF_PDM_SOURCE_INIT(Rim3dOverlayInfoConfig, "View3dOverlayInfoConfig"); //-------------------------------------------------------------------------------------------------- @@ -174,6 +175,65 @@ void Rim3dOverlayInfoConfig::setReservoirView(RimView* ownerReservoirView) //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) { + double min = HUGE_VAL, max = HUGE_VAL; + double p10 = HUGE_VAL, p90 = HUGE_VAL; + double mean = HUGE_VAL; + const std::vector* histogram = NULL; + + bool isResultsInfoRelevant = reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult(); + + if (showHistogram() || showInfoText()) + { + if (isResultsInfoRelevant) + { + size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); + if (m_statisticsCellRange == ALL_CELLS) + { + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP ) + { + int timeStepIdx = reservoirView->currentTimeStep(); + reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); + reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); + reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); + histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex, timeStepIdx)); + } + else + { + CVF_ASSERT(false); + } + } + else if ( m_statisticsCellRange == VISIBLE_CELLS) + { + updateVisCellStatsIfNeeded(); + if (m_statisticsTimeRange == ALL_TIMESTEPS) + { + // TODO: Only valid if we have no dynamic property filter + m_visibleCellStatistics->meanCellScalarValues(mean); + m_visibleCellStatistics->minMaxCellScalarValues(min, max); + m_visibleCellStatistics->p10p90CellScalarValues(p10, p90); + + histogram = &(m_visibleCellStatistics->cellScalarValuesHistogram()); + } + else if (m_statisticsTimeRange == CURRENT_TIMESTEP) + { + int currentTimeStep = reservoirView->currentTimeStep(); + m_visibleCellStatistics->meanCellScalarValues(currentTimeStep, mean); + m_visibleCellStatistics->minMaxCellScalarValues(currentTimeStep, min, max); + m_visibleCellStatistics->p10p90CellScalarValues(currentTimeStep, p10, p90); + + histogram = &(m_visibleCellStatistics->cellScalarValuesHistogram(currentTimeStep)); + } + } + } + } + if (showInfoText()) { QString caseName; @@ -217,39 +277,17 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) infoText += QString("Cell Property: %1 ").arg(propName); } - if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) + if (isResultsInfoRelevant) { infoText += QString("Cell Property: %1 ").arg(propName); // Wait until regression tests confirm new statisticks is ok : //infoText += QString("
Statistics for: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); - if (m_statisticsCellRange == ALL_CELLS) - { - double min = HUGE_VAL, max = HUGE_VAL; - double p10 = HUGE_VAL, p90 = HUGE_VAL; - double mean = HUGE_VAL; - - size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); - - if (m_statisticsTimeRange == ALL_TIMESTEPS) - { - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); - } - else if (m_statisticsTimeRange == CURRENT_TIMESTEP) - { - int timeStepIdx = reservoirView->currentTimeStep(); - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); - } - infoText += QString("" - "" - "" - "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - } + infoText += QString("" + "" + "" + "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); if (reservoirView->faultResultSettings()->hasValidCustomResult()) { @@ -309,41 +347,11 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) if (showHistogram()) { - if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult()) + if (isResultsInfoRelevant) { - if (m_statisticsCellRange == ALL_CELLS) - { - double min = HUGE_VAL, max = HUGE_VAL; - double p10 = HUGE_VAL, p90 = HUGE_VAL; - double mean = HUGE_VAL; - const std::vector* histogram = NULL; - - size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); - - if (m_statisticsTimeRange == ALL_TIMESTEPS) - { - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); - histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); - } - else if (m_statisticsTimeRange == CURRENT_TIMESTEP ) - { - int timeStepIdx = reservoirView->currentTimeStep(); - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); - histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex, timeStepIdx)); - } - else - { - CVF_ASSERT(false); - } - - reservoirView->viewer()->showHistogram(true); - reservoirView->viewer()->setHistogram(min, max, *histogram); - reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); - } + reservoirView->viewer()->showHistogram(true); + reservoirView->viewer()->setHistogram(min, max, *histogram); + reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); } } } @@ -511,15 +519,14 @@ void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() calc = new RigFemNativeVisibleCellsStatCalc(geoMechView->geoMechCase()->geoMechData(), resAddress, geoMechView->currentTotalCellVisibility().p()); - m_visibleCellStatistics = new RigStatisticsDataCache(calc.p()); - m_isVisCellStatUpToDate = true; + } else if (eclipseView) { - // RigFemResultAddress resAddress = geoMechView->cellResult()->resultAddress(); - // cvf::ref calc = new RigEclipseNativeVisibleCellsStatCalc(geoMechView->geoMechCase()->geoMechData(), - // resAddress, - // geoMechView->currentTotalCellVisibility().p()); + size_t scalarIndex = eclipseView->cellResult()->scalarResultIndex(); + calc = new RigEclipseNativeVisibleCellsStatCalc(eclipseView->currentGridCellResults()->cellResults(), + scalarIndex, + eclipseView->currentTotalCellVisibility().p()); } m_visibleCellStatistics = new RigStatisticsDataCache(calc.p()); diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 68d64de050..3afd3f2d9c 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -35,6 +35,7 @@ ${CEE_CURRENT_LIST_DIR}RigPipeInCellEvaluator.h ${CEE_CURRENT_LIST_DIR}RigResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h +${CEE_CURRENT_LIST_DIR}RigEclipseNativeVisibleCellsStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.h ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.h ${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.h @@ -68,6 +69,7 @@ ${CEE_CURRENT_LIST_DIR}RigNNCData.cpp ${CEE_CURRENT_LIST_DIR}cvfGeometryTools.cpp ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.cpp +${CEE_CURRENT_LIST_DIR}RigEclipseNativeVisibleCellsStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigEclipseMultiPropertyStatCalc.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogCurveData.cpp ${CEE_CURRENT_LIST_DIR}RigTimeHistoryResultAccessor.cpp diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp new file mode 100644 index 0000000000..0281f7b94d --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp @@ -0,0 +1,91 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RigEclipseNativeVisibleCellsStatCalc.h" + +#include +#include "RigStatisticsMath.h" +#include "RigCaseCellResultsData.h" +#include "RigActiveCellInfo.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEclipseNativeVisibleCellsStatCalc::RigEclipseNativeVisibleCellsStatCalc(RigCaseCellResultsData* cellResultsData, + size_t scalarResultIndex, + const cvf::UByteArray* cellVisibilities) +: m_caseData(cellResultsData), + m_scalarResultIndex(scalarResultIndex), + m_cellVisibilities(cellVisibilities) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseNativeVisibleCellsStatCalc::minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) +{ + MinMaxAccumulator acc(min, max); + traverseCells(acc, timeStepIndex); + min = acc.min; + max = acc.max; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseNativeVisibleCellsStatCalc::posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) +{ + PosNegAccumulator acc(pos, neg); + traverseCells(acc, timeStepIndex); + pos = acc.pos; + neg = acc.neg; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseNativeVisibleCellsStatCalc::valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) +{ + SumCountAccumulator acc(valueSum, sampleCount); + traverseCells(acc, timeStepIndex); + valueSum = acc.valueSum; + sampleCount = acc.sampleCount; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseNativeVisibleCellsStatCalc::addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) +{ + traverseCells(histogramCalculator, timeStepIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigEclipseNativeVisibleCellsStatCalc::timeStepCount() +{ + return m_caseData->timeStepCount(m_scalarResultIndex); +} + + diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h new file mode 100644 index 0000000000..1c58e067fc --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + + +//================================================================================================== +/// +//================================================================================================== +#include "RigStatisticsCalculator.h" +#include "cvfArray.h" + +class RigCaseCellResultsData; + + +class RigEclipseNativeVisibleCellsStatCalc : public RigStatisticsCalculator +{ +public: + RigEclipseNativeVisibleCellsStatCalc(RigCaseCellResultsData* cellResultsData, + size_t scalarResultIndex, + const cvf::UByteArray* cellVisibilities); + + virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); + virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); + virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + virtual size_t timeStepCount(); + +private: + RigCaseCellResultsData* m_caseData; + size_t m_scalarResultIndex; + cvf::cref m_cellVisibilities; + + template + void traverseCells(StatisticsAccumulator& accumulator, size_t timeStepIndex) + { + std::vector& values = m_caseData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + const RigActiveCellInfo* actCellInfo = m_caseData->activeCellInfo(); + size_t cellCount = actCellInfo->reservoirCellCount(); + + CVF_TIGHT_ASSERT(cellCount == m_cellVisibilities->size()); + + for (size_t cIdx = 0; cIdx < cellCount; ++cIdx) + { + if (!(*m_cellVisibilities)[cIdx]) continue; + + size_t cellResultIndex = actCellInfo->cellResultIndex(cIdx); + + if (cellResultIndex != cvf::UNDEFINED_SIZE_T) accumulator.addValue(values[cellResultIndex]); + } + } + +}; + + + diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp index 774278f324..acb1947449 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.cpp @@ -263,7 +263,7 @@ void RigStatisticsDataCache::computeHistogramStatisticsIfNeeded(size_t timeStepI double min; double max; size_t nBins = 100; - this->minMaxCellScalarValues(min, max); + this->minMaxCellScalarValues(timeStepIndex, min, max); RigHistogramCalculator histCalc(min, max, nBins, &m_statsPrTs[timeStepIndex].m_histogram); diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h index 741edf2eb2..5aac8c258a 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.h @@ -56,3 +56,78 @@ class RigHistogramCalculator size_t m_observationCount; std::vector* m_histogram; }; + + +class MinMaxAccumulator +{ +public: + MinMaxAccumulator(double initMin, double initMax): max(initMax), min(initMin) {} + void addValue(double value) + { + if (value == HUGE_VAL) // TODO + { + return; + } + + if (value < min) + { + min = value; + } + + if (value > max) + { + max = value; + } + } + + double max; + double min; +}; + + +class PosNegAccumulator +{ +public: + PosNegAccumulator(double initPos, double initNeg): pos(initPos), neg(initNeg) {} + void addValue(double value) + { + if (value == HUGE_VAL) + { + return; + } + + if (value < pos && value > 0) + { + pos = value; + } + + if (value > neg && value < 0) + { + neg = value; + } + } + + double pos; + double neg; +}; + + +class SumCountAccumulator +{ +public: + SumCountAccumulator(double initSum, size_t initCount): valueSum(initSum), sampleCount(initCount) {} + + void addValue(double value) + { + if (value == HUGE_VAL || value != value) + { + return; + } + + valueSum += value; + ++sampleCount; + } + + double valueSum; + size_t sampleCount; +}; diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp index f5384166de..11eb954553 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp @@ -105,3 +105,38 @@ void RiuSimpleHistogramWidget::setHistogramData(double min, double max, const st if (m_maxHistogramCount < m_histogramData[colIdx]) m_maxHistogramCount = m_histogramData[colIdx] ; } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSimpleHistogramWidget::setPercentiles(double pmin, double pmax) +{ + m_minPercentile = pmin; + m_maxPercentile = pmax; +} + +#define xBorder 1 +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuSimpleHistogramWidget::xPosFromColIdx(size_t colIdx) +{ + return (int)(m_x + xBorder + (m_width - 2*xBorder) * colIdx/m_histogramData.size()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuSimpleHistogramWidget::xPosFromDomainValue(double value) +{ + double range = m_max - m_min; + return (range == 0.0) ? (int)(m_x + xBorder) : (int)(m_x + xBorder + (m_width - 2*xBorder) * (value - m_min)/(m_max - m_min)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuSimpleHistogramWidget::yPosFromCount(size_t colHeight) +{ + return (int)(m_y + m_height - 1 - (m_height - 3) * colHeight/m_maxHistogramCount); +} diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h index 5ced51fa8e..2dd2a409fa 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h @@ -10,7 +10,7 @@ class RiuSimpleHistogramWidget : public QWidget RiuSimpleHistogramWidget( QWidget * parent = 0, Qt::WindowFlags f = 0); void setHistogramData(double min, double max, const std::vector& histogram); - void setPercentiles(double pmin, double pmax) {m_minPercentile = pmin; m_maxPercentile = pmax;} + void setPercentiles(double pmin, double pmax); void setMean(double mean) {m_mean = mean;} protected: @@ -19,10 +19,10 @@ class RiuSimpleHistogramWidget : public QWidget private: void draw(QPainter *painter,int x, int y, int width, int height ); - int xPosFromColIdx(size_t colIdx) { return (int)(m_x + 1 + (m_width - 2 ) * colIdx/m_histogramData.size());} - int yPosFromCount(size_t colHeight) { return (int)(m_y + m_height - 1 - (m_height - 3 ) * colHeight/m_maxHistogramCount);} + int xPosFromColIdx(size_t colIdx); + int yPosFromCount(size_t colHeight); - int xPosFromDomainValue(double value) { double range = m_max - m_min; return (range == 0.0) ? (int)(m_x + 1) : (int)(m_x + 1 + (m_width - 2 ) * (value - m_min)/(m_max - m_min));} + int xPosFromDomainValue(double value); std::vector m_histogramData; double m_max; From 516c1203139150eb5eede7a29751f142507a8bc1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 9 Nov 2015 17:41:34 +0100 Subject: [PATCH 021/290] (#632) Added selection manager for items in 3D view --- .../UserInterface/RiuSelectionManager.cpp | 73 +++++++++++++ .../UserInterface/RiuSelectionManager.h | 103 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 ApplicationCode/UserInterface/RiuSelectionManager.cpp create mode 100644 ApplicationCode/UserInterface/RiuSelectionManager.h diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.cpp b/ApplicationCode/UserInterface/RiuSelectionManager.cpp new file mode 100644 index 0000000000..fc25056989 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionManager.cpp @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuSelectionManager.h" + +#include "RimEclipseView.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionManager* RiuSelectionManager::instance() +{ + static RiuSelectionManager* singleton = new RiuSelectionManager; + return singleton; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionManager::selectedItems(std::vector& items) const +{ + items = m_selection; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionManager::setSelectedItems(const std::vector& items) +{ + CVF_ASSERT(m_selection.size() == 0); + + m_selection = items; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionManager::deleteAllItems() +{ + for (size_t i = 0; i < m_selection.size(); i++) + { + delete m_selection[i]; + } + + m_selection.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuEclipseSelectionItem::RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color) + : m_view(view), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex), + m_color(color) +{ +} diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.h b/ApplicationCode/UserInterface/RiuSelectionManager.h new file mode 100644 index 0000000000..7e85181b4c --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionManager.h @@ -0,0 +1,103 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cafPdmPointer.h" + +#include "cvfBase.h" +#include "cvfColor3.h" + +#include + +class RimEclipseView; + +class RiuSelectionItem; + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuSelectionManager +{ +public: + static RiuSelectionManager* instance(); + + // Returns selected items + // Selection manager owns the selection items and is responsible for delete + void selectedItems(std::vector& items) const; + + // Set vector of items as selected items in SelectionManager + // SelectionManager takes ownership of the selection items + void setSelectedItems(const std::vector& items); + + // Deletes all items in the SelectionManager + void deleteAllItems(); + +private: + std::vector < RiuSelectionItem* > m_selection; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuSelectionItem +{ +public: + enum RiuSelectionType + { + ECLIPSE_SELECTION_OBJECT, + GEOMECH_SELECTION_OBJECT + }; + +public: + RiuSelectionItem() {} + virtual ~RiuSelectionItem() {}; + + virtual RiuSelectionType type() = 0; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuEclipseSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color); + virtual ~RiuEclipseSelectionItem() {}; + + virtual RiuSelectionType type() + { + return ECLIPSE_SELECTION_OBJECT; + } + +public: + caf::PdmPointer m_view; + size_t m_gridIndex; + size_t m_cellIndex; + cvf::Color3f m_color; +}; + + From 963220dd37c57f9ebd8f10d633441bdee56aa0e0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 9 Nov 2015 17:42:55 +0100 Subject: [PATCH 022/290] (#632) Added support for creation of mesh part from a single cell --- ApplicationCode/CMakeLists.txt | 2 + .../ModelVisualization/CMakeLists_files.cmake | 4 +- .../RivSingleCellPartGenerator.cpp | 74 +++++++++++++++++++ .../RivSingleCellPartGenerator.h | 48 ++++++++++++ .../cvfStructGridGeometryGenerator.cpp | 40 ++++++++++ .../cvfStructGridGeometryGenerator.h | 2 + 6 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 57b5c2d616..705cf03c58 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -92,6 +92,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuProjectPropertyView.cpp UserInterface/RiuTimeHistoryQwtPlot.h UserInterface/RiuTimeHistoryQwtPlot.cpp + UserInterface/RiuSelectionManager.h + UserInterface/RiuSelectionManager.cpp ) set( SOCKET_INTERFACE_FILES diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index b17a032cf4..7c86908d4f 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -32,8 +32,7 @@ ${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapperEffectGenerator.h ${CEE_CURRENT_LIST_DIR}RivScalarMapperUtils.h ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.h ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.h - - +${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -62,6 +61,7 @@ ${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapperEffectGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivScalarMapperUtils.cpp ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.cpp ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.cpp +${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.cpp ) diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp new file mode 100644 index 0000000000..20aac2f185 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp @@ -0,0 +1,74 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivSingleCellPartGenerator.h" + +#include "RigCaseData.h" + +#include "cafEffectGenerator.h" +#include "cvfPart.h" +#include "cvfRenderStateDepth.h" +#include "cvfStructGridGeometryGenerator.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivSingleCellPartGenerator::RivSingleCellPartGenerator(RigCaseData* rigCaseData, size_t gridIndex, size_t cellIndex) + : m_rigCaseData(rigCaseData), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivSingleCellPartGenerator::createPart(const cvf::Color3f color) +{ + cvf::ref part = new cvf::Part; + part->setName("Hightlight part for cell index " + m_cellIndex); + part->setDrawable(createMeshDrawable().p()); + + cvf::ref eff; + caf::MeshEffectGenerator effGen(color); + eff = effGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + + part->setEffect(eff.p()); + + return part; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivSingleCellPartGenerator::createMeshDrawable() +{ + if (m_rigCaseData && + m_cellIndex != cvf::UNDEFINED_SIZE_T) + { + return cvf::StructGridGeometryGenerator::createMeshDrawableFromSingleCell(m_rigCaseData->grid(m_gridIndex), m_cellIndex); + } + + return NULL; +} diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h new file mode 100644 index 0000000000..dbf8b2ad56 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h @@ -0,0 +1,48 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cvfDrawableGeo.h" + +namespace cvf +{ + class Part; +} + +class RigCaseData; + +//================================================================================================== +/// +/// +//================================================================================================== +class RivSingleCellPartGenerator +{ +public: + RivSingleCellPartGenerator(RigCaseData* rigCaseData, size_t gridIndex, size_t cellIndex); + + cvf::ref createPart(const cvf::Color3f color); + +private: + cvf::ref createMeshDrawable(); + +private: + RigCaseData* m_rigCaseData; + size_t m_gridIndex; + size_t m_cellIndex; +}; diff --git a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp index e3fe26dcfa..7a724cd464 100644 --- a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp +++ b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.cpp @@ -252,6 +252,46 @@ ref StructGridGeometryGenerator::createOutlineMeshDrawable(double c } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +ref StructGridGeometryGenerator::createMeshDrawableFromSingleCell(const StructGridInterface* grid, size_t cellIndex) +{ + cvf::Vec3d cornerVerts[8]; + grid->cellCornerVertices(cellIndex, cornerVerts); + + std::vector vertices; + + for (int enumInt = cvf::StructGridInterface::POS_I; enumInt < cvf::StructGridInterface::NO_FACE; enumInt++) + { + cvf::StructGridInterface::FaceType face = static_cast(enumInt); + + ubyte faceConn[4]; + grid->cellFaceVertexIndices(face, faceConn); + + int n; + for (n = 0; n < 4; n++) + { + vertices.push_back(cvf::Vec3f(cornerVerts[faceConn[n]] - grid->displayModelOffset())); + } + } + + cvf::ref cvfVertices = new cvf::Vec3fArray; + cvfVertices->assign(vertices); + + if (!(cvfVertices.notNull() && cvfVertices->size() != 0)) return NULL; + + ref geo = new DrawableGeo; + geo->setVertexArray(cvfVertices.p()); + + ref indices = lineIndicesFromQuadVertexArray(cvfVertices.p()); + ref prim = new PrimitiveSetIndexedUInt(PT_LINES); + prim->setIndices(indices.p()); + + geo->addPrimitiveSet(prim.p()); + return geo; +} + //-------------------------------------------------------------------------------------------------- /// /// diff --git a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h index 953043654d..03ba0642bb 100644 --- a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h +++ b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h @@ -187,6 +187,8 @@ class StructGridGeometryGenerator : public Object ref createMeshDrawable(); ref createOutlineMeshDrawable(double creaseAngle); + static ref createMeshDrawableFromSingleCell(const StructGridInterface* grid, size_t cellIndex); + private: static ref lineIndicesFromQuadVertexArray(const Vec3fArray* vertexArray); From 7cd2cd0f50089add7767706824dc2ca9a8932b25 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 9 Nov 2015 19:05:00 +0100 Subject: [PATCH 023/290] (#632) Add Eclipse cell to selection and show in 3D view and time history plot Consolidated remove of model based on name in RimView Cleanup selection and time history plot when project is closed --- .../Application/RiaApplication.cpp | 3 + .../ProjectDataModel/RimEclipseView.cpp | 97 ++++++++++++------- ApplicationCode/ProjectDataModel/RimView.cpp | 20 ++++ ApplicationCode/ProjectDataModel/RimView.h | 4 +- .../UserInterface/RiuMainWindow.cpp | 2 + .../UserInterface/RiuSelectionManager.cpp | 8 ++ .../UserInterface/RiuSelectionManager.h | 4 + .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 7 +- .../UserInterface/RiuTimeHistoryQwtPlot.h | 9 +- .../UserInterface/RiuViewerCommands.cpp | 41 +++++++- 10 files changed, 149 insertions(+), 46 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 6c85decc4b..855b10e198 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -66,6 +66,7 @@ #include "RiuMainWindow.h" #include "RiuProcessMonitor.h" +#include "RiuSelectionManager.h" #include "RiuViewer.h" #include "cafAppEnum.h" @@ -608,6 +609,8 @@ bool RiaApplication::closeProject(bool askToSaveIfDirty) } } + RiuSelectionManager::instance()->deleteAllItems(); + mainWnd->cleanupGuiBeforeProjectClose(); caf::EffectGenerator::clearEffectCache(); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 268ddd07fc..9d4ae8fda6 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -22,33 +22,42 @@ #include "RiaApplication.h" #include "RiaPreferences.h" + #include "RigCaseCellResultsData.h" #include "RigCaseData.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" + #include "Rim3dOverlayInfoConfig.h" -#include "RimEclipseCase.h" #include "RimCellEdgeColors.h" -#include "RimEclipsePropertyFilterCollection.h" #include "RimCellRangeFilterCollection.h" -#include "RimFaultCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" #include "RimEclipseFaultColors.h" +#include "RimEclipsePropertyFilterCollection.h" +#include "RimEclipseWell.h" +#include "RimEclipseWellCollection.h" +#include "RimFaultCollection.h" #include "RimOilField.h" #include "RimProject.h" -#include "RimEclipseCellColors.h" #include "RimTernaryLegendConfig.h" -#include "RimEclipseWell.h" -#include "RimEclipseWellCollection.h" +#include "RimViewController.h" +#include "RimViewLinker.h" #include "RimWellPathCollection.h" + #include "RiuMainWindow.h" +#include "RiuSelectionManager.h" #include "RiuViewer.h" + #include "RivReservoirPipesPartMgr.h" +#include "RivSingleCellPartGenerator.h" #include "RivTernarySaturationOverlayItem.h" #include "RivWellPathCollectionPartMgr.h" #include "cafCadNavigation.h" #include "cafCeetronPlusNavigation.h" #include "cafFrameAnimationControl.h" +#include "cafPdmUiTreeOrdering.h" #include "cvfDrawable.h" #include "cvfModelBasicList.h" @@ -61,9 +70,6 @@ #include #include -#include "RimViewLinker.h" -#include "RimViewController.h" -#include "cafPdmUiTreeOrdering.h" @@ -644,20 +650,8 @@ void RimEclipseView::updateCurrentTimeStep() // Well pipes // ---------- cvf::String wellPipeModelName = "WellPipeModel"; - std::vector wellPipeModels; - for (cvf::uint i = 0; i < frameScene->modelCount(); i++) - { - if (frameScene->model(i)->name() == wellPipeModelName) - { - wellPipeModels.push_back(frameScene->model(i)); - } - } - for (size_t i = 0; i < wellPipeModels.size(); i++) - { - //printf("updateCurrentTimeStep: Remove WellPipeModel %i from frameScene, for frame %i\n", i, m_currentTimeStep.v()); - frameScene->removeModel(wellPipeModels[i]); - } + this->removeModelByName(frameScene, wellPipeModelName); cvf::ref wellPipeModelBasicList = new cvf::ModelBasicList; wellPipeModelBasicList->setName(wellPipeModelName); @@ -680,6 +674,51 @@ void RimEclipseView::updateCurrentTimeStep() mainGrid->characteristicIJCellSize(), currentActiveCellInfo()->geometryBoundingBox(), m_reservoirGridPartManager->scaleTransform()); + + + { + // Actions related to highlight items in scene + // + // Removed highlight model by name + // Create new highlight model with name + // Create and add selected parts + // Modify with scaletransform() + // Add parts to model + // Add model to scene + + cvf::String highlightModelName = "HighLightModel"; + + this->removeModelByName(frameScene, highlightModelName); + + cvf::ref highlightModelBasicList = new cvf::ModelBasicList; + highlightModelBasicList->setName(highlightModelName); + + RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + std::vector items; + riuSelManager->selectedItems(items); + for (size_t i = 0; i < items.size(); i++) + { + RiuEclipseSelectionItem* eclipseSelItem = dynamic_cast(items[i]); + if (eclipseSelItem && + eclipseSelItem->m_view) + { + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); + + RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); + + cvf::ref part = partGen.createPart(eclipseSelItem->m_color); + part->setTransform(this->scaleTransform()); + part->setPriority(10000); + + highlightModelBasicList->addPart(part.p()); + } + } + + highlightModelBasicList->updateBoundingBoxesRecursive(); + + frameScene->addModel(highlightModelBasicList.p()); + } } } @@ -1565,19 +1604,7 @@ void RimEclipseView::addWellPathsToScene(cvf::Scene* scene, CVF_ASSERT(scaleTransform); cvf::String wellPathModelName = "WellPathModel"; - std::vector wellPathModels; - for (cvf::uint i = 0; i < scene->modelCount(); i++) - { - if (scene->model(i)->name() == wellPathModelName) - { - wellPathModels.push_back(scene->model(i)); - } - } - - for (size_t i = 0; i < wellPathModels.size(); i++) - { - scene->removeModel(wellPathModels[i]); - } + this->removeModelByName(scene, wellPathModelName); // Append static Well Paths to model cvf::ref wellPathModelBasicList = new cvf::ModelBasicList; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 2bf4d50587..d3429e3b1b 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -746,3 +746,23 @@ void RimView::replaceRangeFilterCollectionWithOverride() this->uiCapability()->updateConnectedEditors(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimView::removeModelByName(cvf::Scene* scene, const cvf::String& modelName) +{ + std::vector modelsToBeRemoved; + for (cvf::uint i = 0; i < scene->modelCount(); i++) + { + if (scene->model(i)->name() == modelName) + { + modelsToBeRemoved.push_back(scene->model(i)); + } + } + + for (size_t i = 0; i < modelsToBeRemoved.size(); i++) + { + scene->removeModel(modelsToBeRemoved[i]); + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index ec84420a08..28912acf6f 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -33,7 +33,6 @@ #include "cvfBase.h" #include "cvfObject.h" - #include class Rim3dOverlayInfoConfig; @@ -49,6 +48,7 @@ namespace cvf class BoundingBox; class ModelBasicList; class Scene; + class String; class Transform; } @@ -151,6 +151,8 @@ class RimView : public caf::PdmObject const cvf::BoundingBox& wellPathClipBoundingBox, cvf::Transform* scaleTransform); + static void removeModelByName(cvf::Scene* scene, const cvf::String& modelName); + virtual void createDisplayModel() = 0; virtual void updateDisplayModelVisibility() = 0; virtual void clampCurrentTimestep() = 0; diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 5e5f3c0d8b..c3a4c07cfa 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -181,6 +181,8 @@ void RiuMainWindow::cleanupGuiBeforeProjectClose() setPdmRoot(NULL); setResultInfo(""); + + m_timeHistoryQwtPlot->deleteAllCurves(); if (m_pdmUiPropertyView) { diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.cpp b/ApplicationCode/UserInterface/RiuSelectionManager.cpp index fc25056989..8a8c46d54a 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionManager.cpp @@ -48,6 +48,14 @@ void RiuSelectionManager::setSelectedItems(const std::vector& m_selection = items; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionManager::appendItemToSelection(RiuSelectionItem* item) +{ + m_selection.push_back(item); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.h b/ApplicationCode/UserInterface/RiuSelectionManager.h index 7e85181b4c..0089106647 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.h +++ b/ApplicationCode/UserInterface/RiuSelectionManager.h @@ -47,6 +47,10 @@ class RiuSelectionManager // SelectionManager takes ownership of the selection items void setSelectedItems(const std::vector& items); + // Append item to selected items in SelectionManager + // SelectionManager takes ownership of the item + void appendItemToSelection(RiuSelectionItem* item); + // Deletes all items in the SelectionManager void deleteAllItems(); diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index 09fe3bd589..6fe444881b 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -63,7 +63,7 @@ RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& timeHistoryValues) +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& dateTimes, const std::vector& timeHistoryValues) { CVF_ASSERT(dateTimes.size() == timeHistoryValues.size()); @@ -94,7 +94,6 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector plotCurve->setLineSegmentStartStopIndices(filteredIntervals); plotCurve->setTitle(curveName); - cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); plotCurve->setPen(QPen(QColor(curveColor.rByte(), curveColor.gByte(), curveColor.bByte()))); plotCurve->attach(this); @@ -108,7 +107,7 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector& frameTimes, const std::vector& timeHistoryValues) +void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& frameTimes, const std::vector& timeHistoryValues) { std::vector dateTimes; @@ -117,7 +116,7 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const std::vector dateTimes.push_back(QwtDate::toDateTime(frameTimes[i])); } - addCurve(curveName, dateTimes, timeHistoryValues); + addCurve(curveName, curveColor, dateTimes, timeHistoryValues); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h index 6f39124dc5..6737371553 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -24,6 +24,11 @@ class QwtPlotCurve; class QwtPlotGrid; +namespace cvf +{ + class Color3f; +} + //================================================================================================== // // @@ -35,8 +40,8 @@ class RiuTimeHistoryQwtPlot : public QwtPlot RiuTimeHistoryQwtPlot(QWidget* parent = NULL); virtual ~RiuTimeHistoryQwtPlot(); - void addCurve(const QString& curveName, const std::vector& dateTimes, const std::vector& timeHistoryValues); - void addCurve(const QString& curveName, const std::vector& frameTimes, const std::vector& timeHistoryValues); + void addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& dateTimes, const std::vector& timeHistoryValues); + void addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& frameTimes, const std::vector& timeHistoryValues); void deleteAllCurves(); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 465681d3d3..08c05cb0c9 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -78,6 +78,8 @@ #include #include #include "RigFemTimeHistoryResultAccessor.h" +#include "RiuSelectionManager.h" +#include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" //================================================================================================== // @@ -531,6 +533,11 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { // Delete all curves if no cell is hit mainWnd->timeHistoryPlot()->deleteAllCurves(); + + std::vector items; + RiuSelectionManager::instance()->deleteAllItems(); + + m_reservoirView->scheduleCreateDisplayModelAndRedraw(); } } @@ -567,10 +574,34 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t curveName += timeHistResultAccessor.topologyText(); std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); - - mainWnd->timeHistoryPlot()->addCurve(curveName, timeStepDates, timeHistoryValues); + + cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); + + std::vector items; + RiuSelectionManager::instance()->selectedItems(items); + + bool isItemPartOfSelection = false; + for (size_t i = 0; i < items.size(); i++) + { + RiuEclipseSelectionItem* eclSelItem = dynamic_cast(items[i]); + if (eclSelItem && + eclSelItem->m_view == eclipseView && + eclSelItem->m_gridIndex == gridIndex && + eclSelItem->m_cellIndex == cellIndex) + { + isItemPartOfSelection = true; + } + } + + if (!isItemPartOfSelection) + { + RiuSelectionManager::instance()->appendItemToSelection(new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, curveColor)); + + mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, timeStepDates, timeHistoryValues); + + eclipseView->scheduleCreateDisplayModelAndRedraw(); + } } } @@ -607,9 +638,11 @@ void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t } CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); + + cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); RiuMainWindow* mainWnd = RiuMainWindow::instance(); - mainWnd->timeHistoryPlot()->addCurve(curveName, frameTimes, timeHistoryValues); + mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, frameTimes, timeHistoryValues); } } From f05385129b4b4784af59ab4952b1a4f205b23702 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 08:58:17 +0100 Subject: [PATCH 024/290] (#632) Single click on cell gives single cell selection for curves, CTRL + click appends --- .../UserInterface/RiuViewerCommands.cpp | 27 ++++++++++++------- .../UserInterface/RiuViewerCommands.h | 4 +-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 08c05cb0c9..80b3eeeae3 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -481,12 +481,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM QString pickInfo = "No hits"; QString resultInfo = ""; - bool addCurveToTimeHistoryPlot = false; - if (keyboardModifiers & Qt::ControlModifier) - { - addCurveToTimeHistoryPlot = true; - } - if (cellIndex != cvf::UNDEFINED_SIZE_T || nncIndex != cvf::UNDEFINED_SIZE_T) { RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); @@ -503,7 +497,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM pickInfo = textBuilder.topologyText(", "); - if (addCurveToTimeHistoryPlot) addTimeHistoryCurve(eclipseView, gridIndex, cellIndex); + addTimeHistoryCurve(eclipseView, gridIndex, cellIndex, keyboardModifiers); } else if (geomView) { @@ -516,7 +510,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM pickInfo = textBuilder.topologyText(", "); - if (addCurveToTimeHistoryPlot) addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint); + addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint, keyboardModifiers); } } @@ -548,7 +542,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex) +void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex, Qt::KeyboardModifiers keyboardModifiers) { RiuMainWindow* mainWnd = RiuMainWindow::instance(); if (!mainWnd->timeHistoryPlot()->isVisible()) return; @@ -596,6 +590,12 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t if (!isItemPartOfSelection) { + if (!(keyboardModifiers & Qt::ControlModifier)) + { + mainWnd->timeHistoryPlot()->deleteAllCurves(); + RiuSelectionManager::instance()->deleteAllItems(); + } + RiuSelectionManager::instance()->appendItemToSelection(new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, curveColor)); mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, timeStepDates, timeHistoryValues); @@ -608,7 +608,7 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint) +void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint, Qt::KeyboardModifiers keyboardModifiers) { RiuMainWindow* mainWnd = RiuMainWindow::instance(); if (!mainWnd->timeHistoryPlot()->isVisible()) return; @@ -642,6 +642,13 @@ void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); RiuMainWindow* mainWnd = RiuMainWindow::instance(); + + if (!(keyboardModifiers & Qt::ControlModifier)) + { + mainWnd->timeHistoryPlot()->deleteAllCurves(); + RiuSelectionManager::instance()->deleteAllItems(); + } + mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, frameTimes, timeHistoryValues); } } diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 3a3dcd44be..dcca840e92 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -63,8 +63,8 @@ private slots: void createSliceRangeFilter(int ijOrk); void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); void updateSelectionFromPickedPart(cvf::Part* part); - void addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex); - void addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint); + void addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex, Qt::KeyboardModifiers keyboardModifiers); + void addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint, Qt::KeyboardModifiers keyboardModifiers); size_t m_currentGridIdx; size_t m_currentCellIndex; From 21ed13d61ae680244a8cef3ef29bfcaad913f9f0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 09:02:27 +0100 Subject: [PATCH 025/290] Upped version to 1.5.100-dev --- ResInsightVersion.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index b3b9777ce4..2dcf9847ee 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,9 +1,9 @@ set(CMAKE_MAJOR_VERSION 1) -set(CMAKE_MINOR_VERSION 3) -set(CMAKE_PATCH_VERSION 106) -# set(DEV_VERSION "-dev") -set(DEV_VERSION "-RC") +set(CMAKE_MINOR_VERSION 5) +set(CMAKE_PATCH_VERSION 100) +set(DEV_VERSION "-dev") + # https://github.com/CRAVA/crava/tree/master/libs/nrlib set(NRLIB_GITHUB_SHA "ba35d4359882f1c6f5e9dc30eb95fe52af50fd6f") From 2f70abb90d832f70b5ca439b40a50202f4ca2526 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 09:06:44 +0100 Subject: [PATCH 026/290] (#632) Minimum widget size of time history plot is set to zero --- .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 16 ++++++++++++++++ .../UserInterface/RiuTimeHistoryQwtPlot.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index 6fe444881b..1d867517e5 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -133,6 +133,22 @@ void RiuTimeHistoryQwtPlot::deleteAllCurves() m_plotCurves.clear(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuTimeHistoryQwtPlot::sizeHint() const +{ + return QSize(0, 0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuTimeHistoryQwtPlot::minimumSizeHint() const +{ + return QSize(0, 0); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h index 6737371553..4a7ad625da 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h @@ -45,6 +45,10 @@ class RiuTimeHistoryQwtPlot : public QwtPlot void deleteAllCurves(); +protected: + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + private: void setDefaults(); From 17493070ac0d3e37e10b27a6f8cea906f147ee6e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 09:43:56 +0100 Subject: [PATCH 027/290] (#632) Improved colors used for selection and time history curves --- ApplicationCode/CMakeLists.txt | 2 + .../UserInterface/RiuSelectionColors.cpp | 57 +++++++++++++++++++ .../UserInterface/RiuSelectionColors.h | 33 +++++++++++ .../UserInterface/RiuSelectionManager.cpp | 8 +++ .../UserInterface/RiuSelectionManager.h | 2 + .../UserInterface/RiuTimeHistoryQwtPlot.cpp | 3 +- .../UserInterface/RiuViewerCommands.cpp | 19 ++++--- 7 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 ApplicationCode/UserInterface/RiuSelectionColors.cpp create mode 100644 ApplicationCode/UserInterface/RiuSelectionColors.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 705cf03c58..f3e6b490c2 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -94,6 +94,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuTimeHistoryQwtPlot.cpp UserInterface/RiuSelectionManager.h UserInterface/RiuSelectionManager.cpp + UserInterface/RiuSelectionColors.h + UserInterface/RiuSelectionColors.cpp ) set( SOCKET_INTERFACE_FILES diff --git a/ApplicationCode/UserInterface/RiuSelectionColors.cpp b/ApplicationCode/UserInterface/RiuSelectionColors.cpp new file mode 100644 index 0000000000..ec2c6d2431 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionColors.cpp @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuSelectionColors.h" + +#include + +static const int RI_SELECTION_COLOR_COUNT = 7; +static const int RI_SELECTION_COLOR[] = +{ + Qt::magenta, + Qt::cyan, + Qt::blue, + Qt::red, + Qt::green, + Qt::yellow, + Qt::gray +}; + +static int riuSelectionColorIndex = 0; + +//-------------------------------------------------------------------------------------------------- +/// Pick default curve color from an index based palette +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiuSelectionColors::curveColorFromTable() +{ + QColor color = QColor(Qt::GlobalColor(RI_SELECTION_COLOR[riuSelectionColorIndex % RI_SELECTION_COLOR_COUNT])); + ++riuSelectionColorIndex; + cvf::Color3f cvfColor(color.redF(), color.greenF(), color.blueF()); + return cvfColor; +} + +//-------------------------------------------------------------------------------------------------- +/// Color rarely present in result value colors +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiuSelectionColors::singleCurveColor() +{ + riuSelectionColorIndex = 0; + + return curveColorFromTable(); +} diff --git a/ApplicationCode/UserInterface/RiuSelectionColors.h b/ApplicationCode/UserInterface/RiuSelectionColors.h new file mode 100644 index 0000000000..b0dbceaf2d --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionColors.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfColor3.h" + +//================================================================================================== +/// +//================================================================================================== +class RiuSelectionColors +{ +public: + static cvf::Color3f curveColorFromTable(); + static cvf::Color3f singleCurveColor(); +}; diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.cpp b/ApplicationCode/UserInterface/RiuSelectionManager.cpp index 8a8c46d54a..524ac234b1 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionManager.cpp @@ -69,6 +69,14 @@ void RiuSelectionManager::deleteAllItems() m_selection.clear(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuSelectionManager::isEmpty() const +{ + return m_selection.size() == 0; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.h b/ApplicationCode/UserInterface/RiuSelectionManager.h index 0089106647..397b1c5fdc 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.h +++ b/ApplicationCode/UserInterface/RiuSelectionManager.h @@ -54,6 +54,8 @@ class RiuSelectionManager // Deletes all items in the SelectionManager void deleteAllItems(); + bool isEmpty() const; + private: std::vector < RiuSelectionItem* > m_selection; }; diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp index 1d867517e5..f672f21ce2 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp @@ -21,10 +21,9 @@ #include "RigCurveDataTools.h" -#include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" - #include "RiuLineSegmentQwtPlotCurve.h" +#include "cvfBase.h" #include "cvfAssert.h" #include "cvfColor3.h" diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 80b3eeeae3..eff716ad7f 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -25,13 +25,14 @@ #include "Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h" #include "Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h" -#include "RigCaseData.h" #include "RigCaseCellResultsData.h" +#include "RigCaseData.h" #include "RigFemPartCollection.h" #include "RigFemPartGrid.h" #include "RigGeoMechCaseData.h" #include "RigTimeHistoryResultAccessor.h" +#include "RigFemTimeHistoryResultAccessor.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" #include "RimEclipseCase.h" @@ -50,13 +51,15 @@ #include "RimProject.h" #include "RimView.h" #include "RimViewController.h" +#include "RimWellLogFile.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" -#include "RimWellLogFile.h" #include "RiuFemResultTextBuilder.h" #include "RiuMainWindow.h" #include "RiuResultTextBuilder.h" +#include "RiuSelectionColors.h" +#include "RiuSelectionManager.h" #include "RiuTimeHistoryQwtPlot.h" #include "RiuViewer.h" @@ -77,9 +80,6 @@ #include #include #include -#include "RigFemTimeHistoryResultAccessor.h" -#include "RiuSelectionManager.h" -#include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" //================================================================================================== // @@ -570,7 +570,6 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); - cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); std::vector items; RiuSelectionManager::instance()->selectedItems(items); @@ -596,6 +595,12 @@ void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t RiuSelectionManager::instance()->deleteAllItems(); } + cvf::Color3f curveColor = RiuSelectionColors::curveColorFromTable(); + if (RiuSelectionManager::instance()->isEmpty()) + { + curveColor = RiuSelectionColors::singleCurveColor(); + } + RiuSelectionManager::instance()->appendItemToSelection(new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, curveColor)); mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, timeStepDates, timeHistoryValues); @@ -639,7 +644,7 @@ void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); - cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); + cvf::Color3f curveColor = RiuSelectionColors::curveColorFromTable(); RiuMainWindow* mainWnd = RiuMainWindow::instance(); From e64f943e4c4a01b8e80ea6d622ff0d2dffadd664 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 01:53:24 -0800 Subject: [PATCH 028/290] Fixed includes on Linux --- .../GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h | 5 ++++- .../ModelVisualization/RivSingleCellPartGenerator.h | 2 ++ .../RigEclipseNativeVisibleCellsStatCalc.h | 5 ++++- .../ResultStatisticsCache/RigStatisticsDataCache.h | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h index 3bc76dbadc..020b5d46e6 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h @@ -25,9 +25,12 @@ //================================================================================================== #include "RigStatisticsCalculator.h" #include "RigFemResultAddress.h" +#include "RigGeoMechCaseData.h" +#include "RigFemPartCollection.h" +#include "RigFemPartResultsCollection.h" + #include "cvfArray.h" -class RigGeoMechCaseData; class RigFemPartResultsCollection; diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h index dbf8b2ad56..703860ca64 100644 --- a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h @@ -18,6 +18,8 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + +#include "cvfBase.h" #include "cvfDrawableGeo.h" namespace cvf diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h index 1c58e067fc..fb1b077f80 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h @@ -24,9 +24,12 @@ /// //================================================================================================== #include "RigStatisticsCalculator.h" + +#include "RigCaseCellResultsData.h" +#include "RigActiveCellInfo.h" + #include "cvfArray.h" -class RigCaseCellResultsData; class RigEclipseNativeVisibleCellsStatCalc : public RigStatisticsCalculator diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h index 4926a0a68c..8b4d3e7cde 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsDataCache.h @@ -25,7 +25,7 @@ #include "cvfObject.h" #include - +#include // Needed for HUGE_VAL on Linux //================================================================================================== /// From a584bcfdf694cb6259246959ae7dcdb9aed114ef Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 11:11:13 +0100 Subject: [PATCH 029/290] Removed unused functions and variables --- .../ProjectDataModel/RimWellLogTrack.cpp | 23 ------------------- .../ProjectDataModel/RimWellLogTrack.h | 1 - .../UserInterface/RiuViewerCommands.cpp | 1 - 3 files changed, 25 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 2fb419c114..8532280db0 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -266,29 +266,6 @@ void RimWellLogTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::alignDepthZoomToPlotAndZoomAllX() -{ - if (m_wellLogTrackPlotWidget) - { - RimWellLogPlot* wellLogPlot; - firstAnchestorOrThisOfType(wellLogPlot); - if (wellLogPlot) - { - double minimumDepth, maximumDepth; - wellLogPlot->depthZoomMinMax(&minimumDepth, &maximumDepth); - - m_wellLogTrackPlotWidget->setDepthZoom(minimumDepth, maximumDepth); - } - - zoomAllXAxis(); - - m_wellLogTrackPlotWidget->replot(); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index ca49f14f51..b15b3cf7b7 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -58,7 +58,6 @@ class RimWellLogTrack : public caf::PdmObject void availableDepthRange(double* minimumDepth, double* maximumDepth); void zoomAllXAndZoomAllDepthOnOwnerPlot(); - void alignDepthZoomToPlotAndZoomAllX(); void zoomAllXAxis(); RiuWellLogTrack* viewer(); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index eff716ad7f..ac39c34a8d 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -528,7 +528,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM // Delete all curves if no cell is hit mainWnd->timeHistoryPlot()->deleteAllCurves(); - std::vector items; RiuSelectionManager::instance()->deleteAllItems(); m_reservoirView->scheduleCreateDisplayModelAndRedraw(); From ff6ea6cf0bfe92ad2f84804c04d6cc2ff851e72e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 10 Nov 2015 11:32:52 +0100 Subject: [PATCH 030/290] Fixed include Linux --- ApplicationCode/ReservoirDataModel/RigCurveDataTools.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h index deec6c889a..8633ad0a05 100644 --- a/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h +++ b/ApplicationCode/ReservoirDataModel/RigCurveDataTools.h @@ -21,6 +21,7 @@ #include "cvfAssert.h" +#include #include From a13376a8bf0be32b04cad077bab6f183c3943889 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 11 Nov 2015 11:41:11 +0100 Subject: [PATCH 031/290] (#632) Update application items when selection changes using a separate class Added RiuSelectionChangedHandler Moved code from ViewerCommands into SelectionChangedHandler --- ApplicationCode/CMakeLists.txt | 2 + .../RiuSelectionChangedHandler.cpp | 252 ++++++++++++++++++ .../RiuSelectionChangedHandler.h | 47 ++++ .../UserInterface/RiuSelectionManager.cpp | 66 ++++- .../UserInterface/RiuSelectionManager.h | 61 ++++- .../UserInterface/RiuViewerCommands.cpp | 194 ++------------ .../UserInterface/RiuViewerCommands.h | 2 - 7 files changed, 437 insertions(+), 187 deletions(-) create mode 100644 ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp create mode 100644 ApplicationCode/UserInterface/RiuSelectionChangedHandler.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index f3e6b490c2..5486f996b1 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -96,6 +96,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuSelectionManager.cpp UserInterface/RiuSelectionColors.h UserInterface/RiuSelectionColors.cpp + UserInterface/RiuSelectionChangedHandler.h + UserInterface/RiuSelectionChangedHandler.cpp ) set( SOCKET_INTERFACE_FILES diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp new file mode 100644 index 0000000000..33019f4437 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -0,0 +1,252 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuSelectionChangedHandler.h" + +#include "RiaApplication.h" + +#include "RigCaseCellResultsData.h" +#include "RigCaseData.h" +#include "RigFemTimeHistoryResultAccessor.h" +#include "RigGeoMechCaseData.h" +#include "RigTimeHistoryResultAccessor.h" + +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseView.h" +#include "RimGeoMechCase.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechView.h" +#include "RimProject.h" + +#include "RiuFemResultTextBuilder.h" +#include "RiuMainWindow.h" +#include "RiuResultTextBuilder.h" +#include "RiuSelectionManager.h" +#include "RiuTimeHistoryQwtPlot.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionChangedHandler::RiuSelectionChangedHandler() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionChangedHandler::~RiuSelectionChangedHandler() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::handleSelectionDeleted() const +{ + RiuMainWindow::instance()->timeHistoryPlot()->deleteAllCurves(); + + updateResultInfo(NULL); + + scheduleUpdateForAllVisibleViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::handleItemAppended(const RiuSelectionItem* item) const +{ + addCurveFromSelectionItem(item); + + updateResultInfo(item); + + scheduleUpdateForAllVisibleViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::handleSetSelectedItem(const RiuSelectionItem* item) const +{ + RiuMainWindow::instance()->timeHistoryPlot()->deleteAllCurves(); + + handleItemAppended(item); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuEclipseSelectionItem* eclipseSelectionItem) const +{ + RimEclipseView* eclipseView = eclipseSelectionItem->m_view.p(); + + if (eclipseView->cellResult()->hasDynamicResult() && + eclipseView->eclipseCase() && + eclipseView->eclipseCase()->reservoirData()) + { + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); + + size_t scalarIndexWithMaxTimeStepCount = cvf::UNDEFINED_SIZE_T; + eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->maxTimeStepCount(&scalarIndexWithMaxTimeStepCount); + std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(scalarIndexWithMaxTimeStepCount); + + RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), + eclipseSelectionItem->m_gridIndex, eclipseSelectionItem->m_cellIndex, + eclipseView->cellResult()->scalarResultIndex(), porosityModel); + + QString curveName = eclipseView->eclipseCase()->caseUserDescription(); + curveName += ", "; + curveName += eclipseView->cellResult()->resultVariable(); + curveName += ", "; + curveName += QString("Grid index %1").arg(eclipseSelectionItem->m_gridIndex); + curveName += ", "; + curveName += timeHistResultAccessor.topologyText(); + + std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); + CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); + + RiuMainWindow::instance()->timeHistoryPlot()->addCurve(curveName, eclipseSelectionItem->m_color, timeStepDates, timeHistoryValues); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuGeoMechSelectionItem* geomSelectionItem) const +{ + RimGeoMechView* geoMechView = geomSelectionItem->m_view.p(); + + if (geoMechView && + geoMechView->cellResult() && + geoMechView->cellResult()->hasResult() && + geoMechView->geoMechCase() && + geoMechView->geoMechCase()->geoMechData()) + { + RigFemTimeHistoryResultAccessor timeHistResultAccessor(geoMechView->geoMechCase()->geoMechData(), geoMechView->cellResult->resultAddress(), + geomSelectionItem->m_gridIndex, geomSelectionItem->m_cellIndex, geomSelectionItem->m_localIntersectionPoint); + + QString curveName; + curveName.append(geoMechView->geoMechCase()->caseUserDescription() + ", "); + + caf::AppEnum resPosAppEnum = geoMechView->cellResult()->resultPositionType(); + curveName.append(resPosAppEnum.uiText() + ", "); + curveName.append(geoMechView->cellResult()->resultFieldUiName()+ ", ") ; + curveName.append(geoMechView->cellResult()->resultComponentUiName() + ":\n"); + curveName.append(timeHistResultAccessor.topologyText()); + + std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); + std::vector frameTimes; + for (size_t i = 0; i < timeHistoryValues.size(); i++) + { + frameTimes.push_back(i); + } + + CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); + + RiuMainWindow::instance()->timeHistoryPlot()->addCurve(curveName, geomSelectionItem->m_color, frameTimes, timeHistoryValues); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuSelectionItem* itemAdded) const +{ + if (itemAdded->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) + { + const RiuEclipseSelectionItem* eclipseSelectionItem = static_cast(itemAdded); + + addCurveFromSelectionItem(eclipseSelectionItem); + } + else if (itemAdded->type() == RiuSelectionItem::GEOMECH_SELECTION_OBJECT) + { + const RiuGeoMechSelectionItem* geomSelectionItem = static_cast(itemAdded); + + addCurveFromSelectionItem(geomSelectionItem); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::scheduleUpdateForAllVisibleViews() const +{ + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + + RimProject* proj = RiaApplication::instance()->project(); + if (proj) + { + std::vector visibleViews; + proj->allVisibleViews(visibleViews); + + for (size_t i = 0; i < visibleViews.size(); i++) + { + visibleViews[i]->scheduleCreateDisplayModelAndRedraw(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionChangedHandler::updateResultInfo(const RiuSelectionItem* itemAdded) const +{ + QString resultInfo; + QString pickInfo; + + if (itemAdded != NULL) + { + if (itemAdded->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) + { + const RiuEclipseSelectionItem* eclipseSelectionItem = static_cast(itemAdded); + + RimEclipseView* eclipseView = eclipseSelectionItem->m_view.p(); + + RiuResultTextBuilder textBuilder(eclipseView, eclipseSelectionItem->m_gridIndex, eclipseSelectionItem->m_cellIndex, eclipseView->currentTimeStep()); + textBuilder.setFace(eclipseSelectionItem->m_face); + textBuilder.setNncIndex(eclipseSelectionItem->m_nncIndex); + textBuilder.setIntersectionPoint(eclipseSelectionItem->m_localIntersectionPoint); + + resultInfo = textBuilder.mainResultText(); + + pickInfo = textBuilder.topologyText(", "); + } + else if (itemAdded->type() == RiuSelectionItem::GEOMECH_SELECTION_OBJECT) + { + const RiuGeoMechSelectionItem* geomSelectionItem = static_cast(itemAdded); + + RimGeoMechView* geomView = geomSelectionItem->m_view.p(); + RiuFemResultTextBuilder textBuilder(geomView, (int)geomSelectionItem->m_gridIndex, (int)geomSelectionItem->m_cellIndex, geomView->currentTimeStep()); + textBuilder.setIntersectionPoint(geomSelectionItem->m_localIntersectionPoint); + + resultInfo = textBuilder.mainResultText(); + + pickInfo = textBuilder.topologyText(", "); + } + } + + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + mainWnd->statusBar()->showMessage(pickInfo); + mainWnd->setResultInfo(resultInfo); +} diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.h b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.h new file mode 100644 index 0000000000..9d6e4c9865 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +class RiuSelectionItem; +class RiuEclipseSelectionItem; +class RiuGeoMechSelectionItem; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiuSelectionChangedHandler +{ +public: + RiuSelectionChangedHandler(); + ~RiuSelectionChangedHandler(); + + void handleSelectionDeleted() const; + void handleItemAppended(const RiuSelectionItem* item) const; + void handleSetSelectedItem(const RiuSelectionItem* item) const; + +private: + void addCurveFromSelectionItem(const RiuSelectionItem* itemAdded) const; + void addCurveFromSelectionItem(const RiuEclipseSelectionItem* selectionItem) const; + void addCurveFromSelectionItem(const RiuGeoMechSelectionItem* selectionItem) const; + + void scheduleUpdateForAllVisibleViews() const; + void updateResultInfo(const RiuSelectionItem* itemAdded) const; +}; + diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.cpp b/ApplicationCode/UserInterface/RiuSelectionManager.cpp index 524ac234b1..8f778702c9 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionManager.cpp @@ -20,6 +20,25 @@ #include "RiuSelectionManager.h" #include "RimEclipseView.h" +#include "RimGeoMechView.h" + +#include "RiuSelectionChangedHandler.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionManager::RiuSelectionManager() + : m_notificationCenter(new RiuSelectionChangedHandler) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionManager::~RiuSelectionManager() +{ + delete m_notificationCenter; +} //-------------------------------------------------------------------------------------------------- /// @@ -41,25 +60,49 @@ void RiuSelectionManager::selectedItems(std::vector& items) c //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::setSelectedItems(const std::vector& items) +void RiuSelectionManager::appendItemToSelection(RiuSelectionItem* item) { - CVF_ASSERT(m_selection.size() == 0); + m_selection.push_back(item); - m_selection = items; + m_notificationCenter->handleItemAppended(item); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::appendItemToSelection(RiuSelectionItem* item) +void RiuSelectionManager::setSelectedItem(RiuSelectionItem* item) { + deleteAllItemsFromSelection(); + m_selection.push_back(item); + + m_notificationCenter->handleSetSelectedItem(item); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuSelectionManager::deleteAllItems() +{ + if (m_selection.size() == 0) return; + + deleteAllItemsFromSelection(); + + m_notificationCenter->handleSelectionDeleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuSelectionManager::isEmpty() const +{ + return m_selection.size() == 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSelectionManager::deleteAllItemsFromSelection() { for (size_t i = 0; i < m_selection.size(); i++) { @@ -72,18 +115,25 @@ void RiuSelectionManager::deleteAllItems() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RiuSelectionManager::isEmpty() const +RiuEclipseSelectionItem::RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, size_t nncIndex, cvf::Color3f color, cvf::StructGridInterface::FaceType face, const cvf::Vec3d& localIntersectionPoint) + : m_view(view), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex), + m_nncIndex(nncIndex), + m_color(color), + m_face(face), + m_localIntersectionPoint(localIntersectionPoint) { - return m_selection.size() == 0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuEclipseSelectionItem::RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color) +RiuGeoMechSelectionItem::RiuGeoMechSelectionItem(RimGeoMechView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color, const cvf::Vec3d& localIntersectionPoint) : m_view(view), m_gridIndex(gridIndex), m_cellIndex(cellIndex), - m_color(color) + m_color(color), + m_localIntersectionPoint(localIntersectionPoint) { } diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.h b/ApplicationCode/UserInterface/RiuSelectionManager.h index 397b1c5fdc..a975e56aa2 100644 --- a/ApplicationCode/UserInterface/RiuSelectionManager.h +++ b/ApplicationCode/UserInterface/RiuSelectionManager.h @@ -18,16 +18,20 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + #include "cafPdmPointer.h" #include "cvfBase.h" #include "cvfColor3.h" +#include "cvfStructGrid.h" #include +#include class RimEclipseView; - +class RiuSelectionChangedHandler; class RiuSelectionItem; +class RimGeoMechView; //================================================================================================== // @@ -37,27 +41,35 @@ class RiuSelectionItem; class RiuSelectionManager { public: + RiuSelectionManager(); + ~RiuSelectionManager(); + static RiuSelectionManager* instance(); // Returns selected items - // Selection manager owns the selection items and is responsible for delete + // Selection manager owns the selection items void selectedItems(std::vector& items) const; - // Set vector of items as selected items in SelectionManager - // SelectionManager takes ownership of the selection items - void setSelectedItems(const std::vector& items); - - // Append item to selected items in SelectionManager + // Append item to selected items // SelectionManager takes ownership of the item void appendItemToSelection(RiuSelectionItem* item); + // Set one selected item + // SelectionManager takes ownership of the item + void setSelectedItem(RiuSelectionItem* item); + // Deletes all items in the SelectionManager void deleteAllItems(); bool isEmpty() const; +private: + void deleteAllItemsFromSelection(); + private: std::vector < RiuSelectionItem* > m_selection; + + RiuSelectionChangedHandler* m_notificationCenter; }; @@ -79,7 +91,7 @@ class RiuSelectionItem RiuSelectionItem() {} virtual ~RiuSelectionItem() {}; - virtual RiuSelectionType type() = 0; + virtual RiuSelectionType type() const = 0; }; @@ -91,10 +103,12 @@ class RiuSelectionItem class RiuEclipseSelectionItem : public RiuSelectionItem { public: - explicit RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color); + explicit RiuEclipseSelectionItem(RimEclipseView* view, size_t gridIndex, size_t cellIndex, size_t nncIndex, + cvf::Color3f color, cvf::StructGridInterface::FaceType face, const cvf::Vec3d& localIntersectionPoint); + virtual ~RiuEclipseSelectionItem() {}; - virtual RiuSelectionType type() + virtual RiuSelectionType type() const { return ECLIPSE_SELECTION_OBJECT; } @@ -103,7 +117,34 @@ class RiuEclipseSelectionItem : public RiuSelectionItem caf::PdmPointer m_view; size_t m_gridIndex; size_t m_cellIndex; + size_t m_nncIndex; cvf::Color3f m_color; + cvf::StructGridInterface::FaceType m_face; + cvf::Vec3d m_localIntersectionPoint; }; +//================================================================================================== +// +// +// +//================================================================================================== +class RiuGeoMechSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuGeoMechSelectionItem(RimGeoMechView* view, size_t gridIndex, size_t cellIndex, cvf::Color3f color, const cvf::Vec3d& localIntersectionPoint); + virtual ~RiuGeoMechSelectionItem() {}; + + virtual RiuSelectionType type() const + { + return GEOMECH_SELECTION_OBJECT; + } + +public: + caf::PdmPointer m_view; + size_t m_gridIndex; + size_t m_cellIndex; + cvf::Color3f m_color; + cvf::Vec3d m_localIntersectionPoint; +}; + diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index ac39c34a8d..0015bc0cba 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -25,14 +25,12 @@ #include "Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h" #include "Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h" -#include "RigCaseCellResultsData.h" #include "RigCaseData.h" #include "RigFemPartCollection.h" #include "RigFemPartGrid.h" #include "RigGeoMechCaseData.h" #include "RigTimeHistoryResultAccessor.h" -#include "RigFemTimeHistoryResultAccessor.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" #include "RimEclipseCase.h" @@ -46,7 +44,6 @@ #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimGeoMechView.h" -#include "RimGeoMechView.h" #include "RimOilField.h" #include "RimProject.h" #include "RimView.h" @@ -55,12 +52,9 @@ #include "RimWellPath.h" #include "RimWellPathCollection.h" -#include "RiuFemResultTextBuilder.h" #include "RiuMainWindow.h" -#include "RiuResultTextBuilder.h" #include "RiuSelectionColors.h" #include "RiuSelectionManager.h" -#include "RiuTimeHistoryQwtPlot.h" #include "RiuViewer.h" #include "RivFemPartGeometryGenerator.h" @@ -347,7 +341,6 @@ void RiuViewerCommands::createSliceRangeFilter(int ijOrk) eclipseView->setSurfaceDrawstyle(); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -458,8 +451,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM wellPath = wellPathSourceInfo->wellPath(); } } - - if (firstNncHitPart && firstNncHitPart->sourceInfo()) { @@ -474,186 +465,55 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } } - - - // Compose a info text regarding the hit - - QString pickInfo = "No hits"; - QString resultInfo = ""; - - if (cellIndex != cvf::UNDEFINED_SIZE_T || nncIndex != cvf::UNDEFINED_SIZE_T) + if (cellIndex == cvf::UNDEFINED_SIZE_T) { - RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); - RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); - - if (eclipseView) - { - RiuResultTextBuilder textBuilder(eclipseView, gridIndex, cellIndex, eclipseView->currentTimeStep()); - textBuilder.setFace(face); - textBuilder.setNncIndex(nncIndex); - textBuilder.setIntersectionPoint(localIntersectionPoint); - - resultInfo = textBuilder.mainResultText(); - - pickInfo = textBuilder.topologyText(", "); - - addTimeHistoryCurve(eclipseView, gridIndex, cellIndex, keyboardModifiers); - } - else if (geomView) - { - RiuFemResultTextBuilder textBuilder(geomView, (int)gridIndex, (int)cellIndex, geomView->currentTimeStep()); - //textBuilder.setFace(face); - - textBuilder.setIntersectionPoint(localIntersectionPoint); - - resultInfo = textBuilder.mainResultText(); - - pickInfo = textBuilder.topologyText(", "); - - addTimeHistoryCurve(geomView, gridIndex, cellIndex, localIntersectionPoint, keyboardModifiers); - } + RiuSelectionManager::instance()->deleteAllItems(); } - - if (wellPath) + else { - pickInfo = QString("Well path hit: %1").arg(wellPath->name()); - } - - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (cellIndex == cvf::UNDEFINED_SIZE_T && - !(keyboardModifiers & Qt::ControlModifier)) - { - if (mainWnd->timeHistoryPlot()->isVisible()) + bool appendToSelection = false; + if (keyboardModifiers & Qt::ControlModifier) { - // Delete all curves if no cell is hit - mainWnd->timeHistoryPlot()->deleteAllCurves(); - - RiuSelectionManager::instance()->deleteAllItems(); - - m_reservoirView->scheduleCreateDisplayModelAndRedraw(); + appendToSelection = true; } - } - - mainWnd->statusBar()->showMessage(pickInfo); - mainWnd->setResultInfo(resultInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex, Qt::KeyboardModifiers keyboardModifiers) -{ - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (!mainWnd->timeHistoryPlot()->isVisible()) return; - - if (eclipseView->cellResult()->hasDynamicResult() && - eclipseView->eclipseCase() && - eclipseView->eclipseCase()->reservoirData()) - { - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(eclipseView->cellResult()->porosityModel()); - - size_t scalarIndexWithMaxTimeStepCount = cvf::UNDEFINED_SIZE_T; - eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->maxTimeStepCount(&scalarIndexWithMaxTimeStepCount); - std::vector timeStepDates = eclipseView->eclipseCase()->reservoirData()->results(porosityModel)->timeStepDates(scalarIndexWithMaxTimeStepCount); - - RigTimeHistoryResultAccessor timeHistResultAccessor(eclipseView->eclipseCase()->reservoirData(), gridIndex, cellIndex, eclipseView->cellResult()->scalarResultIndex(), porosityModel); - - QString curveName = eclipseView->eclipseCase()->caseUserDescription(); - curveName += ", "; - curveName += eclipseView->cellResult()->resultVariable(); - curveName += ", "; - curveName += QString("Grid index %1").arg(gridIndex); - curveName += ", "; - curveName += timeHistResultAccessor.topologyText(); - - std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); - - std::vector items; - RiuSelectionManager::instance()->selectedItems(items); - - bool isItemPartOfSelection = false; - for (size_t i = 0; i < items.size(); i++) + cvf::Color3f curveColor = RiuSelectionColors::curveColorFromTable(); + if (RiuSelectionManager::instance()->isEmpty() || !appendToSelection) { - RiuEclipseSelectionItem* eclSelItem = dynamic_cast(items[i]); - if (eclSelItem && - eclSelItem->m_view == eclipseView && - eclSelItem->m_gridIndex == gridIndex && - eclSelItem->m_cellIndex == cellIndex) - { - isItemPartOfSelection = true; - } + curveColor = RiuSelectionColors::singleCurveColor(); } - if (!isItemPartOfSelection) + RiuSelectionItem* selItem = NULL; { - if (!(keyboardModifiers & Qt::ControlModifier)) + RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + if (eclipseView) { - mainWnd->timeHistoryPlot()->deleteAllCurves(); - RiuSelectionManager::instance()->deleteAllItems(); + selItem = new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, nncIndex, curveColor, face, localIntersectionPoint); } - cvf::Color3f curveColor = RiuSelectionColors::curveColorFromTable(); - if (RiuSelectionManager::instance()->isEmpty()) + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + if (geomView) { - curveColor = RiuSelectionColors::singleCurveColor(); + selItem = new RiuGeoMechSelectionItem(geomView, gridIndex, cellIndex, curveColor, localIntersectionPoint); } - - RiuSelectionManager::instance()->appendItemToSelection(new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, curveColor)); - - mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, timeStepDates, timeHistoryValues); - - eclipseView->scheduleCreateDisplayModelAndRedraw(); } - } -} -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint, Qt::KeyboardModifiers keyboardModifiers) -{ - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (!mainWnd->timeHistoryPlot()->isVisible()) return; - - if (geoMechView && - geoMechView->cellResult() && - geoMechView->cellResult()->hasResult() && - geoMechView->geoMechCase() && - geoMechView->geoMechCase()->geoMechData()) - { - RigFemTimeHistoryResultAccessor timeHistResultAccessor(geoMechView->geoMechCase()->geoMechData(), geoMechView->cellResult->resultAddress(), gridIndex, cellIndex, localIntersectionPoint); - - QString curveName; - curveName.append(geoMechView->geoMechCase()->caseUserDescription() + ", "); - - caf::AppEnum resPosAppEnum = geoMechView->cellResult()->resultPositionType(); - curveName.append(resPosAppEnum.uiText() + ", "); - curveName.append(geoMechView->cellResult()->resultFieldUiName()+ ", ") ; - curveName.append(geoMechView->cellResult()->resultComponentUiName() + ":\n"); - curveName.append(timeHistResultAccessor.topologyText()); - - std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - std::vector frameTimes; - for (size_t i = 0; i < timeHistoryValues.size(); i++) + if (appendToSelection) { - frameTimes.push_back(i); + RiuSelectionManager::instance()->appendItemToSelection(selItem); } - - CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); - - cvf::Color3f curveColor = RiuSelectionColors::curveColorFromTable(); - - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - - if (!(keyboardModifiers & Qt::ControlModifier)) + else { - mainWnd->timeHistoryPlot()->deleteAllCurves(); - RiuSelectionManager::instance()->deleteAllItems(); + RiuSelectionManager::instance()->setSelectedItem(selItem); } + } - mainWnd->timeHistoryPlot()->addCurve(curveName, curveColor, frameTimes, timeHistoryValues); + if (wellPath) + { + QString pickInfo = QString("Well path hit: %1").arg(wellPath->name()); + + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + mainWnd->statusBar()->showMessage(pickInfo); } } diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index dcca840e92..9e6c9b80d2 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -63,8 +63,6 @@ private slots: void createSliceRangeFilter(int ijOrk); void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); void updateSelectionFromPickedPart(cvf::Part* part); - void addTimeHistoryCurve(RimEclipseView* eclipseView, size_t gridIndex, size_t cellIndex, Qt::KeyboardModifiers keyboardModifiers); - void addTimeHistoryCurve(RimGeoMechView* geoMechView, size_t gridIndex, size_t cellIndex, const cvf::Vec3d& localIntersectionPoint, Qt::KeyboardModifiers keyboardModifiers); size_t m_currentGridIdx; size_t m_currentCellIndex; From 6063ca1b54f5cdd55181c4f05fa80a9579c5304b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 11 Nov 2015 13:38:54 +0100 Subject: [PATCH 032/290] (#646) Show selected cells in geo mech view --- .../RivFemPartGeometryGenerator.cpp | 55 ++++++++++++++++++- .../RivFemPartGeometryGenerator.h | 2 + .../RivSingleCellPartGenerator.cpp | 35 +++++++++++- .../RivSingleCellPartGenerator.h | 9 ++- .../ProjectDataModel/RimEclipseView.cpp | 32 ++++------- .../ProjectDataModel/RimGeoMechView.cpp | 38 ++++++++++++- 6 files changed, 141 insertions(+), 30 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp index 1e18c0a359..52d31a408c 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp @@ -68,7 +68,6 @@ ref RivFemPartGeometryGenerator::generateSurface() //-------------------------------------------------------------------------------------------------- ref RivFemPartGeometryGenerator::createMeshDrawable() { - if (!(m_quadVertices.notNull() && m_quadVertices->size() != 0)) return NULL; ref geo = new DrawableGeo; @@ -265,3 +264,57 @@ void RivFemPartGeometryGenerator::setElementVisibility(const cvf::UByteArray* ce m_elmVisibility = cellVisibility; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivFemPartGeometryGenerator::createMeshDrawableFromSingleElement(const RigFemPart* part, size_t elmIdx) +{ + cvf::ref quadVertices; + + { + std::vector vertices; + + const std::vector& nodeCoordinates = part->nodes().coordinates; + + RigElementType eType = part->elementType(elmIdx); + int faceCount = RigFemTypes::elmentFaceCount(eType); + int elmQuadCount = 0; + + const int* elmNodeIndices = part->connectivities(elmIdx); + + for (int lfIdx = 0; lfIdx < faceCount; ++lfIdx) + { + int elmNeighbor = part->elementNeighbor(static_cast(elmIdx), lfIdx); + + int faceNodeCount = 0; + const int* localElmNodeIndicesForFace = RigFemTypes::localElmNodeIndicesForFace(eType, lfIdx, &faceNodeCount); + if (faceNodeCount == 4) + { + vertices.push_back(nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[0]]]); + vertices.push_back(nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[1]]]); + vertices.push_back(nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[2]]]); + vertices.push_back(nodeCoordinates[elmNodeIndices[localElmNodeIndicesForFace[3]]]); + } + else + { + // Handle triangles and 6 node and 8 node faces + } + } + + quadVertices = new cvf::Vec3fArray; + quadVertices->assign(vertices); + } + + if (!(quadVertices.notNull() && quadVertices->size() != 0)) return NULL; + + ref geo = new DrawableGeo; + geo->setVertexArray(quadVertices.p()); + + ref indices = lineIndicesFromQuadVertexArray(quadVertices.p()); + ref prim = new PrimitiveSetIndexedUInt(PT_LINES); + prim->setIndices(indices.p()); + + geo->addPrimitiveSet(prim.p()); + return geo; +} + diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h index 464628bd43..d9791721ae 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h @@ -64,6 +64,8 @@ class RivFemPartGeometryGenerator : public cvf::Object RivFemPartTriangleToElmMapper* triangleToElementMapper() { return m_triangleMapper.p();} + static cvf::ref createMeshDrawableFromSingleElement(const RigFemPart* grid, size_t elementIndex); + private: static cvf::ref lineIndicesFromQuadVertexArray(const cvf::Vec3fArray* vertexArray); diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp index 20aac2f185..289c86d5d0 100644 --- a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp @@ -20,6 +20,12 @@ #include "RivSingleCellPartGenerator.h" #include "RigCaseData.h" +#include "RigFemPartCollection.h" +#include "RigGeoMechCaseData.h" + +#include "RimGeoMechCase.h" + +#include "RivFemPartGeometryGenerator.h" #include "cafEffectGenerator.h" #include "cvfPart.h" @@ -33,7 +39,19 @@ RivSingleCellPartGenerator::RivSingleCellPartGenerator(RigCaseData* rigCaseData, size_t gridIndex, size_t cellIndex) : m_rigCaseData(rigCaseData), m_gridIndex(gridIndex), - m_cellIndex(cellIndex) + m_cellIndex(cellIndex), + m_geoMechCase(NULL) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivSingleCellPartGenerator::RivSingleCellPartGenerator(RimGeoMechCase* rimGeoMechCase, size_t gridIndex, size_t cellIndex) + : m_geoMechCase(rimGeoMechCase), + m_gridIndex(gridIndex), + m_cellIndex(cellIndex), + m_rigCaseData(NULL) { } @@ -56,6 +74,8 @@ cvf::ref RivSingleCellPartGenerator::createPart(const cvf::Color3f co part->setEffect(eff.p()); + part->setPriority(10000); + return part; } @@ -64,11 +84,20 @@ cvf::ref RivSingleCellPartGenerator::createPart(const cvf::Color3f co //-------------------------------------------------------------------------------------------------- cvf::ref RivSingleCellPartGenerator::createMeshDrawable() { - if (m_rigCaseData && - m_cellIndex != cvf::UNDEFINED_SIZE_T) + if (m_rigCaseData && m_cellIndex != cvf::UNDEFINED_SIZE_T) { return cvf::StructGridGeometryGenerator::createMeshDrawableFromSingleCell(m_rigCaseData->grid(m_gridIndex), m_cellIndex); } + else if (m_geoMechCase && m_cellIndex != cvf::UNDEFINED_SIZE_T) + { + CVF_ASSERT(m_geoMechCase->geoMechData()); + CVF_ASSERT(m_geoMechCase->geoMechData()->femParts()->partCount() > m_gridIndex); + + RigFemPart* femPart = m_geoMechCase->geoMechData()->femParts()->part(m_gridIndex); + CVF_ASSERT(femPart); + + return RivFemPartGeometryGenerator::createMeshDrawableFromSingleElement(femPart, m_cellIndex); + } return NULL; } diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h index 703860ca64..93a2fa370b 100644 --- a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.h @@ -28,6 +28,7 @@ namespace cvf } class RigCaseData; +class RimGeoMechCase; //================================================================================================== /// @@ -37,6 +38,7 @@ class RivSingleCellPartGenerator { public: RivSingleCellPartGenerator(RigCaseData* rigCaseData, size_t gridIndex, size_t cellIndex); + RivSingleCellPartGenerator(RimGeoMechCase* rimGeoMechCase, size_t gridIndex, size_t cellIndex); cvf::ref createPart(const cvf::Color3f color); @@ -44,7 +46,8 @@ class RivSingleCellPartGenerator cvf::ref createMeshDrawable(); private: - RigCaseData* m_rigCaseData; - size_t m_gridIndex; - size_t m_cellIndex; + RigCaseData* m_rigCaseData; + RimGeoMechCase* m_geoMechCase; + size_t m_gridIndex; + size_t m_cellIndex; }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 9d4ae8fda6..398cad5792 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -677,15 +677,6 @@ void RimEclipseView::updateCurrentTimeStep() { - // Actions related to highlight items in scene - // - // Removed highlight model by name - // Create new highlight model with name - // Create and add selected parts - // Modify with scaletransform() - // Add parts to model - // Add model to scene - cvf::String highlightModelName = "HighLightModel"; this->removeModelByName(frameScene, highlightModelName); @@ -698,25 +689,26 @@ void RimEclipseView::updateCurrentTimeStep() riuSelManager->selectedItems(items); for (size_t i = 0; i < items.size(); i++) { - RiuEclipseSelectionItem* eclipseSelItem = dynamic_cast(items[i]); - if (eclipseSelItem && - eclipseSelItem->m_view) + if (items[i]->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) { - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); + RiuEclipseSelectionItem* eclipseSelItem = static_cast(items[i]); + if (eclipseSelItem && + eclipseSelItem->m_view) + { + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); - RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); + RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); - cvf::ref part = partGen.createPart(eclipseSelItem->m_color); - part->setTransform(this->scaleTransform()); - part->setPriority(10000); + cvf::ref part = partGen.createPart(eclipseSelItem->m_color); + part->setTransform(this->scaleTransform()); - highlightModelBasicList->addPart(part.p()); + highlightModelBasicList->addPart(part.p()); + } } } highlightModelBasicList->updateBoundingBoxesRecursive(); - frameScene->addModel(highlightModelBasicList.p()); } } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 2b1482ce44..a08e71d59a 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -34,18 +34,23 @@ #include "RimGeoMechCellColors.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimLegendConfig.h" +#include "RimViewLinker.h" #include "RiuMainWindow.h" +#include "RiuSelectionManager.h" #include "RiuViewer.h" #include "RivGeoMechPartMgr.h" #include "RivGeoMechPartMgrCache.h" #include "RivGeoMechVizLogic.h" +#include "RivSingleCellPartGenerator.h" #include "cafCadNavigation.h" #include "cafCeetronPlusNavigation.h" #include "cafFrameAnimationControl.h" +#include "cafPdmUiTreeOrdering.h" #include "cafProgressInfo.h" + #include "cvfModelBasicList.h" #include "cvfOverlayScalarMapperLegend.h" #include "cvfPart.h" @@ -54,9 +59,6 @@ #include "cvfqtUtils.h" #include -#include "RimViewLinker.h" -#include "cafPdmUiTreeOrdering.h" - CAF_PDM_SOURCE_INIT(RimGeoMechView, "GeoMechView"); @@ -282,6 +284,36 @@ void RimGeoMechView::updateCurrentTimeStep() femBBox, scaleTransform()); frameScene->addModel(wellPathModel.p()); + + { + cvf::String highlightModelName = "HighLightModel"; + cvf::ref highlightModelBasicList = new cvf::ModelBasicList; + highlightModelBasicList->setName(highlightModelName); + + RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + std::vector items; + riuSelManager->selectedItems(items); + for (size_t i = 0; i < items.size(); i++) + { + if (items[i]->type() == RiuSelectionItem::GEOMECH_SELECTION_OBJECT) + { + RiuGeoMechSelectionItem* geomSelItem = static_cast(items[i]); + if (geomSelItem && + geomSelItem->m_view && + geomSelItem->m_view->geoMechCase()) + { + RivSingleCellPartGenerator partGen(geomSelItem->m_view->geoMechCase(), geomSelItem->m_gridIndex, geomSelItem->m_cellIndex); + cvf::ref part = partGen.createPart(geomSelItem->m_color); + part->setTransform(this->scaleTransform()); + + highlightModelBasicList->addPart(part.p()); + } + } + } + + highlightModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(highlightModelBasicList.p()); + } } } From 6f4a4e16c68b074ee61a2ca213978d5a10ac7b75 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 11 Nov 2015 14:07:21 +0100 Subject: [PATCH 033/290] (#638) Changed title to "Result Plot" and renamed files --- ApplicationCode/CMakeLists.txt | 4 ++-- .../UserInterface/RiuMainWindow.cpp | 14 +++++++------- ApplicationCode/UserInterface/RiuMainWindow.h | 6 +++--- ...HistoryQwtPlot.cpp => RiuResultQwtPlot.cpp} | 18 +++++++++--------- ...TimeHistoryQwtPlot.h => RiuResultQwtPlot.h} | 6 +++--- .../RiuSelectionChangedHandler.cpp | 10 +++++----- 6 files changed, 29 insertions(+), 29 deletions(-) rename ApplicationCode/UserInterface/{RiuTimeHistoryQwtPlot.cpp => RiuResultQwtPlot.cpp} (90%) rename ApplicationCode/UserInterface/{RiuTimeHistoryQwtPlot.h => RiuResultQwtPlot.h} (92%) diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 5486f996b1..f4ef776cee 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -90,8 +90,8 @@ set( USER_INTERFACE_FILES UserInterface/RiuWellLogTrack.h UserInterface/RiuProjectPropertyView.h UserInterface/RiuProjectPropertyView.cpp - UserInterface/RiuTimeHistoryQwtPlot.h - UserInterface/RiuTimeHistoryQwtPlot.cpp + UserInterface/RiuResultQwtPlot.h + UserInterface/RiuResultQwtPlot.cpp UserInterface/RiuSelectionManager.h UserInterface/RiuSelectionManager.cpp UserInterface/RiuSelectionColors.h diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index c3a4c07cfa..457b983934 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -58,7 +58,7 @@ #include "RiuProcessMonitor.h" #include "RiuProjectPropertyView.h" #include "RiuResultInfoPanel.h" -#include "RiuTimeHistoryQwtPlot.h" +#include "RiuResultQwtPlot.h" #include "RiuTreeViewEventFilter.h" #include "RiuViewer.h" #include "RiuWellImportWizard.h" @@ -182,7 +182,7 @@ void RiuMainWindow::cleanupGuiBeforeProjectClose() setPdmRoot(NULL); setResultInfo(""); - m_timeHistoryQwtPlot->deleteAllCurves(); + m_resultQwtPlot->deleteAllCurves(); if (m_pdmUiPropertyView) { @@ -665,11 +665,11 @@ void RiuMainWindow::createDockPanels() } { - QDockWidget* dockPanel = new QDockWidget("Time History Plot", this); + QDockWidget* dockPanel = new QDockWidget("Result Plot", this); dockPanel->setObjectName("dockTimeHistoryPanel"); dockPanel->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea); - m_timeHistoryQwtPlot = new RiuTimeHistoryQwtPlot(dockPanel); - dockPanel->setWidget(m_timeHistoryQwtPlot); + m_resultQwtPlot = new RiuResultQwtPlot(dockPanel); + dockPanel->setWidget(m_resultQwtPlot); addDockWidget(Qt::RightDockWidgetArea, dockPanel); } @@ -1170,9 +1170,9 @@ QMdiSubWindow* RiuMainWindow::findMdiSubWindow(QWidget* viewer) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuTimeHistoryQwtPlot* RiuMainWindow::timeHistoryPlot() +RiuResultQwtPlot* RiuMainWindow::resultPlot() { - return m_timeHistoryQwtPlot; + return m_resultQwtPlot; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index d2755cffd5..88d034a6ca 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -42,7 +42,7 @@ class RiuProcessMonitor; class RiuResultInfoPanel; class RiuViewer; class RiuWellLogPlot; -class RiuTimeHistoryQwtPlot; +class RiuResultQwtPlot; namespace caf { @@ -113,7 +113,7 @@ class RiuMainWindow : public QMainWindow bool isAnyMdiSubWindowVisible(); QMdiSubWindow* findMdiSubWindow(QWidget* viewer); - RiuTimeHistoryQwtPlot* timeHistoryPlot(); + RiuResultQwtPlot* resultPlot(); protected: virtual void closeEvent(QCloseEvent* event); @@ -201,7 +201,7 @@ class RiuMainWindow : public QMainWindow RiuResultInfoPanel* m_resultInfoPanel; RiuProcessMonitor* m_processMonitor; - RiuTimeHistoryQwtPlot* m_timeHistoryQwtPlot; + RiuResultQwtPlot* m_resultQwtPlot; QMenu* m_windowMenu; diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp similarity index 90% rename from ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp rename to ApplicationCode/UserInterface/RiuResultQwtPlot.cpp index f672f21ce2..d7f955910a 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RiuTimeHistoryQwtPlot.h" +#include "RiuResultQwtPlot.h" #include "RigCurveDataTools.h" @@ -39,7 +39,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) +RiuResultQwtPlot::RiuResultQwtPlot(QWidget* parent) : QwtPlot(parent) { m_grid = new QwtPlotGrid; @@ -51,7 +51,7 @@ RiuTimeHistoryQwtPlot::RiuTimeHistoryQwtPlot(QWidget* parent) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() +RiuResultQwtPlot::~RiuResultQwtPlot() { deleteAllCurves(); @@ -62,7 +62,7 @@ RiuTimeHistoryQwtPlot::~RiuTimeHistoryQwtPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& dateTimes, const std::vector& timeHistoryValues) +void RiuResultQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& dateTimes, const std::vector& timeHistoryValues) { CVF_ASSERT(dateTimes.size() == timeHistoryValues.size()); @@ -106,7 +106,7 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3 //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& frameTimes, const std::vector& timeHistoryValues) +void RiuResultQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& frameTimes, const std::vector& timeHistoryValues) { std::vector dateTimes; @@ -121,7 +121,7 @@ void RiuTimeHistoryQwtPlot::addCurve(const QString& curveName, const cvf::Color3 //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::deleteAllCurves() +void RiuResultQwtPlot::deleteAllCurves() { for (size_t i = 0; i < m_plotCurves.size(); i++) { @@ -135,7 +135,7 @@ void RiuTimeHistoryQwtPlot::deleteAllCurves() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QSize RiuTimeHistoryQwtPlot::sizeHint() const +QSize RiuResultQwtPlot::sizeHint() const { return QSize(0, 0); } @@ -143,7 +143,7 @@ QSize RiuTimeHistoryQwtPlot::sizeHint() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QSize RiuTimeHistoryQwtPlot::minimumSizeHint() const +QSize RiuResultQwtPlot::minimumSizeHint() const { return QSize(0, 0); } @@ -151,7 +151,7 @@ QSize RiuTimeHistoryQwtPlot::minimumSizeHint() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuTimeHistoryQwtPlot::setDefaults() +void RiuResultQwtPlot::setDefaults() { QPalette newPalette(palette()); newPalette.setColor(QPalette::Background, Qt::white); diff --git a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h b/ApplicationCode/UserInterface/RiuResultQwtPlot.h similarity index 92% rename from ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h rename to ApplicationCode/UserInterface/RiuResultQwtPlot.h index 4a7ad625da..687aab0cc9 100644 --- a/ApplicationCode/UserInterface/RiuTimeHistoryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuResultQwtPlot.h @@ -34,11 +34,11 @@ namespace cvf // // //================================================================================================== -class RiuTimeHistoryQwtPlot : public QwtPlot +class RiuResultQwtPlot : public QwtPlot { public: - RiuTimeHistoryQwtPlot(QWidget* parent = NULL); - virtual ~RiuTimeHistoryQwtPlot(); + RiuResultQwtPlot(QWidget* parent = NULL); + virtual ~RiuResultQwtPlot(); void addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& dateTimes, const std::vector& timeHistoryValues); void addCurve(const QString& curveName, const cvf::Color3f& curveColor, const std::vector& frameTimes, const std::vector& timeHistoryValues); diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index 33019f4437..b6fe284201 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -39,7 +39,7 @@ #include "RiuMainWindow.h" #include "RiuResultTextBuilder.h" #include "RiuSelectionManager.h" -#include "RiuTimeHistoryQwtPlot.h" +#include "RiuResultQwtPlot.h" #include @@ -65,7 +65,7 @@ RiuSelectionChangedHandler::~RiuSelectionChangedHandler() //-------------------------------------------------------------------------------------------------- void RiuSelectionChangedHandler::handleSelectionDeleted() const { - RiuMainWindow::instance()->timeHistoryPlot()->deleteAllCurves(); + RiuMainWindow::instance()->resultPlot()->deleteAllCurves(); updateResultInfo(NULL); @@ -89,7 +89,7 @@ void RiuSelectionChangedHandler::handleItemAppended(const RiuSelectionItem* item //-------------------------------------------------------------------------------------------------- void RiuSelectionChangedHandler::handleSetSelectedItem(const RiuSelectionItem* item) const { - RiuMainWindow::instance()->timeHistoryPlot()->deleteAllCurves(); + RiuMainWindow::instance()->resultPlot()->deleteAllCurves(); handleItemAppended(item); } @@ -126,7 +126,7 @@ void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuEclipseSelec std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); CVF_ASSERT(timeStepDates.size() == timeHistoryValues.size()); - RiuMainWindow::instance()->timeHistoryPlot()->addCurve(curveName, eclipseSelectionItem->m_color, timeStepDates, timeHistoryValues); + RiuMainWindow::instance()->resultPlot()->addCurve(curveName, eclipseSelectionItem->m_color, timeStepDates, timeHistoryValues); } } @@ -164,7 +164,7 @@ void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuGeoMechSelec CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); - RiuMainWindow::instance()->timeHistoryPlot()->addCurve(curveName, geomSelectionItem->m_color, frameTimes, timeHistoryValues); + RiuMainWindow::instance()->resultPlot()->addCurve(curveName, geomSelectionItem->m_color, frameTimes, timeHistoryValues); } } From adc777083d16e7eb5dd2adca71cbca25671fefab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 11 Nov 2015 16:21:07 +0100 Subject: [PATCH 034/290] (#642) Date in animation progress. Not removed from Info text yet --- .../Rim3dOverlayInfoConfig.cpp | 8 +-- ApplicationCode/ProjectDataModel/RimCase.h | 5 +- .../ProjectDataModel/RimEclipseCase.cpp | 51 ++++++++++++------- .../ProjectDataModel/RimEclipseCase.h | 3 +- .../ProjectDataModel/RimEclipseView.h | 3 +- .../ProjectDataModel/RimGeoMechCase.cpp | 10 ++++ .../ProjectDataModel/RimGeoMechCase.h | 2 +- .../ProjectDataModel/RimGeoMechView.h | 2 +- ApplicationCode/UserInterface/RiuViewer.cpp | 3 ++ 9 files changed, 59 insertions(+), 28 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 1ce6ef516f..98d072eb3a 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -338,8 +338,8 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) || reservoirView->cellResult()->isTernarySaturationSelected()) { int currentTimeStep = reservoirView->currentTimeStep(); - QDateTime date = reservoirView->currentGridCellResults()->cellResults()->timeStepDate(0, currentTimeStep); - infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(date.toString("dd.MMM yyyy")); + QString dateString = reservoirView->ownerCase()->timeStepName(currentTimeStep); + infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(dateString); } reservoirView->viewer()->setInfoText(infoText); @@ -480,8 +480,8 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) } { int currentTimeStep = geoMechView->currentTimeStep(); - QString stepName = QString::fromStdString(caseData->femPartResults()->stepNames()[currentTimeStep]); - infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(stepName); + QString dateString = geoMechView->ownerCase()->timeStepName(currentTimeStep); + infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(dateString); } } diff --git a/ApplicationCode/ProjectDataModel/RimCase.h b/ApplicationCode/ProjectDataModel/RimCase.h index c389b97591..9a8c8519b5 100644 --- a/ApplicationCode/ProjectDataModel/RimCase.h +++ b/ApplicationCode/ProjectDataModel/RimCase.h @@ -41,14 +41,13 @@ class RimCase : public caf::PdmObject virtual caf::PdmFieldHandle* userDescriptionField() { return &caseUserDescription; } - virtual QStringList timeStepStrings() { return QStringList(); } + virtual QStringList timeStepStrings() = 0; + virtual QString timeStepName(int frameIdx) = 0; protected: static QString relocateFile(const QString& fileName, const QString& newProjectPath, const QString& oldProjectPath, bool* foundFile, std::vector* searchedPaths); - private: - }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp index 65f31910fc..8ec0d7938c 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp @@ -52,7 +52,7 @@ CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimEclipseCase, "RimReservoir"); //------------------------------------------------------------------------------------------------ /// //-------------------------------------------------------------------------------------------------- -RimEclipseCase::RimEclipseCase() +RimEclipseCase::RimEclipseCase() { CAF_PDM_InitFieldNoDefault(&reservoirViews, "ReservoirViews", "", "", "", ""); reservoirViews.uiCapability()->setUiHidden(true); @@ -428,27 +428,44 @@ QStringList RimEclipseCase::timeStepStrings() { QStringList stringList; - std::vector timeStepDates = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepDates(0); + int timeStepCount = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepCount(0); + for (size_t i = 0; i < timeStepCount; i++) + { + stringList += this->timeStepName(i); + } + + return stringList; +} - bool showHoursAndMinutes = false; - for (size_t i = 0; i < timeStepDates.size(); i++) +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +QString RimEclipseCase::timeStepName(int frameIdx) +{ + if (m_timeStepFormatString.isEmpty()) { - if (timeStepDates[i].time().hour() != 0.0 || timeStepDates[i].time().minute() != 0.0) + std::vector timeStepDates = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepDates(0); + + bool hasHrsAndMinutesInTimesteps = false; + for (size_t i = 0; i < timeStepDates.size(); i++) { - showHoursAndMinutes = true; + if (timeStepDates[i].time().hour() != 0.0 || timeStepDates[i].time().minute() != 0.0) + { + hasHrsAndMinutesInTimesteps = true; + break; + } } - } - QString formatString = "dd.MMM yyyy"; - if (showHoursAndMinutes) - { - formatString += " - hh:mm"; + m_timeStepFormatString = "dd.MMM yyyy"; + if (hasHrsAndMinutesInTimesteps) + { + m_timeStepFormatString += " - hh:mm"; + } } - for (size_t i = 0; i < timeStepDates.size(); i++) - { - stringList += timeStepDates[i].toString(formatString); - } - return stringList; -} + QDateTime date = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepDate(0,frameIdx); + return date.toString(m_timeStepFormatString); + +} \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.h b/ApplicationCode/ProjectDataModel/RimEclipseCase.h index 6c1e4d091b..c3be567624 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.h @@ -86,6 +86,7 @@ class RimEclipseCase : public RimCase virtual std::vector views(); virtual QStringList timeStepStrings(); + virtual QString timeStepName(int frameIdx); // Overridden methods from PdmObject public: @@ -99,13 +100,13 @@ class RimEclipseCase : public RimCase void computeCachedData(); void setReservoirData(RigCaseData* eclipseCase); - private: cvf::ref m_rigEclipseCase; private: caf::PdmChildField m_matrixModelResults; caf::PdmChildField m_fractureModelResults; + QString m_timeStepFormatString; // Obsolete fields protected: diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 4091a424d7..dd2cfeaad3 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -110,6 +110,7 @@ class RimEclipseView : public RimView void setEclipseCase(RimEclipseCase* reservoir); RimEclipseCase* eclipseCase(); + virtual RimCase* ownerCase(); // Display model generation @@ -165,10 +166,10 @@ class RimEclipseView : public RimView void clampCurrentTimestep(); - virtual RimCase* ownerCase(); virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); + caf::PdmChildField m_propertyFilterCollection; caf::PdmPointer m_overridePropertyFilterCollection; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index 9dbefc6a3b..17a8230f17 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -169,3 +169,13 @@ QStringList RimGeoMechCase::timeStepStrings() return stringList; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechCase::timeStepName(int frameIdx) +{ + std::vector stepNames = geoMechData()->femPartResults()->stepNames(); + + return QString::fromStdString(stepNames[frameIdx]); +} diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h index 49eba64147..a5304f29b9 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h @@ -57,7 +57,7 @@ class RimGeoMechCase : public RimCase virtual std::vector views(); virtual QStringList timeStepStrings(); - + virtual QString timeStepName(int frameIdx); // Fields: caf::PdmChildArrayField geoMechViews; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index 1e5d7407e0..aed5085647 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -60,6 +60,7 @@ class RimGeoMechView : public RimView void setGeoMechCase(RimGeoMechCase* gmCase); RimGeoMechCase* geoMechCase(); + virtual RimCase* ownerCase(); virtual void loadDataAndUpdate(); @@ -96,7 +97,6 @@ class RimGeoMechView : public RimView virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void initAfterRead(); - virtual RimCase* ownerCase(); virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index c913390f03..69a6cc8f41 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include "RimCase.h" using cvf::ManipulatorTrackball; @@ -332,6 +333,8 @@ void RiuViewer::paintOverlayItems(QPainter* painter) if (showAnimBar && m_showAnimProgress) { + QString stepName = m_reservoirView->ownerCase()->timeStepName(currentFrameIndex()); + m_animationProgress->setFormat("Time Step: %v/%m " + stepName); m_animationProgress->setMinimum(0); m_animationProgress->setMaximum(static_cast(frameCount()) - 1); m_animationProgress->setValue(currentFrameIndex()); From d8ea2816c300710e7214e33dded2e44c902aba40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 11 Nov 2015 17:42:30 +0100 Subject: [PATCH 035/290] (#647) Made the width of 3dinfo box minimum 275 wide --- ApplicationCode/UserInterface/RiuViewer.cpp | 1 + ApplicationCode/UserInterface/RiuViewer.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 69a6cc8f41..43a66055e3 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -112,6 +112,7 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) m_InfoLabel = new QLabel(); m_InfoLabel->setPalette(p); m_InfoLabel->setFrameShape(QFrame::Box); + m_InfoLabel->setMinimumWidth(275); m_showInfoText = true; // Version info label diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index bdfe58dc98..81ad64224a 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -91,7 +91,7 @@ public slots: QLabel* m_InfoLabel; QLabel* m_versionInfoLabel; - bool m_showInfoText;; + bool m_showInfoText; QProgressBar* m_animationProgress; bool m_showAnimProgress; From a57b27b6c07809d830cf2fd551ae7f27257eb369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 11 Nov 2015 17:44:00 +0100 Subject: [PATCH 036/290] (#643) (#642) Overhauled the 3D info panel. New option. Better layout. --- .../Rim3dOverlayInfoConfig.cpp | 147 +++++++++--------- .../ProjectDataModel/Rim3dOverlayInfoConfig.h | 10 +- 2 files changed, 77 insertions(+), 80 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 98d072eb3a..5735a8d55b 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -85,8 +85,9 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitField(&active, "Active", true, "Active", "", "", ""); active.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&showInfoText, "ShowInfoText", true, "Info Text", "", "", ""); CAF_PDM_InitField(&showAnimProgress, "ShowAnimProgress", true, "Animation progress", "", "", ""); + CAF_PDM_InitField(&showCaseInfo, "ShowInfoText", true, "Case Info", "", "", ""); + CAF_PDM_InitField(&showResultInfo, "ShowResultInfo", true, "Result Info", "", "", ""); CAF_PDM_InitField(&showHistogram, "ShowHistogram", true, "Histogram", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); @@ -142,7 +143,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() return; } - m_viewDef->viewer()->showInfoText(showInfoText()); + m_viewDef->viewer()->showInfoText(showCaseInfo() || showResultInfo()); m_viewDef->viewer()->showHistogram(false); m_viewDef->viewer()->showAnimationProgress(showAnimProgress()); @@ -173,36 +174,36 @@ void Rim3dOverlayInfoConfig::setReservoirView(RimView* ownerReservoirView) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) +void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * eclipseView) { double min = HUGE_VAL, max = HUGE_VAL; double p10 = HUGE_VAL, p90 = HUGE_VAL; double mean = HUGE_VAL; const std::vector* histogram = NULL; - bool isResultsInfoRelevant = reservoirView->hasUserRequestedAnimation() && reservoirView->cellResult()->hasResult(); + bool isResultsInfoRelevant = eclipseView->hasUserRequestedAnimation() && eclipseView->cellResult()->hasResult(); - if (showHistogram() || showInfoText()) + if (showHistogram() || showResultInfo()) { if (isResultsInfoRelevant) { - size_t scalarIndex = reservoirView->cellResult()->scalarResultIndex(); + size_t scalarIndex = eclipseView->cellResult()->scalarResultIndex(); if (m_statisticsCellRange == ALL_CELLS) { if (m_statisticsTimeRange == ALL_TIMESTEPS) { - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); - histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); + eclipseView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, min, max); + eclipseView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, p10, p90); + eclipseView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, mean); + histogram = &(eclipseView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex)); } else if (m_statisticsTimeRange == CURRENT_TIMESTEP ) { - int timeStepIdx = reservoirView->currentTimeStep(); - reservoirView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); - reservoirView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); - reservoirView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); - histogram = &(reservoirView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex, timeStepIdx)); + int timeStepIdx = eclipseView->currentTimeStep(); + eclipseView->currentGridCellResults()->cellResults()->minMaxCellScalarValues(scalarIndex, timeStepIdx, min, max); + eclipseView->currentGridCellResults()->cellResults()->p10p90CellScalarValues(scalarIndex, timeStepIdx, p10, p90); + eclipseView->currentGridCellResults()->cellResults()->meanCellScalarValues(scalarIndex, timeStepIdx, mean); + histogram = &(eclipseView->currentGridCellResults()->cellResults()->cellScalarValuesHistogram(scalarIndex, timeStepIdx)); } else { @@ -223,7 +224,7 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) } else if (m_statisticsTimeRange == CURRENT_TIMESTEP) { - int currentTimeStep = reservoirView->currentTimeStep(); + int currentTimeStep = eclipseView->currentTimeStep(); m_visibleCellStatistics->meanCellScalarValues(currentTimeStep, mean); m_visibleCellStatistics->minMaxCellScalarValues(currentTimeStep, min, max); m_visibleCellStatistics->p10p90CellScalarValues(currentTimeStep, p10, p90); @@ -234,7 +235,9 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) } } - if (showInfoText()) + QString infoText; + + if (showCaseInfo()) { QString caseName; QString totCellCount; @@ -242,64 +245,61 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) QString fractureActiveCellCount; QString iSize, jSize, kSize; QString zScale; - QString propName; - QString cellEdgeName; - QString faultCellResultMapping; - - if (reservoirView->eclipseCase() && reservoirView->eclipseCase()->reservoirData() && reservoirView->eclipseCase()->reservoirData()->mainGrid()) + if (eclipseView->eclipseCase() && eclipseView->eclipseCase()->reservoirData() && eclipseView->eclipseCase()->reservoirData()->mainGrid()) { - caseName = reservoirView->eclipseCase()->caseUserDescription(); - totCellCount = QString::number(reservoirView->eclipseCase()->reservoirData()->mainGrid()->cells().size()); - size_t mxActCellCount = reservoirView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)->reservoirActiveCellCount(); - size_t frActCellCount = reservoirView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS)->reservoirActiveCellCount(); + caseName = eclipseView->eclipseCase()->caseUserDescription(); + totCellCount = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->cells().size()); + size_t mxActCellCount = eclipseView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)->reservoirActiveCellCount(); + size_t frActCellCount = eclipseView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS)->reservoirActiveCellCount(); if (frActCellCount > 0) activeCellCountText += "Matrix : "; activeCellCountText += QString::number(mxActCellCount); if (frActCellCount > 0) activeCellCountText += " Fracture : " + QString::number(frActCellCount); - iSize = QString::number(reservoirView->eclipseCase()->reservoirData()->mainGrid()->cellCountI()); - jSize = QString::number(reservoirView->eclipseCase()->reservoirData()->mainGrid()->cellCountJ()); - kSize = QString::number(reservoirView->eclipseCase()->reservoirData()->mainGrid()->cellCountK()); + iSize = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->cellCountI()); + jSize = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->cellCountJ()); + kSize = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->cellCountK()); - zScale = QString::number(reservoirView->scaleZ()); + zScale = QString::number(eclipseView->scaleZ()); - propName = reservoirView->cellResult()->resultVariable(); - cellEdgeName = reservoirView->cellEdgeResult()->resultVariable(); } - QString infoText = QString( + infoText += QString( "

-- %1 --

" "Cell count. Total: %2 Active: %3
" "Main Grid I,J,K: %4, %5, %6 Z-Scale: %7
").arg(caseName, totCellCount, activeCellCountText, iSize, jSize, kSize, zScale); + } - if (reservoirView->cellResult()->isTernarySaturationSelected()) + if (showResultInfo()) + { + + if (eclipseView->cellResult()->isTernarySaturationSelected()) { + QString propName = eclipseView->cellResult()->resultVariable(); infoText += QString("Cell Property: %1 ").arg(propName); } if (isResultsInfoRelevant) { + QString propName = eclipseView->cellResult()->resultVariable(); infoText += QString("Cell Property: %1 ").arg(propName); - // Wait until regression tests confirm new statisticks is ok : - //infoText += QString("
Statistics for: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); - - + infoText += QString("
Statistics: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); infoText += QString("" "" "" "
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
").arg(min).arg(p10).arg(mean).arg(p90).arg(max); - if (reservoirView->faultResultSettings()->hasValidCustomResult()) + if (eclipseView->faultResultSettings()->hasValidCustomResult()) { QString faultMapping; - bool isShowingGrid = reservoirView->faultCollection()->isGridVisualizationMode(); + bool isShowingGrid = eclipseView->faultCollection()->isGridVisualizationMode(); if (!isShowingGrid) { - if (reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_BACK_FACE_CULLING) + if (eclipseView->faultCollection()->faultResult() == RimFaultCollection::FAULT_BACK_FACE_CULLING) { faultMapping = "Cells behind fault"; } - else if (reservoirView->faultCollection()->faultResult() == RimFaultCollection::FAULT_FRONT_FACE_CULLING) + else if (eclipseView->faultCollection()->faultResult() == RimFaultCollection::FAULT_FRONT_FACE_CULLING) { faultMapping = "Cells in front of fault"; } @@ -314,44 +314,37 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * reservoirView) } infoText += QString("Fault results: %1
").arg(faultMapping); - - infoText += QString("Fault Property: %1
").arg(reservoirView->faultResultSettings()->customFaultResult()->resultVariable()); + infoText += QString("Fault Property: %1
").arg(eclipseView->faultResultSettings()->customFaultResult()->resultVariable()); } } - else - { - infoText += "
"; - } - - if (reservoirView->hasUserRequestedAnimation() && reservoirView->cellEdgeResult()->hasResult()) + if (eclipseView->hasUserRequestedAnimation() && eclipseView->cellEdgeResult()->hasResult()) { double min, max; - reservoirView->cellEdgeResult()->minMaxCellEdgeValues(min, max); - infoText += QString("Cell Edge Property: %1

Min: %2 Max: %3
").arg(cellEdgeName).arg(min).arg(max); - - } + QString cellEdgeName = eclipseView->cellEdgeResult()->resultVariable(); + eclipseView->cellEdgeResult()->minMaxCellEdgeValues(min, max); + infoText += QString("Cell Edge Property: %1 ").arg(cellEdgeName); + infoText += QString("" + "" + "" + "
Min Max
%1 %2
").arg(min).arg(max); - if (reservoirView->cellResult()->hasDynamicResult() - || reservoirView->propertyFilterCollection()->hasActiveDynamicFilters() - || reservoirView->wellCollection()->hasVisibleWellPipes() - || reservoirView->cellResult()->isTernarySaturationSelected()) - { - int currentTimeStep = reservoirView->currentTimeStep(); - QString dateString = reservoirView->ownerCase()->timeStepName(currentTimeStep); - infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(dateString); } + + } - reservoirView->viewer()->setInfoText(infoText); + if (!infoText.isEmpty()) + { + eclipseView->viewer()->setInfoText(infoText); } if (showHistogram()) { if (isResultsInfoRelevant) { - reservoirView->viewer()->showHistogram(true); - reservoirView->viewer()->setHistogram(min, max, *histogram); - reservoirView->viewer()->setHistogramPercentiles(p10, p90, mean); + eclipseView->viewer()->showHistogram(true); + eclipseView->viewer()->setHistogram(min, max, *histogram); + eclipseView->viewer()->setHistogramPercentiles(p10, p90, mean); } } } @@ -372,7 +365,7 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) double mean = HUGE_VAL; const std::vector* histogram = NULL; - if (showInfoText() || showHistogram()) + if (showResultInfo() || showHistogram()) { if (isResultsInfoRelevant) { @@ -425,9 +418,10 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) // Compose text - if (showInfoText()) + QString infoText; + + if (showCaseInfo()) { - QString infoText; RigFemPartCollection* femParts = caseData ? caseData->femParts() : NULL; @@ -441,6 +435,10 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) "

-- %1 --

" "Cell count: %2 Z-Scale: %3
").arg(caseName, cellCount, zScale); } + } + + if (showResultInfo()) + { if (isResultsInfoRelevant) { @@ -470,7 +468,7 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); } { - + infoText += QString("
Statistics: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); infoText += QString("" "" "" @@ -478,14 +476,11 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) } - { - int currentTimeStep = geoMechView->currentTimeStep(); - QString dateString = geoMechView->ownerCase()->timeStepName(currentTimeStep); - infoText += QString("Time Step: %1 Time: %2").arg(currentTimeStep).arg(dateString); - } } + } - + if (!infoText.isEmpty()) + { geoMechView->viewer()->setInfoText(infoText); } diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h index ef291904e4..330ea0a06a 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h @@ -49,10 +49,6 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject void setReservoirView(RimView* ownerView); void setPosition(cvf::Vec2ui position); - caf::PdmField active; - caf::PdmField showInfoText; - caf::PdmField showAnimProgress; - caf::PdmField showHistogram; enum StatisticsTimeRangeType { @@ -74,6 +70,12 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject void updateEclipse3DInfo(RimEclipseView * reservoirView); void updateGeoMech3DInfo(RimGeoMechView * geoMechView); + caf::PdmField active; + caf::PdmField showAnimProgress; + caf::PdmField showCaseInfo; + caf::PdmField showResultInfo; + caf::PdmField showHistogram; + caf::PdmField > m_statisticsTimeRange; caf::PdmField > m_statisticsCellRange; From 8b8fd51862a71310e59fdf87ec43f11995c9d94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 12 Nov 2015 10:24:21 +0100 Subject: [PATCH 037/290] Created baseclass for PropertyFilterCollections --- .../ProjectDataModel/CMakeLists_files.cmake | 2 + .../RimEclipsePropertyFilterCollection.cpp | 55 ----------- .../RimEclipsePropertyFilterCollection.h | 17 ++-- .../RimGeoMechPropertyFilterCollection.cpp | 55 ----------- .../RimGeoMechPropertyFilterCollection.h | 8 +- .../RimPropertyFilterCollection.cpp | 99 +++++++++++++++++++ .../RimPropertyFilterCollection.h | 53 ++++++++++ 7 files changed, 164 insertions(+), 125 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index 8ef43ea022..ae9966a825 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -9,6 +9,7 @@ ${CEE_CURRENT_LIST_DIR}RimEclipseCaseCollection.h ${CEE_CURRENT_LIST_DIR}RimCaseCollection.h ${CEE_CURRENT_LIST_DIR}RimCellFilter.h ${CEE_CURRENT_LIST_DIR}RimEclipsePropertyFilter.h +${CEE_CURRENT_LIST_DIR}RimPropertyFilterCollection.h ${CEE_CURRENT_LIST_DIR}RimEclipsePropertyFilterCollection.h ${CEE_CURRENT_LIST_DIR}RimCellRangeFilter.h ${CEE_CURRENT_LIST_DIR}RimCellRangeFilterCollection.h @@ -78,6 +79,7 @@ ${CEE_CURRENT_LIST_DIR}RimEclipseCaseCollection.cpp ${CEE_CURRENT_LIST_DIR}RimCaseCollection.cpp ${CEE_CURRENT_LIST_DIR}RimCellFilter.cpp ${CEE_CURRENT_LIST_DIR}RimEclipsePropertyFilter.cpp +${CEE_CURRENT_LIST_DIR}RimPropertyFilterCollection.cpp ${CEE_CURRENT_LIST_DIR}RimEclipsePropertyFilterCollection.cpp ${CEE_CURRENT_LIST_DIR}RimCellRangeFilter.cpp ${CEE_CURRENT_LIST_DIR}RimCellRangeFilterCollection.cpp diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp index a25d0c0f1b..4e157d0471 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp @@ -41,8 +41,6 @@ RimEclipsePropertyFilterCollection::RimEclipsePropertyFilterCollection() CAF_PDM_InitFieldNoDefault(&propertyFilters, "PropertyFilters", "Property Filters", "", "", ""); propertyFilters.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); - isActive.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -64,17 +62,6 @@ RimEclipseView* RimEclipsePropertyFilterCollection::reservoirView() return eclipseView; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipsePropertyFilterCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) -{ - updateIconState(); - uiCapability()->updateConnectedEditors(); - - updateDisplayModelNotifyManagedViews(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -127,26 +114,6 @@ bool RimEclipsePropertyFilterCollection::hasActiveDynamicFilters() const return false; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimEclipsePropertyFilterCollection::objectToggleField() -{ - return &isActive; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipsePropertyFilterCollection::updateDisplayModelNotifyManagedViews() -{ - RimEclipseView* view = NULL; - this->firstAnchestorOrThisOfType(view); - CVF_ASSERT(view); - - view->scheduleGeometryRegen(PROPERTY_FILTERED); - view->scheduleCreateDisplayModelAndRedraw(); -} //-------------------------------------------------------------------------------------------------- /// @@ -179,25 +146,3 @@ void RimEclipsePropertyFilterCollection::updateIconState() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipsePropertyFilterCollection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) -{ - PdmObject::defineUiTreeOrdering(uiTreeOrdering, uiConfigName); - - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - RimViewController* viewController = rimView->viewController(); - if (viewController && (viewController->isPropertyFilterOveridden() - || viewController->isVisibleCellsOveridden())) - { - isActive.uiCapability()->setUiReadOnly(true, uiConfigName); - } - else - { - isActive.uiCapability()->setUiReadOnly(false, uiConfigName); - } - - updateIconState(); -} diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.h b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.h index 0632f93333..3a36e7b028 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.h +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.h @@ -1,6 +1,8 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,37 +23,34 @@ #include "RimEclipsePropertyFilter.h" #include "cafPdmChildArrayField.h" +#include "RimPropertyFilterCollection.h" + //================================================================================================== /// /// //================================================================================================== -class RimEclipsePropertyFilterCollection : public caf::PdmObject +class RimEclipsePropertyFilterCollection : public RimPropertyFilterCollection { CAF_PDM_HEADER_INIT; public: RimEclipsePropertyFilterCollection(); virtual ~RimEclipsePropertyFilterCollection(); + RimEclipseView* reservoirView(); + // Fields: - caf::PdmField isActive; caf::PdmChildArrayField propertyFilters; // Methods bool hasActiveFilters() const; bool hasActiveDynamicFilters() const; - RimEclipseView* reservoirView(); - void loadAndInitializePropertyFilters(); - void updateDisplayModelNotifyManagedViews(); void updateIconState(); protected: // Overridden methods - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); virtual void initAfterRead(); - virtual caf::PdmFieldHandle* objectToggleField(); }; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp index 97545ce789..18c5c34c68 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp @@ -40,8 +40,6 @@ RimGeoMechPropertyFilterCollection::RimGeoMechPropertyFilterCollection() CAF_PDM_InitFieldNoDefault(&propertyFilters, "PropertyFilters", "Property Filters", "", "", ""); propertyFilters.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); - isActive.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -63,16 +61,6 @@ RimGeoMechView* RimGeoMechPropertyFilterCollection::reservoirView() return geoMechView; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGeoMechPropertyFilterCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) -{ - updateIconState(); - uiCapability()->updateConnectedEditors(); - - updateDisplayModelNotifyManagedViews(); -} //-------------------------------------------------------------------------------------------------- /// @@ -129,27 +117,6 @@ bool RimGeoMechPropertyFilterCollection::hasActiveDynamicFilters() const return hasActiveFilters(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimGeoMechPropertyFilterCollection::objectToggleField() -{ - return &isActive; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGeoMechPropertyFilterCollection::updateDisplayModelNotifyManagedViews() -{ - RimGeoMechView* view = NULL; - this->firstAnchestorOrThisOfType(view); - CVF_ASSERT(view); - - view->scheduleGeometryRegen(PROPERTY_FILTERED); - view->scheduleCreateDisplayModelAndRedraw(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -181,25 +148,3 @@ void RimGeoMechPropertyFilterCollection::updateIconState() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGeoMechPropertyFilterCollection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) -{ - PdmObject::defineUiTreeOrdering(uiTreeOrdering, uiConfigName); - - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - RimViewController* viewController = rimView->viewController(); - if (viewController && (viewController->isPropertyFilterOveridden() - || viewController->isVisibleCellsOveridden())) - { - isActive.uiCapability()->setUiReadOnly(true, uiConfigName); - } - else - { - isActive.uiCapability()->setUiReadOnly(false, uiConfigName); - } - - updateIconState(); -} diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.h b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.h index f26d9c7d18..2f9430706e 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.h @@ -23,6 +23,7 @@ #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmPointer.h" +#include "RimPropertyFilterCollection.h" class RimGeoMechPropertyFilter; class RimGeoMechView; @@ -31,7 +32,7 @@ class RimGeoMechView; /// /// //================================================================================================== -class RimGeoMechPropertyFilterCollection : public caf::PdmObject +class RimGeoMechPropertyFilterCollection : public RimPropertyFilterCollection { CAF_PDM_HEADER_INIT; public: @@ -41,7 +42,6 @@ class RimGeoMechPropertyFilterCollection : public caf::PdmObject RimGeoMechView* reservoirView(); // Fields: - caf::PdmField isActive; caf::PdmChildArrayField propertyFilters; // Methods @@ -49,13 +49,9 @@ class RimGeoMechPropertyFilterCollection : public caf::PdmObject bool hasActiveDynamicFilters() const; void loadAndInitializePropertyFilters(); - void updateDisplayModelNotifyManagedViews(); void updateIconState(); protected: // Overridden methods - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); - virtual caf::PdmFieldHandle* objectToggleField(); virtual void initAfterRead(); }; diff --git a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp new file mode 100644 index 0000000000..e3d83e6748 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp @@ -0,0 +1,99 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPropertyFilterCollection.h" +#include "RimView.h" +#include "RimViewController.h" + +CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimPropertyFilterCollection, "RimPropertyFilterCollection"); // Abstract class + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPropertyFilterCollection::RimPropertyFilterCollection() +{ + CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); + isActive.uiCapability()->setUiHidden(true); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPropertyFilterCollection::~RimPropertyFilterCollection() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPropertyFilterCollection::updateDisplayModelNotifyManagedViews() +{ + RimView* view = NULL; + this->firstAnchestorOrThisOfType(view); + CVF_ASSERT(view); + + view->scheduleGeometryRegen(PROPERTY_FILTERED); + view->scheduleCreateDisplayModelAndRedraw(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPropertyFilterCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + updateIconState(); + uiCapability()->updateConnectedEditors(); + + updateDisplayModelNotifyManagedViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPropertyFilterCollection::objectToggleField() +{ + return &isActive; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPropertyFilterCollection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) +{ + PdmObject::defineUiTreeOrdering(uiTreeOrdering, uiConfigName); + + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + RimViewController* viewController = rimView->viewController(); + if (viewController && (viewController->isPropertyFilterOveridden() + || viewController->isVisibleCellsOveridden())) + { + isActive.uiCapability()->setUiReadOnly(true, uiConfigName); + } + else + { + isActive.uiCapability()->setUiReadOnly(false, uiConfigName); + } + + updateIconState(); +} diff --git a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h new file mode 100644 index 0000000000..66e4b7e709 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmObject.h" +#include "cafPdmField.h" + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPropertyFilterCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimPropertyFilterCollection(); + virtual ~RimPropertyFilterCollection(); + + // Fields: + caf::PdmField isActive; + + // Methods + virtual bool hasActiveFilters() const = 0; + virtual bool hasActiveDynamicFilters() const = 0; + + virtual void loadAndInitializePropertyFilters() = 0; + + void updateDisplayModelNotifyManagedViews(); + virtual void updateIconState() = 0; + +protected: + // Overridden methods + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); + virtual caf::PdmFieldHandle* objectToggleField(); +}; + From 7b65cb91ce05391c3328e2f04d5b67217076107d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 12 Nov 2015 10:48:13 +0100 Subject: [PATCH 038/290] (#625) Added access to the generalized propertyFilterCollection in the view --- .../RivGeoMechVizLogic.cpp | 4 +-- .../RivReservoirViewPartMgr.cpp | 4 +-- .../ProjectDataModel/RimEclipseCase.cpp | 6 ++-- .../ProjectDataModel/RimEclipseView.cpp | 24 ++++++++++------ .../ProjectDataModel/RimEclipseView.h | 5 ++-- .../ProjectDataModel/RimGeoMechView.cpp | 28 +++++++++++++++++-- .../ProjectDataModel/RimGeoMechView.h | 5 +++- .../RimPropertyFilterCollection.cpp | 2 +- .../RimPropertyFilterCollection.h | 2 +- ApplicationCode/ProjectDataModel/RimView.cpp | 4 +-- ApplicationCode/ProjectDataModel/RimView.h | 4 ++- .../ProjectDataModel/RimViewController.cpp | 6 ++-- .../UserInterface/RiuViewerCommands.cpp | 4 +-- 13 files changed, 67 insertions(+), 31 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp index e7d9f59231..ba58d3d236 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp @@ -144,7 +144,7 @@ std::vector RivGeoMechVizLogic::keysToVisiblePartMg { visiblePartMgrs.push_back(RivGeoMechPartMgrCache::Key(OVERRIDDEN_CELL_VISIBILITY, -1)); } - else if (timeStepIndex >= 0 && m_geomechView->propertyFilterCollection()->hasActiveFilters()) + else if (timeStepIndex >= 0 && m_geomechView->geoMechPropertyFilterCollection()->hasActiveFilters()) { visiblePartMgrs.push_back(RivGeoMechPartMgrCache::Key(PROPERTY_FILTERED, timeStepIndex)); } @@ -209,7 +209,7 @@ RivGeoMechPartMgr* RivGeoMechVizLogic::getUpdatedPartMgr(RivGeoMechPartMgrCache: caseData->femParts()->part(femPartIdx), pMgrKey.frameIndex(), rangeFiltVisibility.p(), - m_geomechView->propertyFilterCollection() + m_geomechView->geoMechPropertyFilterCollection() ); } else if (pMgrKey.geometryType() == OVERRIDDEN_CELL_VISIBILITY) diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp index c3a99ca95e..762ba1d1a8 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp @@ -458,7 +458,7 @@ void RivReservoirViewPartMgr::createPropertyFilteredNoneWellCellGeometry(size_t (*cellVisibility)[cellIdx] = (*rangeVisibility)[cellIdx] || (*fenceVisibility)[cellIdx]; } - computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->propertyFilterCollection()); + computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); m_propFilteredGeometryFrames[frameIndex]->setCellVisibility(gIdx, cellVisibility.p()); } @@ -542,7 +542,7 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd (*cellVisibility)[cellIdx] = (*wellFenceCells)[cellIdx] || (*rangeVisibility)[cellIdx] || (*wellCellsOutsideRange)[cellIdx]; } - computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->propertyFilterCollection()); + computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); m_propFilteredWellGeometryFrames[frameIndex]->setCellVisibility(gIdx, cellVisibility.p()); } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp index 8ec0d7938c..04becf0527 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp @@ -195,7 +195,7 @@ void RimEclipseCase::removeResult(const QString& resultName) rebuildDisplayModel = true; } - RimEclipsePropertyFilterCollection* propFilterCollection = reservoirView->propertyFilterCollection(); + RimEclipsePropertyFilterCollection* propFilterCollection = reservoirView->eclipsePropertyFilterCollection(); for (size_t filter = 0; filter < propFilterCollection->propertyFilters().size(); filter++) { RimEclipsePropertyFilter* propertyFilter = propFilterCollection->propertyFilters()[filter]; @@ -428,8 +428,8 @@ QStringList RimEclipseCase::timeStepStrings() { QStringList stringList; - int timeStepCount = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepCount(0); - for (size_t i = 0; i < timeStepCount; i++) + int timeStepCount = static_cast(results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepCount(0)); + for (int i = 0; i < timeStepCount; i++) { stringList += this->timeStepName(i); } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 398cad5792..43d21816f9 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -302,7 +302,7 @@ void RimEclipseView::createDisplayModel() } else if (this->cellResult()->hasStaticResult() || this->cellEdgeResult()->hasResult() - || this->propertyFilterCollection()->hasActiveFilters()) + || this->eclipsePropertyFilterCollection()->hasActiveFilters()) { // The one and only result entry timeStepIndices.push_back(0); @@ -334,7 +334,7 @@ void RimEclipseView::createDisplayModel() // updateCurrentTimeStep requests the actual parts - if (!this->propertyFilterCollection()->hasActiveFilters() + if (!this->eclipsePropertyFilterCollection()->hasActiveFilters() || this->viewController() && this->viewController()->isVisibleCellsOveridden()) { std::vector geometryTypesToAdd; @@ -394,7 +394,7 @@ void RimEclipseView::createDisplayModel() m_visibleGridParts = geometryTypesToAdd; } - if (faultCollection()->showFaultsOutsideFilters() || !this->propertyFilterCollection()->hasActiveFilters() ) + if (faultCollection()->showFaultsOutsideFilters() || !this->eclipsePropertyFilterCollection()->hasActiveFilters() ) { forceFaultVisibilityOn(); @@ -524,7 +524,7 @@ void RimEclipseView::updateCurrentTimeStep() } #endif } - else if (this->propertyFilterCollection()->hasActiveFilters()) + else if (this->eclipsePropertyFilterCollection()->hasActiveFilters()) { cvf::ref frameParts = new cvf::ModelBasicList; @@ -1413,7 +1413,7 @@ std::vector RimEclipseView::visibleFaultGeometryTypes() const faultParts.push_back(OVERRIDDEN_CELL_VISIBILITY); } } - else if (this->propertyFilterCollection()->hasActiveFilters() && !faultCollection()->showFaultsOutsideFilters()) + else if (this->eclipsePropertyFilterCollection()->hasActiveFilters() && !faultCollection()->showFaultsOutsideFilters()) { faultParts.push_back(PROPERTY_FILTERED); faultParts.push_back(PROPERTY_FILTERED_WELL_CELLS); @@ -1516,7 +1516,7 @@ bool RimEclipseView::isTimeStepDependentDataVisible() const { if (this->cellResult()->hasDynamicResult()) return true; - if (this->propertyFilterCollection()->hasActiveDynamicFilters()) return true; + if (this->eclipsePropertyFilterCollection()->hasActiveDynamicFilters()) return true; if (this->wellCollection->hasVisibleWellPipes()) return true; @@ -1614,7 +1614,7 @@ void RimEclipseView::addWellPathsToScene(cvf::Scene* scene, //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimEclipsePropertyFilterCollection* RimEclipseView::propertyFilterCollection() +RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterCollection() { if (m_overridePropertyFilterCollection) { @@ -1629,7 +1629,7 @@ RimEclipsePropertyFilterCollection* RimEclipseView::propertyFilterCollection() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const RimEclipsePropertyFilterCollection* RimEclipseView::propertyFilterCollection() const +const RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterCollection() const { if (m_overridePropertyFilterCollection) { @@ -1692,3 +1692,11 @@ void RimEclipseView::updateIconStateForFilterCollections() m_propertyFilterCollection()->updateIconState(); m_propertyFilterCollection()->uiCapability()->updateConnectedEditors(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimPropertyFilterCollection* RimEclipseView::propertyFilterCollection() const +{ + return eclipsePropertyFilterCollection(); +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index dd2cfeaad3..c4cbc3af5c 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -99,9 +99,10 @@ class RimEclipseView : public RimView caf::PdmField showMainGrid; // Access internal objects + virtual const RimPropertyFilterCollection* propertyFilterCollection() const; - RimEclipsePropertyFilterCollection* propertyFilterCollection(); - const RimEclipsePropertyFilterCollection* propertyFilterCollection() const; + RimEclipsePropertyFilterCollection* eclipsePropertyFilterCollection(); + const RimEclipsePropertyFilterCollection* eclipsePropertyFilterCollection() const; void setOverridePropertyFilterCollection(RimEclipsePropertyFilterCollection* pfc); RimReservoirCellResultsStorage* currentGridCellResults(); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index a08e71d59a..f81f574e99 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -154,7 +154,7 @@ void RimGeoMechView::loadDataAndUpdate() progress.setProgressDescription("Create Display model"); updateViewerWidget(); - this->propertyFilterCollection()->loadAndInitializePropertyFilters(); + this->geoMechPropertyFilterCollection()->loadAndInitializePropertyFilters(); this->scheduleCreateDisplayModelAndRedraw(); @@ -486,7 +486,7 @@ void RimGeoMechView::clampCurrentTimestep() //-------------------------------------------------------------------------------------------------- bool RimGeoMechView::isTimeStepDependentDataVisible() { - return this->hasUserRequestedAnimation() && (this->cellResult()->hasResult() || this->propertyFilterCollection()->hasActiveFilters()); + return this->hasUserRequestedAnimation() && (this->cellResult()->hasResult() || this->geoMechPropertyFilterCollection()->hasActiveFilters()); } //-------------------------------------------------------------------------------------------------- @@ -581,7 +581,21 @@ void RimGeoMechView::setOverridePropertyFilterCollection(RimGeoMechPropertyFilte //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimGeoMechPropertyFilterCollection* RimGeoMechView::propertyFilterCollection() +RimGeoMechPropertyFilterCollection* RimGeoMechView::geoMechPropertyFilterCollection() +{ + if (m_overridePropertyFilterCollection) + { + return m_overridePropertyFilterCollection; + } + else + { + return m_propertyFilterCollection; + } +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimGeoMechPropertyFilterCollection* RimGeoMechView::geoMechPropertyFilterCollection() const { if (m_overridePropertyFilterCollection) { @@ -629,3 +643,11 @@ void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.setForgetRemainingFields(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimPropertyFilterCollection* RimGeoMechView::propertyFilterCollection() const +{ + return geoMechPropertyFilterCollection(); +} + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index aed5085647..710162393e 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -66,7 +66,10 @@ class RimGeoMechView : public RimView caf::PdmChildField cellResult; - RimGeoMechPropertyFilterCollection* propertyFilterCollection(); + virtual const RimPropertyFilterCollection* propertyFilterCollection() const; + + RimGeoMechPropertyFilterCollection* geoMechPropertyFilterCollection(); + const RimGeoMechPropertyFilterCollection* geoMechPropertyFilterCollection() const; void setOverridePropertyFilterCollection(RimGeoMechPropertyFilterCollection* pfc); bool isTimeStepDependentDataVisible(); diff --git a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp index e3d83e6748..609ca992c5 100644 --- a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.cpp @@ -44,7 +44,7 @@ RimPropertyFilterCollection::~RimPropertyFilterCollection() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimPropertyFilterCollection::updateDisplayModelNotifyManagedViews() +void RimPropertyFilterCollection::updateDisplayModelNotifyManagedViews() const { RimView* view = NULL; this->firstAnchestorOrThisOfType(view); diff --git a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h index 66e4b7e709..0fdd5a2d42 100644 --- a/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h +++ b/ApplicationCode/ProjectDataModel/RimPropertyFilterCollection.h @@ -41,7 +41,7 @@ class RimPropertyFilterCollection : public caf::PdmObject virtual void loadAndInitializePropertyFilters() = 0; - void updateDisplayModelNotifyManagedViews(); + void updateDisplayModelNotifyManagedViews() const; virtual void updateIconState() = 0; protected: diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index d3429e3b1b..cca390c4ff 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -718,9 +718,9 @@ bool RimView::isMasterView() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimCellRangeFilterCollection* RimView::overrideRangeFilterCollection() +bool RimView::hasOverridenRangeFilterCollection() { - return m_overrideRangeFilterCollection(); + return m_overrideRangeFilterCollection() != NULL; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 28912acf6f..09ebd2d0dc 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -42,6 +42,7 @@ class RimCellRangeFilterCollection; class RiuViewer; class RimViewLinker; class RimViewController; +class RimPropertyFilterCollection; namespace cvf { @@ -76,10 +77,11 @@ class RimView : public caf::PdmObject caf::PdmField maximumFrameRate; caf::PdmField hasUserRequestedAnimation; + virtual const RimPropertyFilterCollection* propertyFilterCollection() const = 0; RimCellRangeFilterCollection* rangeFilterCollection(); const RimCellRangeFilterCollection* rangeFilterCollection() const; - RimCellRangeFilterCollection* overrideRangeFilterCollection(); + bool hasOverridenRangeFilterCollection(); void setOverrideRangeFilterCollection(RimCellRangeFilterCollection* rfc); void replaceRangeFilterCollectionWithOverride(); diff --git a/ApplicationCode/ProjectDataModel/RimViewController.cpp b/ApplicationCode/ProjectDataModel/RimViewController.cpp index 4cc5832ba9..b177d98674 100644 --- a/ApplicationCode/ProjectDataModel/RimViewController.cpp +++ b/ApplicationCode/ProjectDataModel/RimViewController.cpp @@ -268,7 +268,7 @@ void RimViewController::updateOverrides() { if (isPropertyFilterOveridden()) { - manEclView->setOverridePropertyFilterCollection(masterEclipseView->propertyFilterCollection()); + manEclView->setOverridePropertyFilterCollection(masterEclipseView->eclipsePropertyFilterCollection()); } else { @@ -284,7 +284,7 @@ void RimViewController::updateOverrides() { if (isPropertyFilterOveridden()) { - manGeoView->setOverridePropertyFilterCollection(masterGeoView->propertyFilterCollection()); + manGeoView->setOverridePropertyFilterCollection(masterGeoView->geoMechPropertyFilterCollection()); } else { @@ -941,7 +941,7 @@ void RimViewController::updateRangeFilterOverrides(RimCellRangeFilter* changedRa //-------------------------------------------------------------------------------------------------- void RimViewController::applyRangeFilterCollectionByUserChoice() { - if (!m_managedView->overrideRangeFilterCollection()) + if (!m_managedView->hasOverridenRangeFilterCollection()) { return; } diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 0015bc0cba..593a0f7d83 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -376,7 +376,7 @@ void RiuViewerCommands::slotAddEclipsePropertyFilter() RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); if (eclipseView) { - RimEclipsePropertyFilterCollection* filterCollection = eclipseView->propertyFilterCollection(); + RimEclipsePropertyFilterCollection* filterCollection = eclipseView->eclipsePropertyFilterCollection(); RicEclipsePropertyFilterNewExec* propCmdExe = new RicEclipsePropertyFilterNewExec(filterCollection); caf::CmdExecCommandManager::instance()->processExecuteCommand(propCmdExe); } @@ -390,7 +390,7 @@ void RiuViewerCommands::slotAddGeoMechPropertyFilter() RimGeoMechView* geoMechView = dynamic_cast(m_reservoirView.p()); if (geoMechView) { - RimGeoMechPropertyFilterCollection* filterCollection = geoMechView->propertyFilterCollection(); + RimGeoMechPropertyFilterCollection* filterCollection = geoMechView->geoMechPropertyFilterCollection(); RicGeoMechPropertyFilterNewExec* propCmdExe = new RicGeoMechPropertyFilterNewExec(filterCollection); caf::CmdExecCommandManager::instance()->processExecuteCommand(propCmdExe); } From 8283f6665bff8c2709cad5095705e1ca42406c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 12 Nov 2015 11:53:22 +0100 Subject: [PATCH 039/290] (#625) Guard against All Timesteps Visible cells statistics when using dyn prop filter --- .../Rim3dOverlayInfoConfig.cpp | 43 +++++++++++++++++++ .../ProjectDataModel/Rim3dOverlayInfoConfig.h | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 5735a8d55b..ee5c33ddf4 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -108,6 +108,15 @@ Rim3dOverlayInfoConfig::~Rim3dOverlayInfoConfig() //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { + if (m_viewDef->propertyFilterCollection() && m_viewDef->propertyFilterCollection()->hasActiveDynamicFilters() && + m_statisticsCellRange() == VISIBLE_CELLS && m_statisticsTimeRange() == ALL_TIMESTEPS) + { + displayPropertyFilteredStatisticsMessage(false); + if (changedField == &m_statisticsTimeRange) m_statisticsTimeRange = CURRENT_TIMESTEP; + if (changedField == &m_statisticsCellRange) m_statisticsCellRange = ALL_CELLS; + } + + this->update3DInfo(); if (m_viewDef && m_viewDef->viewer()) @@ -149,6 +158,13 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_isVisCellStatUpToDate = false; + if (m_viewDef->propertyFilterCollection() && m_viewDef->propertyFilterCollection()->hasActiveDynamicFilters() && + m_statisticsCellRange() == VISIBLE_CELLS && m_statisticsTimeRange() == ALL_TIMESTEPS) + { + displayPropertyFilteredStatisticsMessage(true); + m_statisticsTimeRange = CURRENT_TIMESTEP; + } + RimEclipseView * reservoirView = dynamic_cast(m_viewDef.p()); if (reservoirView) updateEclipse3DInfo(reservoirView); RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); @@ -528,3 +544,30 @@ void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() m_isVisCellStatUpToDate = true; } } + +#include + +void Rim3dOverlayInfoConfig::displayPropertyFilteredStatisticsMessage(bool showSwitchToCurrentTimestep) +{ + static bool isShowing = false; + + QString switchString; + if (showSwitchToCurrentTimestep) + { + switchString = QString("
" + "Switching to statistics for Current Time Step"); + } + + if (!isShowing) + { + isShowing = true; + QMessageBox::information(m_viewDef->viewer()->layoutWidget(), + QString("ResInsight"), + QString("Statistics not available
" + "
" + "Statistics calculations of Visible Cells for All Time Steps is not supported
" + "when you have an active Property filter on a time varying result.
") + + switchString); + isShowing = false; + } +} \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h index 330ea0a06a..47dbd1e3fc 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h @@ -84,7 +84,7 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject cvf::Vec2ui m_position; void updateVisCellStatsIfNeeded(); - + void displayPropertyFilteredStatisticsMessage(bool showSwitchToCurrentTimestep); bool m_isVisCellStatUpToDate; cvf::ref m_visibleCellStatistics; From 83d1c0c4110a462ef217e7df4235466a9b1d7602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 12 Nov 2015 12:24:05 +0100 Subject: [PATCH 040/290] (#648) Fixed missing update of total cell visibility --- ApplicationCode/ProjectDataModel/RimView.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index cca390c4ff..f2a6247c25 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -31,6 +31,7 @@ #include "cvfViewport.h" #include +#include "RimPropertyFilterCollection.h" namespace caf { @@ -240,6 +241,10 @@ void RimView::setCurrentTimeStep(int frameIndex) clampCurrentTimestep(); this->hasUserRequestedAnimation = true; + if (this->propertyFilterCollection() && this->propertyFilterCollection()->hasActiveDynamicFilters()) + { + m_currentReservoirCellVisibility = NULL; + } this->updateCurrentTimeStep(); } //-------------------------------------------------------------------------------------------------- From 7ff7f42adc7448947de00e6d833b6f821a62ff05 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 12 Nov 2015 12:00:51 +0100 Subject: [PATCH 041/290] (#266) Added geometry for grid box faces Added legend lines and text --- ApplicationCode/CMakeLists.txt | 17 +- .../RivFemPartGeometryGenerator.cpp | 13 +- .../GridBox/CMakeLists_files.cmake | 26 + .../GridBox/RivGridBoxGenerator.cpp | 487 ++++++++++++++++++ .../GridBox/RivGridBoxGenerator.h | 118 +++++ .../GridBox/RivPatchGenerator.cpp | 163 ++++++ .../GridBox/RivPatchGenerator.h | 64 +++ .../ScalarMapper-Test.cpp | 34 ++ .../ProjectDataModel/RimEclipseView.cpp | 2 + .../ProjectDataModel/RimGeoMechView.cpp | 2 + ApplicationCode/UserInterface/RiuViewer.cpp | 33 ++ ApplicationCode/UserInterface/RiuViewer.h | 15 +- 12 files changed, 955 insertions(+), 19 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h create mode 100644 ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index f4ef776cee..1e91d60ed5 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -31,6 +31,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/FileInterface ${CMAKE_CURRENT_SOURCE_DIR}/SocketInterface ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization + ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/GridBox ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel ${CMAKE_CURRENT_SOURCE_DIR}/ResultStatisticsCache @@ -111,12 +112,11 @@ set( SOCKET_INTERFACE_FILES SocketInterface/RiaSocketDataTransfer.cpp ) -set( UNIT_TEST_FILES - ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp - ProjectDataModel/ProjectDataModel_UnitTests/WellPathAsciiFileReader-Test.cpp +# Using GLOB here to ease adding of new unit tests +FILE ( GLOB UNIT_TEST_FILES + ProjectDataModel/ProjectDataModel_UnitTests/*.cpp ) - list( APPEND CPP_SOURCES ${APPLICATION_FILES} ${USER_INTERFACE_FILES} @@ -124,16 +124,17 @@ list( APPEND CPP_SOURCES ${UNIT_TEST_FILES} ) - - list( APPEND REFERENCED_CMAKE_FILES ReservoirDataModel/CMakeLists_files.cmake ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake FileInterface/CMakeLists_files.cmake ProjectDataModel/CMakeLists_files.cmake + GeoMech/GeoMechVisualization/CMakeLists_files.cmake + ModelVisualization/CMakeLists_files.cmake - GeoMech/GeoMechVisualization/CMakeLists_files.cmake - Commands/CMakeLists_files.cmake + ModelVisualization/GridBox/CMakeLists_files.cmake + + Commands/CMakeLists_files.cmake Commands/OperationsUsingObjReferences/CMakeLists_files.cmake Commands/ToggleCommands/CMakeLists_files.cmake Commands/OctaveScriptCommands/CMakeLists_files.cmake diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp index 52d31a408c..e655ddf137 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp @@ -1,18 +1,17 @@ -#include -#include "RivFemPartGeometryGenerator.h" -#include "cvfBase.h" +#include "RivFemPartGeometryGenerator.h" #include "RigFemPart.h" -//#include "RigFemPartScalarDataAccess.h" +#include "cvfBase.h" +#include "cvfArray.h" #include "cvfDebugTimer.h" -#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfDrawableGeo.h" +#include "cvfOutlineEdgeExtractor.h" #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" -#include "cvfArray.h" -#include "cvfOutlineEdgeExtractor.h" +#include #include diff --git a/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake new file mode 100644 index 0000000000..0049fdae70 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/CMakeLists_files.cmake @@ -0,0 +1,26 @@ + +# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly +if (${CMAKE_VERSION} VERSION_GREATER "2.8.2") + set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/) +endif() + +set (SOURCE_GROUP_HEADER_FILES +${CEE_CURRENT_LIST_DIR}RivPatchGenerator.h +${CEE_CURRENT_LIST_DIR}RivGridBoxGenerator.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CEE_CURRENT_LIST_DIR}RivPatchGenerator.cpp +${CEE_CURRENT_LIST_DIR}RivGridBoxGenerator.cpp + +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "ModelVisualization\\GridBox" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake ) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp new file mode 100644 index 0000000000..81a393da58 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -0,0 +1,487 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RivGridBoxGenerator.h" + +#include "RivPatchGenerator.h" + +#include "cafEffectGenerator.h" +#include "cvfCamera.h" +#include "cvfDrawableText.h" +#include "cvfFixedAtlasFont.h" +#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfGeometryBuilderFaceList.h" +#include "cvfMeshEdgeExtractor.h" +#include "cvfPrimitiveSetIndexedUInt.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivGridBoxGenerator::RivGridBoxGenerator() +{ + m_gridBoxModel = new cvf::ModelBasicList; + + m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::setTransform(cvf::Transform* scaleTransform) +{ + m_scaleTransform = scaleTransform; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::setBoundingBox(const cvf::BoundingBox& boundingBox) +{ + m_boundingBox = boundingBox; + + m_xValues.clear(); + m_yValues.clear(); + m_zValues.clear(); + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + m_linDiscreteScalarMapper->setRange(min.x(), max.x()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_xValues); + + m_linDiscreteScalarMapper->setRange(min.y(), max.y()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_yValues); + + m_linDiscreteScalarMapper->setRange(min.z(), max.z()); + m_linDiscreteScalarMapper->setLevelCount(5, true); + m_linDiscreteScalarMapper->majorTickValues(&m_zValues); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxParts() +{ + createGridBoxSideParts(); + createGridBoxLegendParts(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) +{ + m_gridBoxModel->removeAllParts(); + + if (m_gridBoxSideParts.size() == 0) return; + + for (size_t i = POS_X; i <= NEG_Z; i++) + { + cvf::Vec3f sideNorm = sideNormalOutwards((FaceType)i); + + cvf::Vec3d camToSide = camera->position() - pointOnSide((FaceType)i); + camToSide.normalize(); + + if (sideNorm.dot(cvf::Vec3f(camToSide)) < 0.0) + { + m_gridBoxModel->addPart(m_gridBoxSideParts[i].p()); + } + } + + for (size_t i = 0; i < m_gridBoxLegendParts.size(); i++) + { + m_gridBoxModel->addPart(m_gridBoxLegendParts[i].p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Model* RivGridBoxGenerator::model() +{ + return m_gridBoxModel.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxSideParts() +{ + m_gridBoxSideParts.clear(); + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + + for (int face = POS_X; face <= NEG_Z; face++) + { + // TODO: move out of loop + RivPatchGenerator patchGen; + + if (face == POS_X) + { + patchGen.setOrigin(cvf::Vec3d(max.x(), 0.0, 0.0)); + patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_yValues, m_zValues); + } + else if (face == NEG_X) + { + patchGen.setOrigin(cvf::Vec3d(min.x(), 0.0, 0.0)); + patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_yValues, m_zValues); + } + else if (face == POS_Y) + { + patchGen.setOrigin(cvf::Vec3d(0.0, max.y(), 0.0)); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_xValues, m_zValues); + } + else if (face == NEG_Y) + { + patchGen.setOrigin(cvf::Vec3d(0.0, min.y(), 0.0)); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); + patchGen.setSubdivisions(m_xValues, m_zValues); + } + else if (face == POS_Z) + { + patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, max.z())); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); + patchGen.setSubdivisions(m_xValues, m_yValues); + } + else if (face == NEG_Z) + { + patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, min.z())); + patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); + patchGen.setSubdivisions(m_xValues, m_yValues); + } + else + { + CVF_ASSERT(false); + } + + cvf::GeometryBuilderFaceList builder; + patchGen.generate(&builder); + cvf::ref vertexArray = builder.vertices(); + cvf::ref faceList = builder.faceList(); + + { + // Box mesh + cvf::MeshEdgeExtractor ee; + ee.addFaceList(*faceList); + + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray(vertexArray.p()); + geo->addPrimitiveSet(new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES, ee.lineIndices().p())); + + cvf::ref part = new cvf::Part; + part->setName("Grid box "); + part->setDrawable(geo.p()); + + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff; + caf::MeshEffectGenerator effGen(cvf::Color3f::GRAY); + eff = effGen.generateCachedEffect(); + + part->setEffect(eff.p()); + + m_gridBoxSideParts.push_back(part.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createGridBoxLegendParts() +{ + m_gridBoxLegendParts.clear(); + + for (int edge = POS_Z_POS_X; edge <= NEG_X_NEG_Y; edge++) + { + cvf::Collection parts; + + createLegend((EdgeType)edge, &parts); + + for (int i = 0; i < parts.size(); i++) + { + m_gridBoxLegendParts.push_back(parts.at(i)); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection* parts) +{ + cvf::Vec3d posMin; + cvf::Vec3d posMax; + + cvf::Vec3d min = m_boundingBox.min(); + cvf::Vec3d max = m_boundingBox.max(); + + std::vector* tickValues = NULL; + AxisType axis; + + cvf::Vec3f tickMarkDir; + + switch (edge) + { + case RivGridBoxGenerator::POS_Z_POS_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(max.x(), min.y(), max.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, POS_X); + break; + case RivGridBoxGenerator::POS_Z_NEG_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(min.x(), min.y(), max.z()); + posMax.set(min.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, NEG_X); + break; + case RivGridBoxGenerator::POS_Z_POS_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), max.y(), max.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, POS_Y); + break; + case RivGridBoxGenerator::POS_Z_NEG_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), min.y(), max.z()); + posMax.set(max.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(POS_Z, NEG_Y); + break; + case RivGridBoxGenerator::NEG_Z_POS_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(max.x(), min.y(), min.z()); + posMax.set(max.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, POS_X); + break; + case RivGridBoxGenerator::NEG_Z_NEG_X: + axis = Y_AXIS; + tickValues = &m_yValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(min.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, NEG_X); + break; + case RivGridBoxGenerator::NEG_Z_POS_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), max.y(), min.z()); + posMax.set(max.x(), max.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, POS_Y); + break; + case RivGridBoxGenerator::NEG_Z_NEG_Y: + axis = X_AXIS; + tickValues = &m_xValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(max.x(), min.y(), min.z()); + tickMarkDir = cornerDirection(NEG_Z, NEG_Y); + break; + case RivGridBoxGenerator::POS_X_POS_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(max.x(), max.y(), min.z()); + posMax.set(max.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(POS_X, POS_Y); + break; + case RivGridBoxGenerator::POS_X_NEG_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(max.x(), min.y(), min.z()); + posMax.set(max.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(POS_X, NEG_Y); + break; + case RivGridBoxGenerator::NEG_X_POS_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(min.x(), max.y(), min.z()); + posMax.set(min.x(), max.y(), max.z()); + tickMarkDir = cornerDirection(NEG_X, POS_Y); + break; + case RivGridBoxGenerator::NEG_X_NEG_Y: + axis = Z_AXIS; + tickValues = &m_zValues; + posMin.set(min.x(), min.y(), min.z()); + posMax.set(min.x(), min.y(), max.z()); + tickMarkDir = cornerDirection(NEG_X, NEG_Y); + break; + default: + break; + } + + CVF_ASSERT(tickValues); + + size_t numVerts = (tickValues->size()) * 2; + size_t numLines = (tickValues->size()) + 1; + + cvf::ref vertices = new cvf::Vec3fArray; + vertices->reserve(numVerts); + + cvf::ref indices = new cvf::UIntArray; + indices->reserve(2 * numLines); + + + float tickLength = static_cast(m_boundingBox.extent().length() / 100.0); + + cvf::Vec3f point = cvf::Vec3f(posMin); + cvf::Vec3f tickPoint; + + // Tick marks + for (size_t i = 0; i < tickValues->size(); ++i) + { + point[axis] = static_cast(tickValues->at(i)); + + vertices->add(point); + tickPoint = point + tickLength*tickMarkDir;; + vertices->add(tickPoint); + indices->add(2 * static_cast(i)); + indices->add(2 * static_cast(i) + 1); + } + + // Backbone of legend + indices->add(0); + indices->add(static_cast(numVerts) - 2); + + { + // Legend lines + + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray(vertices.p()); + + cvf::ref primSet = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); + primSet->setIndices(indices.p()); + geo->addPrimitiveSet(primSet.p()); + + cvf::ref part = new cvf::Part; + part->setName("Legend lines "); + part->setDrawable(geo.p()); + + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff; + caf::MeshEffectGenerator effGen(cvf::Color3f::WHITE); + eff = effGen.generateCachedEffect(); + + part->setEffect(eff.p()); + + parts->push_back(part.p()); + } + + + { + // Text labels + + cvf::ref geo = new cvf::DrawableText; + geo->setFont(new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD)); + geo->setTextColor(cvf::Color3::WHITE); + geo->setDrawBackground(false); + geo->setDrawBorder(false); + //textGeo->setCheckPosVisible(false); + + for (size_t idx = 0; idx < tickValues->size(); idx++) + { + geo->addText(cvf::String(tickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); + } + + cvf::ref part = new cvf::Part; + part->setDrawable(geo.p()); + part->setTransform(m_scaleTransform.p()); + part->updateBoundingBox(); + + cvf::ref eff = new cvf::Effect; + part->setEffect(eff.p()); + + //textPart->setPriority(11); + part->setName("Legend text"); + + parts->push_back(part.p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3f RivGridBoxGenerator::sideNormalOutwards(FaceType face) +{ + switch (face) + { + case RivGridBoxGenerator::POS_X: + return cvf::Vec3f::X_AXIS; + case RivGridBoxGenerator::NEG_X: + return -cvf::Vec3f::X_AXIS; + case RivGridBoxGenerator::POS_Y: + return cvf::Vec3f::Y_AXIS; + case RivGridBoxGenerator::NEG_Y: + return -cvf::Vec3f::Y_AXIS; + case RivGridBoxGenerator::POS_Z: + return cvf::Vec3f::Z_AXIS; + case RivGridBoxGenerator::NEG_Z: + return -cvf::Vec3f::Z_AXIS; + default: + break; + } + + return cvf::Vec3f::ZERO; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivGridBoxGenerator::pointOnSide(FaceType face) +{ + switch (face) + { + case RivGridBoxGenerator::POS_X: + case RivGridBoxGenerator::POS_Y: + case RivGridBoxGenerator::POS_Z: + return cvf::Vec3d(m_boundingBox.max()); + + case RivGridBoxGenerator::NEG_X: + case RivGridBoxGenerator::NEG_Y: + case RivGridBoxGenerator::NEG_Z: + return cvf::Vec3d(m_boundingBox.min()); + default: + break; + } + + return cvf::Vec3d::ZERO; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) +{ + cvf::Vec3f dir = sideNormalOutwards(face1) + sideNormalOutwards(face2); + dir.normalize(); + + return dir; +} diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h new file mode 100644 index 0000000000..666b90b69c --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -0,0 +1,118 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#pragma once + +#include "cvfBase.h" + +#include "cvfCollection.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfTransform.h" +#include "cvfScalarMapperDiscreteLinear.h" + + +namespace cvf +{ + class Camera; +} + + +//================================================================================================== +// +// +//================================================================================================== +class RivGridBoxGenerator +{ +public: + RivGridBoxGenerator(); + + void setTransform(cvf::Transform* scaleTransform); + void setBoundingBox(const cvf::BoundingBox& boundingBox); + void createGridBoxParts(); + + void updateFromCamera(const cvf::Camera* camera); + + cvf::Model* model(); + +private: + enum AxisType + { + X_AXIS, + Y_AXIS, + Z_AXIS + }; + + enum FaceType + { + POS_X, + NEG_X, + POS_Y, + NEG_Y, + POS_Z, + NEG_Z + }; + + enum EdgeType + { + POS_Z_POS_X, + POS_Z_NEG_X, + POS_Z_POS_Y, + POS_Z_NEG_Y, + + NEG_Z_POS_X, + NEG_Z_NEG_X, + NEG_Z_POS_Y, + NEG_Z_NEG_Y, + + POS_X_POS_Y, + POS_X_NEG_Y, + NEG_X_POS_Y, + NEG_X_NEG_Y + }; + + +private: + void createGridBoxSideParts(); + void createGridBoxLegendParts(); + + void createLegend(EdgeType edge, cvf::Collection* parts); + + cvf::Vec3f sideNormalOutwards(FaceType face); + cvf::Vec3d pointOnSide(FaceType face); + cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); + + +private: + cvf::Collection m_gridBoxSideParts; + cvf::Collection m_gridBoxLegendParts; + + cvf::ref m_gridBoxModel; + + cvf::ref m_scaleTransform; + cvf::BoundingBox m_boundingBox; + + cvf::ref m_linDiscreteScalarMapper; + + std::vector m_xValues; + std::vector m_yValues; + std::vector m_zValues; +}; + diff --git a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp new file mode 100644 index 0000000000..e08862d935 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp @@ -0,0 +1,163 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#include "RivPatchGenerator.h" + +#include "cvfGeometryUtils.h" +#include "cvfArray.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivPatchGenerator::RivPatchGenerator() +: m_origin(0, 0, 0), + m_axisU(cvf::Vec3d::X_AXIS), + m_axisV(cvf::Vec3d::Y_AXIS), + m_useQuads(true), + m_windingCCW(true) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setOrigin(const cvf::Vec3d& origin) +{ + m_origin = origin; +} + +//-------------------------------------------------------------------------------------------------- +/// Set the axes +/// +/// The specified axes will be normalized +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setAxes(const cvf::Vec3d& axisU, const cvf::Vec3d& axisV) +{ + m_axisU = axisU.getNormalized(); + m_axisV = axisV.getNormalized(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setSubdivisions(const std::vector& uValues, const std::vector& vValues) +{ + m_uValues = uValues; + m_vValues = vValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setQuads(bool useQuads) +{ + m_useQuads = useQuads; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::setWindingCCW(bool windingCCW) +{ + m_windingCCW = windingCCW; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPatchGenerator::generate(cvf::GeometryBuilder* builder) +{ +/* + CVF_ASSERT(m_cellCountU > 0); + CVF_ASSERT(m_cellCountV > 0); + + size_t numVertices = (m_cellCountU + 1)*(m_cellCountV + 1); + + Vec3fArray vertices; + vertices.reserve(numVertices); + + const Vec3d unitU = (m_extentU*m_axisU)/m_cellCountU; + const Vec3d unitV = (m_extentV*m_axisV)/m_cellCountV; + + uint v; + for (v = 0; v <= m_cellCountV; v++) + { + Vec3d rowOrigo(m_origin + unitV*v); + + uint u; + for (u = 0; u <= m_cellCountU; u++) + { + vertices.add(Vec3f(rowOrigo + unitU*u)); + } + } + + uint baseNodeIdx = builder->addVertices(vertices); + + if (m_useQuads) + { + UIntArray conn; + GeometryUtils::tesselatePatchAsQuads(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); + builder->addQuads(conn); + } + else + { + UIntArray conn; + GeometryUtils::tesselatePatchAsTriangles(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); + builder->addTriangles(conn); + } +*/ + + CVF_ASSERT(m_uValues.size() > 0); + CVF_ASSERT(m_vValues.size() > 0); + + size_t numVertices = m_uValues.size() * m_vValues.size(); + + cvf::Vec3fArray vertices; + vertices.reserve(numVertices); + + for (size_t v = 0; v < m_vValues.size(); v++) + { + cvf::Vec3d rowOrigo(m_origin + m_axisV * m_vValues[v]); + + for (size_t u = 0; u < m_uValues.size(); u++) + { + vertices.add(cvf::Vec3f(rowOrigo + m_axisU * m_uValues[u])); + } + } + + cvf::uint baseNodeIdx = builder->addVertices(vertices); + + if (m_useQuads) + { + cvf::UIntArray conn; + cvf::GeometryUtils::tesselatePatchAsQuads(static_cast(m_uValues.size()), static_cast(m_vValues.size()), baseNodeIdx, m_windingCCW, &conn); + builder->addQuads(conn); + } + else + { + cvf::UIntArray conn; + cvf::GeometryUtils::tesselatePatchAsTriangles(static_cast(m_uValues.size()), static_cast(m_vValues.size()), baseNodeIdx, m_windingCCW, &conn); + builder->addTriangles(conn); + } +} + diff --git a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h new file mode 100644 index 0000000000..c944c86ea1 --- /dev/null +++ b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + +#pragma once + +#include "cvfBase.h" +#include "cvfVector3.h" + +#include + +namespace cvf +{ + class GeometryBuilder; +} + +//================================================================================================== +// +// Generates 2D patches based on predefined coordinates along u and v axis +// Inspired by cvf::PatchGenerator +// +//================================================================================================== +class RivPatchGenerator +{ +public: + RivPatchGenerator(); + + void setOrigin(const cvf::Vec3d& origin); + void setAxes(const cvf::Vec3d& axisU, const cvf::Vec3d& axisV); + void setSubdivisions(const std::vector& uValues, const std::vector& vValues); + + void setQuads(bool useQuads); + void setWindingCCW(bool windingCCW); + + void generate(cvf::GeometryBuilder* builder); + +private: + cvf::Vec3d m_origin; // Origin. Default (0, 0, 0) + cvf::Vec3d m_axisU; // First axis of patch. Default is global X-axis + cvf::Vec3d m_axisV; // Second axis of patch. Default is global Y-axis + + std::vector m_uValues; + std::vector m_vValues; + + bool m_useQuads; // If true, quads will be generated, otherwise triangles. Default is quads + bool m_windingCCW; // Winding of the generated quads. Controls which side of the patch will be front facing. +}; + diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp new file mode 100644 index 0000000000..dc875050d6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp @@ -0,0 +1,34 @@ +#include "gtest/gtest.h" + +#include "cvfScalarMapperDiscreteLinear.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(ScalarMapperTest, TestHumanReadableTickmarks) +{ + cvf::ref m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; + + + double adjustedMin = 0.0; + double adjustedMax = 0.0; + + adjustedMin = 2141234; + adjustedMax = 2165239; + + size_t m_numLevels = 10; + + m_linDiscreteScalarMapper->setRange(adjustedMin, adjustedMax); + m_linDiscreteScalarMapper->setLevelCount(m_numLevels, true); + + std::vector tickValues; + m_linDiscreteScalarMapper->majorTickValues(&tickValues); + + for (size_t i = 0; i < tickValues.size(); i++) + { + qDebug() << i << " " << tickValues[i]; + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 43d21816f9..57bf83ae7a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -480,6 +480,8 @@ void RimEclipseView::createDisplayModel() m_overlayInfoConfig()->update3DInfo(); updateLegends(); } + + m_viewer->showGridBox(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index f81f574e99..f1be68b085 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -250,6 +250,8 @@ void RimGeoMechView::createDisplayModel() m_vizLogic->updateStaticCellColors(-1); m_overlayInfoConfig()->update3DInfo(); } + + m_viewer->showGridBox(true); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 43a66055e3..160d6e74f5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -28,6 +28,8 @@ #include "RimViewController.h" #include "RimViewLinker.h" +#include "RivGridBoxGenerator.h" + #include "RiuCadNavigation.h" #include "RiuGeoQuestNavigation.h" #include "RiuRmsNavigation.h" @@ -160,6 +162,9 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) // Setting this policy will make sure the handling is not deferred to the widget's parent, // which solves the problem setContextMenuPolicy(Qt::PreventContextMenu); + + m_showGridBox = true; + m_gridBoxGenerator = new RivGridBoxGenerator; } @@ -179,6 +184,7 @@ RiuViewer::~RiuViewer() delete m_animationProgress; delete m_histogramWidget; delete m_progressBarStyle; + delete m_gridBoxGenerator; } @@ -502,6 +508,11 @@ void RiuViewer::navigationPolicyUpdate() { viewLinker->updateCamera(m_reservoirView); } + + if (m_showGridBox) + { + m_gridBoxGenerator->updateFromCamera(mainCamera()); + } } } @@ -525,3 +536,25 @@ RimView* RiuViewer::ownerReservoirView() { return m_reservoirView; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::showGridBox(bool enable) +{ + m_showGridBox = enable; + + if (!enable) + { + currentScene()->removeModel(m_gridBoxGenerator->model()); + } + else + { + m_gridBoxGenerator->setBoundingBox(mainScene()->boundingBox()); +// m_gridBoxGenerator->setTransform(); + m_gridBoxGenerator->updateFromCamera(mainCamera()); + m_gridBoxGenerator->createGridBoxParts(); + + currentScene()->addModel(m_gridBoxGenerator->model()); + } +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 81ad64224a..e32aa09a7a 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -29,11 +29,13 @@ #include "cvfStructGrid.h" class RimView; -class QLabel; -class QProgressBar; class RiuSimpleHistogramWidget; -class QCDEStyle; class RiuViewerCommands; +class RivGridBoxGenerator; + +class QCDEStyle; +class QLabel; +class QProgressBar; namespace cvf { @@ -67,6 +69,8 @@ class RiuViewer : public caf::Viewer void setHistogram(double min, double max, const std::vector& histogram); void setHistogramPercentiles(double pmin, double pmax, double mean); + void showGridBox(bool enable); + void showAnimationProgress(bool enable); void removeAllColorLegends(); @@ -106,6 +110,9 @@ public slots: caf::PdmPointer m_reservoirView; QPoint m_lastMousePressPosition; - RiuViewerCommands * m_viewerCommands; + RiuViewerCommands* m_viewerCommands; + + bool m_showGridBox; + RivGridBoxGenerator* m_gridBoxGenerator; }; From bca5720968a1c2d12b142f1e83ebd1fda39154b4 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 07:16:30 +0100 Subject: [PATCH 042/290] (#266) Added interface for all/activeCellsBoundingBox and displayModelOffset --- .../GeoMech/GeoMechDataModel/RigFemPart.cpp | 2 +- .../GeoMech/GeoMechDataModel/RigFemPart.h | 4 +- .../GeoMechDataModel/RigFemPartCollection.cpp | 2 +- .../GeoMechDataModel/RigFemPartCollection.h | 2 +- .../GridBox/RivGridBoxGenerator.cpp | 177 ++++++++++++------ .../GridBox/RivGridBoxGenerator.h | 24 ++- .../GridBox/RivPatchGenerator.cpp | 40 ---- ApplicationCode/ProjectDataModel/RimCase.cpp | 11 +- ApplicationCode/ProjectDataModel/RimCase.h | 12 ++ .../ProjectDataModel/RimEclipseCase.cpp | 47 ++++- .../ProjectDataModel/RimEclipseCase.h | 8 +- .../ProjectDataModel/RimEclipseView.cpp | 31 ++- .../ProjectDataModel/RimEclipseView.h | 2 + .../ProjectDataModel/RimGeoMechCase.cpp | 34 +++- .../ProjectDataModel/RimGeoMechCase.h | 3 + .../ProjectDataModel/RimGeoMechView.cpp | 2 - ApplicationCode/ProjectDataModel/RimView.cpp | 32 ++++ ApplicationCode/ProjectDataModel/RimView.h | 2 + ApplicationCode/UserInterface/RiuViewer.cpp | 54 ++---- ApplicationCode/UserInterface/RiuViewer.h | 12 +- 20 files changed, 337 insertions(+), 164 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp index 56c941da84..2f86eb7f10 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp @@ -326,7 +326,7 @@ float RigFemPart::characteristicElementSize() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::BoundingBox RigFemPart::boundingBox() +cvf::BoundingBox RigFemPart::boundingBox() const { if (m_boundingBox.isValid()) return m_boundingBox; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h index 2cf13f7bfc..7c8230e35c 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h @@ -77,7 +77,7 @@ class RigFemPart : public cvf::Object int neighborFace(int elementIndex, int faceIndex) const { return m_elmNeighbors[elementIndex].faceInNeighborElm[faceIndex]; } - cvf::BoundingBox boundingBox(); + cvf::BoundingBox boundingBox() const; float characteristicElementSize(); const std::vector& possibleGridCornerElements() const { return m_possibleGridCornerElements; } void findIntersectingCells(const cvf::BoundingBox& inputBB, std::vector* elementIndices) const; @@ -107,7 +107,7 @@ class RigFemPart : public cvf::Object std::vector m_possibleGridCornerElements; float m_characteristicElementSize; - cvf::BoundingBox m_boundingBox; + mutable cvf::BoundingBox m_boundingBox; mutable cvf::ref m_elementSearchTree; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.cpp index 6afa7383cb..cd735dea19 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.cpp @@ -103,7 +103,7 @@ float RigFemPartCollection::characteristicElementSize() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::BoundingBox RigFemPartCollection::boundingBox() +cvf::BoundingBox RigFemPartCollection::boundingBox() const { cvf::BoundingBox bBox; for (int i = 0; i < partCount(); i++) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h index 99af25738c..5f172de9b7 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h @@ -37,7 +37,7 @@ class RigFemPartCollection: public cvf::Object size_t totalElementCount() const; float characteristicElementSize(); - cvf::BoundingBox boundingBox(); + cvf::BoundingBox boundingBox() const; private: diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 81a393da58..849ef34c43 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -38,42 +38,53 @@ RivGridBoxGenerator::RivGridBoxGenerator() { m_gridBoxModel = new cvf::ModelBasicList; - m_linDiscreteScalarMapper = new cvf::ScalarMapperDiscreteLinear; + m_scaleZ = 1.0; + m_displayModelOffset = cvf::Vec3d::ZERO; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivGridBoxGenerator::setTransform(cvf::Transform* scaleTransform) +void RivGridBoxGenerator::setScaleZ(double scaleZ) { - m_scaleTransform = scaleTransform; + m_scaleZ = scaleZ; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivGridBoxGenerator::setBoundingBox(const cvf::BoundingBox& boundingBox) +void RivGridBoxGenerator::setDisplayModelOffset(cvf::Vec3d offset) { - m_boundingBox = boundingBox; + m_displayModelOffset = offset; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::setGridBoxDomainCoordBoundingBox(const cvf::BoundingBox& bb) +{ + m_domainCoordsBoundingBox = bb; - m_xValues.clear(); - m_yValues.clear(); - m_zValues.clear(); + m_domainCoordsXValues.clear(); + m_domainCoordsYValues.clear(); + m_domainCoordsZValues.clear(); - cvf::Vec3d min = m_boundingBox.min(); - cvf::Vec3d max = m_boundingBox.max(); + cvf::Vec3d min = m_domainCoordsBoundingBox.min(); + cvf::Vec3d max = m_domainCoordsBoundingBox.max(); - m_linDiscreteScalarMapper->setRange(min.x(), max.x()); - m_linDiscreteScalarMapper->setLevelCount(5, true); - m_linDiscreteScalarMapper->majorTickValues(&m_xValues); + cvf::ScalarMapperDiscreteLinear m_linDiscreteScalarMapper; - m_linDiscreteScalarMapper->setRange(min.y(), max.y()); - m_linDiscreteScalarMapper->setLevelCount(5, true); - m_linDiscreteScalarMapper->majorTickValues(&m_yValues); + m_linDiscreteScalarMapper.setRange(min.x(), max.x()); + m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsXValues); - m_linDiscreteScalarMapper->setRange(min.z(), max.z()); - m_linDiscreteScalarMapper->setLevelCount(5, true); - m_linDiscreteScalarMapper->majorTickValues(&m_zValues); + m_linDiscreteScalarMapper.setRange(min.y(), max.y()); + m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsYValues); + + m_linDiscreteScalarMapper.setRange(min.z(), max.z()); + m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsZValues); } //-------------------------------------------------------------------------------------------------- @@ -81,6 +92,8 @@ void RivGridBoxGenerator::setBoundingBox(const cvf::BoundingBox& boundingBox) //-------------------------------------------------------------------------------------------------- void RivGridBoxGenerator::createGridBoxParts() { + computeDisplayCoords(); + createGridBoxSideParts(); createGridBoxLegendParts(); } @@ -128,9 +141,13 @@ void RivGridBoxGenerator::createGridBoxSideParts() { m_gridBoxSideParts.clear(); - cvf::Vec3d min = m_boundingBox.min(); - cvf::Vec3d max = m_boundingBox.max(); + CVF_ASSERT(m_displayCoordsBoundingBox.isValid()); + CVF_ASSERT(m_displayCoordsXValues.size() > 0); + CVF_ASSERT(m_displayCoordsYValues.size() > 0); + CVF_ASSERT(m_displayCoordsZValues.size() > 0); + cvf::Vec3d min = m_displayCoordsBoundingBox.min(); + cvf::Vec3d max = m_displayCoordsBoundingBox.max(); for (int face = POS_X; face <= NEG_Z; face++) { @@ -141,37 +158,37 @@ void RivGridBoxGenerator::createGridBoxSideParts() { patchGen.setOrigin(cvf::Vec3d(max.x(), 0.0, 0.0)); patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); - patchGen.setSubdivisions(m_yValues, m_zValues); + patchGen.setSubdivisions(m_displayCoordsYValues, m_displayCoordsZValues); } else if (face == NEG_X) { patchGen.setOrigin(cvf::Vec3d(min.x(), 0.0, 0.0)); patchGen.setAxes(cvf::Vec3d::Y_AXIS, cvf::Vec3d::Z_AXIS); - patchGen.setSubdivisions(m_yValues, m_zValues); + patchGen.setSubdivisions(m_displayCoordsYValues, m_displayCoordsZValues); } else if (face == POS_Y) { patchGen.setOrigin(cvf::Vec3d(0.0, max.y(), 0.0)); patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); - patchGen.setSubdivisions(m_xValues, m_zValues); + patchGen.setSubdivisions(m_displayCoordsXValues, m_displayCoordsZValues); } else if (face == NEG_Y) { patchGen.setOrigin(cvf::Vec3d(0.0, min.y(), 0.0)); patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Z_AXIS); - patchGen.setSubdivisions(m_xValues, m_zValues); + patchGen.setSubdivisions(m_displayCoordsXValues, m_displayCoordsZValues); } else if (face == POS_Z) { patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, max.z())); patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); - patchGen.setSubdivisions(m_xValues, m_yValues); + patchGen.setSubdivisions(m_displayCoordsXValues, m_displayCoordsYValues); } else if (face == NEG_Z) { patchGen.setOrigin(cvf::Vec3d(0.0, 0.0, min.z())); patchGen.setAxes(cvf::Vec3d::X_AXIS, cvf::Vec3d::Y_AXIS); - patchGen.setSubdivisions(m_xValues, m_yValues); + patchGen.setSubdivisions(m_displayCoordsXValues, m_displayCoordsYValues); } else { @@ -196,7 +213,6 @@ void RivGridBoxGenerator::createGridBoxSideParts() part->setName("Grid box "); part->setDrawable(geo.p()); - part->setTransform(m_scaleTransform.p()); part->updateBoundingBox(); cvf::ref eff; @@ -217,6 +233,11 @@ void RivGridBoxGenerator::createGridBoxLegendParts() { m_gridBoxLegendParts.clear(); + CVF_ASSERT(m_displayCoordsBoundingBox.isValid()); + CVF_ASSERT(m_displayCoordsXValues.size() > 0); + CVF_ASSERT(m_displayCoordsYValues.size() > 0); + CVF_ASSERT(m_displayCoordsZValues.size() > 0); + for (int edge = POS_Z_POS_X; edge <= NEG_X_NEG_Y; edge++) { cvf::Collection parts; @@ -230,6 +251,17 @@ void RivGridBoxGenerator::createGridBoxLegendParts() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivGridBoxGenerator::displayModelCoordFromDomainCoord(const cvf::Vec3d& domainCoord) const +{ + cvf::Vec3d coord = domainCoord - m_displayModelOffset; + coord.z() *= m_scaleZ; + + return coord; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -238,10 +270,9 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection cvf::Vec3d posMin; cvf::Vec3d posMax; - cvf::Vec3d min = m_boundingBox.min(); - cvf::Vec3d max = m_boundingBox.max(); + cvf::Vec3d min = m_displayCoordsBoundingBox.min(); + cvf::Vec3d max = m_displayCoordsBoundingBox.max(); - std::vector* tickValues = NULL; AxisType axis; cvf::Vec3f tickMarkDir; @@ -250,84 +281,72 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection { case RivGridBoxGenerator::POS_Z_POS_X: axis = Y_AXIS; - tickValues = &m_yValues; posMin.set(max.x(), min.y(), max.z()); posMax.set(max.x(), max.y(), max.z()); tickMarkDir = cornerDirection(POS_Z, POS_X); break; case RivGridBoxGenerator::POS_Z_NEG_X: axis = Y_AXIS; - tickValues = &m_yValues; posMin.set(min.x(), min.y(), max.z()); posMax.set(min.x(), max.y(), max.z()); tickMarkDir = cornerDirection(POS_Z, NEG_X); break; case RivGridBoxGenerator::POS_Z_POS_Y: axis = X_AXIS; - tickValues = &m_xValues; posMin.set(min.x(), max.y(), max.z()); posMax.set(max.x(), max.y(), max.z()); tickMarkDir = cornerDirection(POS_Z, POS_Y); break; case RivGridBoxGenerator::POS_Z_NEG_Y: axis = X_AXIS; - tickValues = &m_xValues; posMin.set(min.x(), min.y(), max.z()); posMax.set(max.x(), min.y(), max.z()); tickMarkDir = cornerDirection(POS_Z, NEG_Y); break; case RivGridBoxGenerator::NEG_Z_POS_X: axis = Y_AXIS; - tickValues = &m_yValues; posMin.set(max.x(), min.y(), min.z()); posMax.set(max.x(), max.y(), min.z()); tickMarkDir = cornerDirection(NEG_Z, POS_X); break; case RivGridBoxGenerator::NEG_Z_NEG_X: axis = Y_AXIS; - tickValues = &m_yValues; posMin.set(min.x(), min.y(), min.z()); posMax.set(min.x(), max.y(), min.z()); tickMarkDir = cornerDirection(NEG_Z, NEG_X); break; case RivGridBoxGenerator::NEG_Z_POS_Y: axis = X_AXIS; - tickValues = &m_xValues; posMin.set(min.x(), max.y(), min.z()); posMax.set(max.x(), max.y(), min.z()); tickMarkDir = cornerDirection(NEG_Z, POS_Y); break; case RivGridBoxGenerator::NEG_Z_NEG_Y: axis = X_AXIS; - tickValues = &m_xValues; posMin.set(min.x(), min.y(), min.z()); posMax.set(max.x(), min.y(), min.z()); tickMarkDir = cornerDirection(NEG_Z, NEG_Y); break; case RivGridBoxGenerator::POS_X_POS_Y: axis = Z_AXIS; - tickValues = &m_zValues; posMin.set(max.x(), max.y(), min.z()); posMax.set(max.x(), max.y(), max.z()); tickMarkDir = cornerDirection(POS_X, POS_Y); break; case RivGridBoxGenerator::POS_X_NEG_Y: axis = Z_AXIS; - tickValues = &m_zValues; posMin.set(max.x(), min.y(), min.z()); posMax.set(max.x(), min.y(), max.z()); tickMarkDir = cornerDirection(POS_X, NEG_Y); break; case RivGridBoxGenerator::NEG_X_POS_Y: axis = Z_AXIS; - tickValues = &m_zValues; posMin.set(min.x(), max.y(), min.z()); posMax.set(min.x(), max.y(), max.z()); tickMarkDir = cornerDirection(NEG_X, POS_Y); break; case RivGridBoxGenerator::NEG_X_NEG_Y: axis = Z_AXIS; - tickValues = &m_zValues; posMin.set(min.x(), min.y(), min.z()); posMax.set(min.x(), min.y(), max.z()); tickMarkDir = cornerDirection(NEG_X, NEG_Y); @@ -336,10 +355,30 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection break; } - CVF_ASSERT(tickValues); + std::vector* displayCoordsTickValues = NULL; + std::vector* domainCoordsTickValues = NULL; - size_t numVerts = (tickValues->size()) * 2; - size_t numLines = (tickValues->size()) + 1; + if (axis == X_AXIS) + { + displayCoordsTickValues = &m_displayCoordsXValues; + domainCoordsTickValues = &m_domainCoordsXValues; + } + else if (axis == Y_AXIS) + { + displayCoordsTickValues = &m_displayCoordsYValues; + domainCoordsTickValues = &m_domainCoordsYValues; + } + else if (axis == Z_AXIS) + { + displayCoordsTickValues = &m_displayCoordsZValues; + domainCoordsTickValues = &m_domainCoordsZValues; + } + + CVF_ASSERT(displayCoordsTickValues); + CVF_ASSERT(domainCoordsTickValues); + + size_t numVerts = (displayCoordsTickValues->size()) * 2; + size_t numLines = (displayCoordsTickValues->size()) + 1; cvf::ref vertices = new cvf::Vec3fArray; vertices->reserve(numVerts); @@ -348,15 +387,15 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection indices->reserve(2 * numLines); - float tickLength = static_cast(m_boundingBox.extent().length() / 100.0); + float tickLength = static_cast(m_displayCoordsBoundingBox.extent().length() / 100.0); cvf::Vec3f point = cvf::Vec3f(posMin); cvf::Vec3f tickPoint; // Tick marks - for (size_t i = 0; i < tickValues->size(); ++i) + for (size_t i = 0; i < displayCoordsTickValues->size(); ++i) { - point[axis] = static_cast(tickValues->at(i)); + point[axis] = static_cast(displayCoordsTickValues->at(i)); vertices->add(point); tickPoint = point + tickLength*tickMarkDir;; @@ -383,7 +422,6 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection part->setName("Legend lines "); part->setDrawable(geo.p()); - part->setTransform(m_scaleTransform.p()); part->updateBoundingBox(); cvf::ref eff; @@ -395,7 +433,6 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection parts->push_back(part.p()); } - { // Text labels @@ -406,14 +443,13 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection geo->setDrawBorder(false); //textGeo->setCheckPosVisible(false); - for (size_t idx = 0; idx < tickValues->size(); idx++) + for (size_t idx = 0; idx < domainCoordsTickValues->size(); idx++) { - geo->addText(cvf::String(tickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); + geo->addText(cvf::String(domainCoordsTickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); } cvf::ref part = new cvf::Part; part->setDrawable(geo.p()); - part->setTransform(m_scaleTransform.p()); part->updateBoundingBox(); cvf::ref eff = new cvf::Effect; @@ -462,12 +498,12 @@ cvf::Vec3d RivGridBoxGenerator::pointOnSide(FaceType face) case RivGridBoxGenerator::POS_X: case RivGridBoxGenerator::POS_Y: case RivGridBoxGenerator::POS_Z: - return cvf::Vec3d(m_boundingBox.max()); + return cvf::Vec3d(m_displayCoordsBoundingBox.max()); case RivGridBoxGenerator::NEG_X: case RivGridBoxGenerator::NEG_Y: case RivGridBoxGenerator::NEG_Z: - return cvf::Vec3d(m_boundingBox.min()); + return cvf::Vec3d(m_displayCoordsBoundingBox.min()); default: break; } @@ -485,3 +521,32 @@ cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) return dir; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::computeDisplayCoords() +{ + m_displayCoordsBoundingBox.reset(); + m_displayCoordsXValues.clear(); + m_displayCoordsYValues.clear(); + m_displayCoordsZValues.clear(); + + m_displayCoordsBoundingBox.add(displayModelCoordFromDomainCoord(m_domainCoordsBoundingBox.min())); + m_displayCoordsBoundingBox.add(displayModelCoordFromDomainCoord(m_domainCoordsBoundingBox.max())); + + for (size_t i = 0; i < m_domainCoordsXValues.size(); i++) + { + m_displayCoordsXValues.push_back(m_domainCoordsXValues[i] - m_displayModelOffset.x()); + } + + for (size_t i = 0; i < m_domainCoordsYValues.size(); i++) + { + m_displayCoordsYValues.push_back(m_domainCoordsYValues[i] - m_displayModelOffset.y()); + } + + for (size_t i = 0; i < m_domainCoordsZValues.size(); i++) + { + m_displayCoordsZValues.push_back(m_scaleZ * (m_domainCoordsZValues[i] - m_displayModelOffset.z())); + } +} diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index 666b90b69c..9d5594a3dd 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -44,8 +44,9 @@ class RivGridBoxGenerator public: RivGridBoxGenerator(); - void setTransform(cvf::Transform* scaleTransform); - void setBoundingBox(const cvf::BoundingBox& boundingBox); + void setScaleZ(double scaleZ); + void setDisplayModelOffset(cvf::Vec3d offset); + void setGridBoxDomainCoordBoundingBox(const cvf::BoundingBox& boundingBox); void createGridBoxParts(); void updateFromCamera(const cvf::Camera* camera); @@ -93,12 +94,15 @@ class RivGridBoxGenerator void createGridBoxSideParts(); void createGridBoxLegendParts(); + cvf::Vec3d displayModelCoordFromDomainCoord(const cvf::Vec3d& domainCoord) const; + void createLegend(EdgeType edge, cvf::Collection* parts); cvf::Vec3f sideNormalOutwards(FaceType face); cvf::Vec3d pointOnSide(FaceType face); cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); + void computeDisplayCoords(); private: cvf::Collection m_gridBoxSideParts; @@ -106,13 +110,17 @@ class RivGridBoxGenerator cvf::ref m_gridBoxModel; - cvf::ref m_scaleTransform; - cvf::BoundingBox m_boundingBox; + cvf::BoundingBox m_domainCoordsBoundingBox; + std::vector m_domainCoordsXValues; + std::vector m_domainCoordsYValues; + std::vector m_domainCoordsZValues; - cvf::ref m_linDiscreteScalarMapper; + cvf::BoundingBox m_displayCoordsBoundingBox; + std::vector m_displayCoordsXValues; + std::vector m_displayCoordsYValues; + std::vector m_displayCoordsZValues; - std::vector m_xValues; - std::vector m_yValues; - std::vector m_zValues; + double m_scaleZ; + cvf::Vec3d m_displayModelOffset; }; diff --git a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp index e08862d935..773603c6a6 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivPatchGenerator.cpp @@ -87,46 +87,6 @@ void RivPatchGenerator::setWindingCCW(bool windingCCW) //-------------------------------------------------------------------------------------------------- void RivPatchGenerator::generate(cvf::GeometryBuilder* builder) { -/* - CVF_ASSERT(m_cellCountU > 0); - CVF_ASSERT(m_cellCountV > 0); - - size_t numVertices = (m_cellCountU + 1)*(m_cellCountV + 1); - - Vec3fArray vertices; - vertices.reserve(numVertices); - - const Vec3d unitU = (m_extentU*m_axisU)/m_cellCountU; - const Vec3d unitV = (m_extentV*m_axisV)/m_cellCountV; - - uint v; - for (v = 0; v <= m_cellCountV; v++) - { - Vec3d rowOrigo(m_origin + unitV*v); - - uint u; - for (u = 0; u <= m_cellCountU; u++) - { - vertices.add(Vec3f(rowOrigo + unitU*u)); - } - } - - uint baseNodeIdx = builder->addVertices(vertices); - - if (m_useQuads) - { - UIntArray conn; - GeometryUtils::tesselatePatchAsQuads(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); - builder->addQuads(conn); - } - else - { - UIntArray conn; - GeometryUtils::tesselatePatchAsTriangles(m_cellCountU + 1, m_cellCountV + 1, baseNodeIdx, m_windingCCW, &conn); - builder->addTriangles(conn); - } -*/ - CVF_ASSERT(m_uValues.size() > 0); CVF_ASSERT(m_vValues.size() > 0); diff --git a/ApplicationCode/ProjectDataModel/RimCase.cpp b/ApplicationCode/ProjectDataModel/RimCase.cpp index 09e06d6f75..1baf6e8942 100644 --- a/ApplicationCode/ProjectDataModel/RimCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimCase.cpp @@ -18,6 +18,7 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RimCase.h" + #include "cafPdmObjectFactory.h" #include @@ -203,4 +204,12 @@ QString RimCase::relocateFile(const QString& orgFileName, const QString& orgNew if (foundFile) *foundFile = false; return fileName; -} \ No newline at end of file +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimCase::displayModelOffset() const +{ + return cvf::Vec3d::ZERO; +} diff --git a/ApplicationCode/ProjectDataModel/RimCase.h b/ApplicationCode/ProjectDataModel/RimCase.h index 9a8c8519b5..37dc1a9229 100644 --- a/ApplicationCode/ProjectDataModel/RimCase.h +++ b/ApplicationCode/ProjectDataModel/RimCase.h @@ -18,13 +18,20 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + #include "cafPdmField.h" #include "cafPdmObject.h" +#include "cvfVector3.h" + #include class RimView; +namespace cvf { + class BoundingBox; +} + class RimCase : public caf::PdmObject { CAF_PDM_HEADER_INIT; @@ -44,6 +51,11 @@ class RimCase : public caf::PdmObject virtual QStringList timeStepStrings() = 0; virtual QString timeStepName(int frameIdx) = 0; + virtual cvf::BoundingBox activeCellsBoundingBox() const = 0; + virtual cvf::BoundingBox allCellsBoundingBox() const = 0; + + virtual cvf::Vec3d displayModelOffset() const; + protected: static QString relocateFile(const QString& fileName, const QString& newProjectPath, const QString& oldProjectPath, bool* foundFile, std::vector* searchedPaths); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp index 04becf0527..3f6ae1084a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp @@ -356,6 +356,51 @@ void RimEclipseCase::setReservoirData(RigCaseData* eclipseCase) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RimEclipseCase::activeCellsBoundingBox() const +{ + if (m_rigEclipseCase.notNull() && m_rigEclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)) + { + return m_rigEclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)->geometryBoundingBox(); + } + else + { + return cvf::BoundingBox(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RimEclipseCase::allCellsBoundingBox() const +{ + if (m_rigEclipseCase.notNull() && m_rigEclipseCase->mainGrid()) + { + return m_rigEclipseCase->mainGrid()->boundingBox(); + } + else + { + return cvf::BoundingBox(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimEclipseCase::displayModelOffset() const +{ + if (m_rigEclipseCase.notNull() && m_rigEclipseCase->mainGrid()) + { + return m_rigEclipseCase->mainGrid()->displayModelOffset(); + } + else + { + return cvf::Vec3d::ZERO; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -468,4 +513,4 @@ QString RimEclipseCase::timeStepName(int frameIdx) QDateTime date = results(RifReaderInterface::MATRIX_RESULTS)->cellResults()->timeStepDate(0,frameIdx); return date.toString(m_timeStepFormatString); -} \ No newline at end of file +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.h b/ApplicationCode/ProjectDataModel/RimEclipseCase.h index c3be567624..47521175c2 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.h @@ -71,9 +71,9 @@ class RimEclipseCase : public RimCase RigCaseData* reservoirData(); const RigCaseData* reservoirData() const; - RimReservoirCellResultsStorage* results(RifReaderInterface::PorosityModelResultType porosityModel); + RimReservoirCellResultsStorage* results(RifReaderInterface::PorosityModelResultType porosityModel); - RimEclipseView* createAndAddReservoirView(); + RimEclipseView* createAndAddReservoirView(); void removeResult(const QString& resultName); @@ -88,6 +88,10 @@ class RimEclipseCase : public RimCase virtual QStringList timeStepStrings(); virtual QString timeStepName(int frameIdx); + virtual cvf::BoundingBox activeCellsBoundingBox() const; + virtual cvf::BoundingBox allCellsBoundingBox() const; + virtual cvf::Vec3d displayModelOffset() const; + // Overridden methods from PdmObject public: diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 57bf83ae7a..718d4cbce6 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -70,6 +70,7 @@ #include #include +#include "RivGridBoxGenerator.h" @@ -227,6 +228,8 @@ void RimEclipseView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c } else if (changedField == &showInactiveCells) { + this->updateGridBoxData(); + this->scheduleGeometryRegen(INACTIVE); this->scheduleGeometryRegen(RANGE_FILTERED_INACTIVE); @@ -480,8 +483,6 @@ void RimEclipseView::createDisplayModel() m_overlayInfoConfig()->update3DInfo(); updateLegends(); } - - m_viewer->showGridBox(true); } @@ -1682,6 +1683,32 @@ void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::updateGridBoxData() +{ + if (viewer()) + { + RivGridBoxGenerator* gridBoxGen = viewer()->gridBoxGenerator(); + + gridBoxGen->setScaleZ(scaleZ); + + if (showInactiveCells) + { + gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->allCellsBoundingBox()); + } + else + { + gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->activeCellsBoundingBox()); + } + + gridBoxGen->setDisplayModelOffset(ownerCase()->displayModelOffset()); + + gridBoxGen->createGridBoxParts(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index c4cbc3af5c..fd523f5f9e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -126,6 +126,8 @@ class RimEclipseView : public RimView const std::vector& visibleGridParts() const { return m_visibleGridParts;} cvf::cref reservoirGridPartManager() const { return m_reservoirGridPartManager.p(); } + virtual void updateGridBoxData(); + // Does this belong here, really ? void calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleCells, RigGridBase * grid); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index 17a8230f17..a58f74bd0a 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -18,14 +18,19 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RimGeoMechCase.h" -#include "RimGeoMechView.h" + #include "RiaApplication.h" #include "RiaPreferences.h" + #include "RifOdbReader.h" -#include "RigGeoMechCaseData.h" + +#include "RigFemPartCollection.h" #include "RigFemPartResultsCollection.h" -#include "RimProject.h" +#include "RigGeoMechCaseData.h" + +#include "RimGeoMechView.h" #include "RimMainPlotCollection.h" +#include "RimProject.h" #include "RimWellLogPlotCollection.h" #include @@ -179,3 +184,26 @@ QString RimGeoMechCase::timeStepName(int frameIdx) return QString::fromStdString(stepNames[frameIdx]); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RimGeoMechCase::activeCellsBoundingBox() const +{ + return allCellsBoundingBox(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RimGeoMechCase::allCellsBoundingBox() const +{ + if (m_geoMechCaseData.notNull() && m_geoMechCaseData->femParts()) + { + return m_geoMechCaseData->femParts()->boundingBox(); + } + else + { + return cvf::BoundingBox(); + } +} diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h index a5304f29b9..ff65abe38e 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h @@ -59,6 +59,9 @@ class RimGeoMechCase : public RimCase virtual QStringList timeStepStrings(); virtual QString timeStepName(int frameIdx); + virtual cvf::BoundingBox activeCellsBoundingBox() const; + virtual cvf::BoundingBox allCellsBoundingBox() const; + // Fields: caf::PdmChildArrayField geoMechViews; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index f1be68b085..f81f574e99 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -250,8 +250,6 @@ void RimGeoMechView::createDisplayModel() m_vizLogic->updateStaticCellColors(-1); m_overlayInfoConfig()->update3DInfo(); } - - m_viewer->showGridBox(true); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index f2a6247c25..7ff03ce908 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -19,6 +19,7 @@ #include "RiuMainWindow.h" #include "RiuViewer.h" +#include "RivGridBoxGenerator.h" #include "RivWellPathCollectionPartMgr.h" #include "cafFrameAnimationControl.h" @@ -178,6 +179,7 @@ void RimView::updateViewerWidget() m_viewer = new RiuViewer(glFormat, NULL); m_viewer->setOwnerReservoirView(this); + this->updateGridBoxData(); RiuMainWindow::instance()->addViewer(m_viewer->layoutWidget(), windowGeometry()); m_viewer->setMinNearPlaneDistance(10); @@ -246,6 +248,17 @@ void RimView::setCurrentTimeStep(int frameIndex) m_currentReservoirCellVisibility = NULL; } this->updateCurrentTimeStep(); + + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + frameScene->removeModel(m_viewer->gridBoxGenerator()->model()); + + if (true) + { + frameScene->addModel(m_viewer->gridBoxGenerator()->model()); + } + } } //-------------------------------------------------------------------------------------------------- /// @@ -464,6 +477,8 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV { if (scaleZ < 1) scaleZ = 1; + this->updateGridBoxData(); + // Regenerate well paths RimOilField* oilFields = RiaApplication::instance()->project() ? RiaApplication::instance()->project()->activeOilField() : NULL; RimWellPathCollection* wellPathCollection = (oilFields) ? oilFields->wellPathCollection() : NULL; @@ -771,3 +786,20 @@ void RimView::removeModelByName(cvf::Scene* scene, const cvf::String& modelName) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimView::updateGridBoxData() +{ + if (viewer()) + { + RivGridBoxGenerator* gridBoxGen = viewer()->gridBoxGenerator(); + + gridBoxGen->setScaleZ(scaleZ); + gridBoxGen->setDisplayModelOffset(cvf::Vec3d::ZERO); + gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->allCellsBoundingBox()); + + gridBoxGen->createGridBoxParts(); + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 09ebd2d0dc..7b8b20769c 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -137,6 +137,8 @@ class RimView : public caf::PdmObject cvf::ref currentTotalCellVisibility(); + virtual void updateGridBoxData(); + public: virtual void loadDataAndUpdate() = 0; virtual RimCase* ownerCase() = 0; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 160d6e74f5..b1c9f05da4 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -163,7 +163,6 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) // which solves the problem setContextMenuPolicy(Qt::PreventContextMenu); - m_showGridBox = true; m_gridBoxGenerator = new RivGridBoxGenerator; } @@ -173,12 +172,12 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) //-------------------------------------------------------------------------------------------------- RiuViewer::~RiuViewer() { - if (m_reservoirView) + if (m_rimView) { - m_reservoirView->showWindow = false; - m_reservoirView->uiCapability()->updateUiIconFromToggleField(); + m_rimView->showWindow = false; + m_rimView->uiCapability()->updateUiIconFromToggleField(); - m_reservoirView->cameraPosition = m_mainCamera->viewMatrix(); + m_rimView->cameraPosition = m_mainCamera->viewMatrix(); } delete m_InfoLabel; delete m_animationProgress; @@ -258,7 +257,7 @@ void RiuViewer::slotEndAnimation() cvf::Rendering* firstRendering = m_renderingSequence->firstRendering(); CVF_ASSERT(firstRendering); - if (m_reservoirView) m_reservoirView->endAnimation(); + if (m_rimView) m_rimView->endAnimation(); caf::Viewer::slotEndAnimation(); @@ -272,12 +271,12 @@ void RiuViewer::slotSetCurrentFrame(int frameIndex) { setCurrentFrame(frameIndex); - if (m_reservoirView) + if (m_rimView) { - RimViewLinker* viewLinker = m_reservoirView->assosiatedViewLinker(); + RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker(); if (viewLinker) { - viewLinker->updateTimeStep(m_reservoirView, frameIndex); + viewLinker->updateTimeStep(m_rimView, frameIndex); } } } @@ -303,7 +302,7 @@ void RiuViewer::setPointOfInterest(cvf::Vec3d poi) //-------------------------------------------------------------------------------------------------- void RiuViewer::setOwnerReservoirView(RimView * owner) { - m_reservoirView = owner; + m_rimView = owner; m_viewerCommands->setOwnerView(owner); } @@ -340,7 +339,7 @@ void RiuViewer::paintOverlayItems(QPainter* painter) if (showAnimBar && m_showAnimProgress) { - QString stepName = m_reservoirView->ownerCase()->timeStepName(currentFrameIndex()); + QString stepName = m_rimView->ownerCase()->timeStepName(currentFrameIndex()); m_animationProgress->setFormat("Time Step: %v/%m " + stepName); m_animationProgress->setMinimum(0); m_animationProgress->setMaximum(static_cast(frameCount()) - 1); @@ -501,17 +500,12 @@ void RiuViewer::navigationPolicyUpdate() { caf::Viewer::navigationPolicyUpdate(); - if (m_reservoirView) + if (m_rimView) { - RimViewLinker* viewLinker = m_reservoirView->assosiatedViewLinker(); + RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker(); if (viewLinker) { - viewLinker->updateCamera(m_reservoirView); - } - - if (m_showGridBox) - { - m_gridBoxGenerator->updateFromCamera(mainCamera()); + viewLinker->updateCamera(m_rimView); } } } @@ -524,7 +518,7 @@ void RiuViewer::setCurrentFrame(int frameIndex) cvf::Rendering* firstRendering = m_renderingSequence->firstRendering(); CVF_ASSERT(firstRendering); - if (m_reservoirView) m_reservoirView->setCurrentTimeStep(frameIndex); + if (m_rimView) m_rimView->setCurrentTimeStep(frameIndex); caf::Viewer::slotSetCurrentFrame(frameIndex); } @@ -534,27 +528,13 @@ void RiuViewer::setCurrentFrame(int frameIndex) //-------------------------------------------------------------------------------------------------- RimView* RiuViewer::ownerReservoirView() { - return m_reservoirView; + return m_rimView; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuViewer::showGridBox(bool enable) +RivGridBoxGenerator* RiuViewer::gridBoxGenerator() const { - m_showGridBox = enable; - - if (!enable) - { - currentScene()->removeModel(m_gridBoxGenerator->model()); - } - else - { - m_gridBoxGenerator->setBoundingBox(mainScene()->boundingBox()); -// m_gridBoxGenerator->setTransform(); - m_gridBoxGenerator->updateFromCamera(mainCamera()); - m_gridBoxGenerator->createGridBoxParts(); - - currentScene()->addModel(m_gridBoxGenerator->model()); - } + return m_gridBoxGenerator; } diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index e32aa09a7a..a9bec34b4b 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -69,7 +69,7 @@ class RiuViewer : public caf::Viewer void setHistogram(double min, double max, const std::vector& histogram); void setHistogramPercentiles(double pmin, double pmax, double mean); - void showGridBox(bool enable); + RivGridBoxGenerator* gridBoxGenerator() const; void showAnimationProgress(bool enable); @@ -92,7 +92,6 @@ public slots: void mouseReleaseEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - QLabel* m_InfoLabel; QLabel* m_versionInfoLabel; bool m_showInfoText; @@ -107,12 +106,11 @@ public slots: cvf::Collection m_visibleLegends; - caf::PdmPointer m_reservoirView; - QPoint m_lastMousePressPosition; + caf::PdmPointer m_rimView; + QPoint m_lastMousePressPosition; - RiuViewerCommands* m_viewerCommands; + RiuViewerCommands* m_viewerCommands; - bool m_showGridBox; - RivGridBoxGenerator* m_gridBoxGenerator; + RivGridBoxGenerator* m_gridBoxGenerator; }; From 121ee80295196d57307a199c32f23e918482592f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 08:06:25 +0100 Subject: [PATCH 043/290] (#266) Cleaned up access to boundingBox --- ApplicationCode/UserInterface/RiuViewer.cpp | 2 ++ Fwk/AppFwk/cafViewer/cafViewer.cpp | 9 +-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index b1c9f05da4..57b991b9ad 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -507,6 +507,8 @@ void RiuViewer::navigationPolicyUpdate() { viewLinker->updateCamera(m_rimView); } + + m_gridBoxGenerator->updateFromCamera(mainCamera()); } } diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 4e7af4fa1d..1f0df3923f 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -528,14 +528,7 @@ void caf::Viewer::setView(const cvf::Vec3d& alongDirection, const cvf::Vec3d& up //-------------------------------------------------------------------------------------------------- void caf::Viewer::zoomAll() { - cvf::BoundingBox bb; - - cvf::Scene* scene = m_renderingSequence->firstRendering()->scene(); - if (scene) - { - bb = scene->boundingBox(); - } - + cvf::BoundingBox bb = m_renderingSequence->boundingBox(); if (!bb.isValid()) { return; From 6e56ee28c21c75488916a605cabd2b4348bf79e7 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 10:00:22 +0100 Subject: [PATCH 044/290] (#266) Functions to be called from a constructor cannot be virtual Improved immediate mode to be applied on all renderings --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 20 ++++++++++++++------ Fwk/AppFwk/cafViewer/cafViewer.h | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 1f0df3923f..88e6a236ae 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -135,7 +135,7 @@ caf::Viewer::~Viewer() } //-------------------------------------------------------------------------------------------------- -/// This method is supposed to setup the contents of the main rendering +/// //-------------------------------------------------------------------------------------------------- void caf::Viewer::setupMainRendering() { @@ -152,9 +152,7 @@ void caf::Viewer::setupMainRendering() } //-------------------------------------------------------------------------------------------------- -/// This method is supposed to assemble the rendering sequence (cvf::RenderSequence) based on -/// the Viewers renderings. THe ViewerBase has only one rendering. The m_mainRendering -/// Reimplement to build more advanced rendering sequences +/// //-------------------------------------------------------------------------------------------------- void caf::Viewer::setupRenderingSequence() { @@ -163,7 +161,6 @@ void caf::Viewer::setupRenderingSequence() updateCamera(width(), height()); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -754,9 +751,20 @@ QSize caf::Viewer::sizeHint() const return QSize(500, 400); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- void caf::Viewer::enableForcedImmediateMode(bool enable) { - m_mainRendering->renderEngine()->enableForcedImmediateMode(enable); + cvf::uint rIdx = m_renderingSequence->renderingCount(); + for (rIdx = 0; rIdx < m_renderingSequence->renderingCount(); rIdx++) + { + cvf::Rendering* rendering = m_renderingSequence->rendering(rIdx); + if (rendering && rendering->scene()) + { + rendering->renderEngine()->enableForcedImmediateMode(enable); + } + } } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index a10c0caf3d..96f0f242aa 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -146,8 +146,6 @@ public slots: virtual void paintOverlayItems(QPainter* painter) {}; // Overridable methods to setup the render system - virtual void setupMainRendering(); - virtual void setupRenderingSequence(); virtual void optimizeClippingPlanes(); // Standard overrides. Not for overriding @@ -169,6 +167,9 @@ public slots: double m_maxFarPlaneDistance; private: + void setupMainRendering(); + void setupRenderingSequence(); + void updateCamera(int width, int height); void releaseOGlResourcesForCurrentFrame(); From d72861f929df24ce8a2b62dea5775f141d89e5de Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 10:01:50 +0100 Subject: [PATCH 045/290] (#266) Show highlight viz models in overlay rendering --- .../ProjectDataModel/RimEclipseView.cpp | 82 +++++++++++-------- .../ProjectDataModel/RimEclipseView.h | 1 + ApplicationCode/UserInterface/RiuViewer.cpp | 77 +++++++++++++++-- ApplicationCode/UserInterface/RiuViewer.h | 13 ++- 4 files changed, 127 insertions(+), 46 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 718d4cbce6..9901e407da 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -483,9 +483,55 @@ void RimEclipseView::createDisplayModel() m_overlayInfoConfig()->update3DInfo(); updateLegends(); } + + createOverlayDisplayModel(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::createOverlayDisplayModel() +{ + cvf::ref overlayScene = new cvf::Scene; + + { + cvf::String highlightModelName = "HighLightModel"; + + cvf::ref highlightModelBasicList = new cvf::ModelBasicList; + highlightModelBasicList->setName(highlightModelName); + + RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + std::vector items; + riuSelManager->selectedItems(items); + for (size_t i = 0; i < items.size(); i++) + { + if (items[i]->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) + { + RiuEclipseSelectionItem* eclipseSelItem = static_cast(items[i]); + if (eclipseSelItem && + eclipseSelItem->m_view) + { + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); + + RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); + + cvf::ref part = partGen.createPart(eclipseSelItem->m_color); + part->setTransform(this->scaleTransform()); + + highlightModelBasicList->addPart(part.p()); + } + } + } + + highlightModelBasicList->updateBoundingBoxesRecursive(); + overlayScene->addModel(highlightModelBasicList.p()); + } + + m_viewer->setOverlayScene(overlayScene.p()); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -678,42 +724,6 @@ void RimEclipseView::updateCurrentTimeStep() currentActiveCellInfo()->geometryBoundingBox(), m_reservoirGridPartManager->scaleTransform()); - - { - cvf::String highlightModelName = "HighLightModel"; - - this->removeModelByName(frameScene, highlightModelName); - - cvf::ref highlightModelBasicList = new cvf::ModelBasicList; - highlightModelBasicList->setName(highlightModelName); - - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - std::vector items; - riuSelManager->selectedItems(items); - for (size_t i = 0; i < items.size(); i++) - { - if (items[i]->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) - { - RiuEclipseSelectionItem* eclipseSelItem = static_cast(items[i]); - if (eclipseSelItem && - eclipseSelItem->m_view) - { - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); - - RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); - - cvf::ref part = partGen.createPart(eclipseSelItem->m_color); - part->setTransform(this->scaleTransform()); - - highlightModelBasicList->addPart(part.p()); - } - } - } - - highlightModelBasicList->updateBoundingBoxesRecursive(); - frameScene->addModel(highlightModelBasicList.p()); - } } } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index fd523f5f9e..0c35cef774 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -142,6 +142,7 @@ class RimEclipseView : public RimView private: void createDisplayModel(); + void createOverlayDisplayModel(); void updateDisplayModelVisibility(); virtual void updateCurrentTimeStep(); diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 57b991b9ad..25554260fe 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -41,6 +41,7 @@ #include "cvfCamera.h" #include "cvfFont.h" #include "cvfOverlayAxisCross.h" +#include "cvfRenderQueueSorter.h" #include "cvfRenderSequence.h" #include "cvfRendering.h" #include "cvfScene.h" @@ -164,6 +165,8 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) setContextMenuPolicy(Qt::PreventContextMenu); m_gridBoxGenerator = new RivGridBoxGenerator; + + setupRenderingSequence(); } @@ -192,21 +195,13 @@ RiuViewer::~RiuViewer() //-------------------------------------------------------------------------------------------------- void RiuViewer::setDefaultView() { - cvf::BoundingBox bb; - - cvf::Scene* scene = m_renderingSequence->firstRendering()->scene(); - if (scene) - { - bb = scene->boundingBox(); - } - + cvf::BoundingBox bb = m_renderingSequence->boundingBox(); if (!bb.isValid()) { bb.add(cvf::Vec3d(-1, -1, -1)); bb.add(cvf::Vec3d( 1, 1, 1)); } - if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) { m_mainCamera->setProjectionAsPerspective(40.0, RI_MIN_NEARPLANE_DISTANCE, 1000); @@ -540,3 +535,67 @@ RivGridBoxGenerator* RiuViewer::gridBoxGenerator() const { return m_gridBoxGenerator; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setupRenderingSequence() +{ + m_overlayRendering = new cvf::Rendering; + m_overlayRendering->setCamera(new cvf::Camera); + m_overlayRendering->setRenderQueueSorter(new cvf::RenderQueueSorterBasic(cvf::RenderQueueSorterBasic::EFFECT_ONLY)); + m_overlayRendering->setClearMode(cvf::Viewport::DO_NOT_CLEAR); + + // Set fixed function rendering if QGLFormat does not support directRendering + if (!this->format().directRendering()) + { + m_overlayRendering->renderEngine()->enableForcedImmediateMode(true); + } + + m_renderingSequence->addRendering(m_overlayRendering.p()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setOverlayScene(cvf::Scene* scene) +{ + m_overlayRendering->setScene(scene); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::copyCameraView(cvf::Camera* srcCamera, cvf::Camera* dstCamera) +{ + if (srcCamera->projection() == cvf::Camera::PERSPECTIVE) + { + dstCamera->setProjectionAsPerspective(srcCamera->fieldOfViewYDeg(), srcCamera->nearPlane(), srcCamera->farPlane()); + } + else + { + dstCamera->setProjectionAsOrtho(srcCamera->frontPlaneFrustumHeight(), srcCamera->nearPlane(), srcCamera->farPlane()); + } + + dstCamera->setViewMatrix(srcCamera->viewMatrix()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::optimizeClippingPlanes() +{ + caf::Viewer::optimizeClippingPlanes(); + + copyCameraView(m_mainCamera.p(), m_overlayRendering->camera()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::resizeGL(int width, int height) +{ + caf::Viewer::resizeGL(width, height); + + m_overlayRendering->camera()->viewport()->set(0, 0, width, height); +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index a9bec34b4b..b9ca85bb5e 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -56,6 +56,8 @@ class RiuViewer : public caf::Viewer RiuViewer(const QGLFormat& format, QWidget* parent); ~RiuViewer(); + void setOverlayScene(cvf::Scene* scene); + void setDefaultView(); cvf::Vec3d pointOfInterest(); void setPointOfInterest(cvf::Vec3d poi); @@ -86,12 +88,20 @@ public slots: virtual void slotSetCurrentFrame(int frameIndex); virtual void slotEndAnimation(); +protected: + virtual void optimizeClippingPlanes(); + virtual void resizeGL(int width, int height); + private: void paintOverlayItems(QPainter* painter); void mouseReleaseEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); + void setupRenderingSequence(); + static void copyCameraView(cvf::Camera* srcCamera, cvf::Camera* dstCamera); + +private: QLabel* m_InfoLabel; QLabel* m_versionInfoLabel; bool m_showInfoText; @@ -103,7 +113,6 @@ public slots: QCDEStyle* m_progressBarStyle; - cvf::Collection m_visibleLegends; caf::PdmPointer m_rimView; @@ -112,5 +121,7 @@ public slots: RiuViewerCommands* m_viewerCommands; RivGridBoxGenerator* m_gridBoxGenerator; + + cvf::ref m_overlayRendering; }; From 3bc7b88ca75cfe2c675cca74b139db9d1379bf2f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 11:30:03 +0100 Subject: [PATCH 046/290] (#266) Create parts from selection in derived classes of RimView --- .../ProjectDataModel/RimEclipseView.cpp | 77 ++++++++----------- .../ProjectDataModel/RimEclipseView.h | 3 +- .../ProjectDataModel/RimGeoMechView.cpp | 58 +++++++------- .../ProjectDataModel/RimGeoMechView.h | 4 +- ApplicationCode/ProjectDataModel/RimView.cpp | 58 +++++++++++--- ApplicationCode/ProjectDataModel/RimView.h | 7 ++ .../RiuSelectionChangedHandler.cpp | 2 +- 7 files changed, 118 insertions(+), 91 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 9901e407da..67d8b58f32 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -483,53 +483,6 @@ void RimEclipseView::createDisplayModel() m_overlayInfoConfig()->update3DInfo(); updateLegends(); } - - createOverlayDisplayModel(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseView::createOverlayDisplayModel() -{ - cvf::ref overlayScene = new cvf::Scene; - - { - cvf::String highlightModelName = "HighLightModel"; - - cvf::ref highlightModelBasicList = new cvf::ModelBasicList; - highlightModelBasicList->setName(highlightModelName); - - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - std::vector items; - riuSelManager->selectedItems(items); - for (size_t i = 0; i < items.size(); i++) - { - if (items[i]->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) - { - RiuEclipseSelectionItem* eclipseSelItem = static_cast(items[i]); - if (eclipseSelItem && - eclipseSelItem->m_view) - { - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); - CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); - - RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); - - cvf::ref part = partGen.createPart(eclipseSelItem->m_color); - part->setTransform(this->scaleTransform()); - - highlightModelBasicList->addPart(part.p()); - } - } - } - - highlightModelBasicList->updateBoundingBoxesRecursive(); - overlayScene->addModel(highlightModelBasicList.p()); - } - - m_viewer->setOverlayScene(overlayScene.p()); } //-------------------------------------------------------------------------------------------------- @@ -1693,6 +1646,36 @@ void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::createPartCollectionFromSelection(cvf::Collection* parts) +{ + RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + std::vector items; + riuSelManager->selectedItems(items); + + for (size_t i = 0; i < items.size(); i++) + { + if (items[i]->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT) + { + RiuEclipseSelectionItem* eclipseSelItem = static_cast(items[i]); + if (eclipseSelItem && eclipseSelItem->m_view == this) + { + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()); + CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->reservoirData()); + + RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->reservoirData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_cellIndex); + + cvf::ref part = partGen.createPart(eclipseSelItem->m_color); + part->setTransform(this->scaleTransform()); + + parts->push_back(part.p()); + } + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 0c35cef774..7f6819fdad 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -140,9 +140,10 @@ class RimEclipseView : public RimView virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); + virtual void createPartCollectionFromSelection(cvf::Collection* parts); + private: void createDisplayModel(); - void createOverlayDisplayModel(); void updateDisplayModelVisibility(); virtual void updateCurrentTimeStep(); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index f81f574e99..b4fb832a75 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -43,6 +43,7 @@ #include "RivGeoMechPartMgr.h" #include "RivGeoMechPartMgrCache.h" #include "RivGeoMechVizLogic.h" +#include "RivGridBoxGenerator.h" #include "RivSingleCellPartGenerator.h" #include "cafCadNavigation.h" @@ -284,36 +285,6 @@ void RimGeoMechView::updateCurrentTimeStep() femBBox, scaleTransform()); frameScene->addModel(wellPathModel.p()); - - { - cvf::String highlightModelName = "HighLightModel"; - cvf::ref highlightModelBasicList = new cvf::ModelBasicList; - highlightModelBasicList->setName(highlightModelName); - - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - std::vector items; - riuSelManager->selectedItems(items); - for (size_t i = 0; i < items.size(); i++) - { - if (items[i]->type() == RiuSelectionItem::GEOMECH_SELECTION_OBJECT) - { - RiuGeoMechSelectionItem* geomSelItem = static_cast(items[i]); - if (geomSelItem && - geomSelItem->m_view && - geomSelItem->m_view->geoMechCase()) - { - RivSingleCellPartGenerator partGen(geomSelItem->m_view->geoMechCase(), geomSelItem->m_gridIndex, geomSelItem->m_cellIndex); - cvf::ref part = partGen.createPart(geomSelItem->m_color); - part->setTransform(this->scaleTransform()); - - highlightModelBasicList->addPart(part.p()); - } - } - } - - highlightModelBasicList->updateBoundingBoxesRecursive(); - frameScene->addModel(highlightModelBasicList.p()); - } } } @@ -615,6 +586,33 @@ void RimGeoMechView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV m_vizLogic->calculateCurrentTotalCellVisibility(totalVisibility, m_currentTimeStep); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechView::createPartCollectionFromSelection(cvf::Collection* parts) +{ + RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + std::vector items; + riuSelManager->selectedItems(items); + for (size_t i = 0; i < items.size(); i++) + { + if (items[i]->type() == RiuSelectionItem::GEOMECH_SELECTION_OBJECT) + { + RiuGeoMechSelectionItem* geomSelItem = static_cast(items[i]); + if (geomSelItem && + geomSelItem->m_view == this && + geomSelItem->m_view->geoMechCase()) + { + RivSingleCellPartGenerator partGen(geomSelItem->m_view->geoMechCase(), geomSelItem->m_gridIndex, geomSelItem->m_cellIndex); + cvf::ref part = partGen.createPart(geomSelItem->m_color); + part->setTransform(this->scaleTransform()); + + parts->push_back(part.p()); + } + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index 710162393e..823e173b3d 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -80,7 +80,8 @@ class RimGeoMechView : public RimView protected: virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); - + + virtual void createPartCollectionFromSelection(cvf::Collection* parts); private: virtual void createDisplayModel(); @@ -103,6 +104,7 @@ class RimGeoMechView : public RimView virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); + caf::PdmChildField m_propertyFilterCollection; caf::PdmPointer m_overridePropertyFilterCollection; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 7ff03ce908..3679598883 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -248,17 +248,6 @@ void RimView::setCurrentTimeStep(int frameIndex) m_currentReservoirCellVisibility = NULL; } this->updateCurrentTimeStep(); - - cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); - if (frameScene) - { - frameScene->removeModel(m_viewer->gridBoxGenerator()->model()); - - if (true) - { - frameScene->addModel(m_viewer->gridBoxGenerator()->model()); - } - } } //-------------------------------------------------------------------------------------------------- /// @@ -281,6 +270,7 @@ void RimView::createDisplayModelAndRedraw() createDisplayModel(); updateDisplayModelVisibility(); + createOverlayDisplayModel(); if (cameraPosition().isIdentity()) { @@ -803,3 +793,49 @@ void RimView::updateGridBoxData() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimView::createOverlayDisplayModelAndRedraw() +{ + createOverlayDisplayModel(); + + if (m_viewer) + { + m_viewer->update(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimView::createOverlayDisplayModel() +{ + cvf::ref overlayScene = new cvf::Scene; + + cvf::Collection parts; + createPartCollectionFromSelection(&parts); + if (parts.size() > 0) + { + cvf::String highlightModelName = "HighLightModel"; + + cvf::ref highlightModelBasicList = new cvf::ModelBasicList; + highlightModelBasicList->setName(highlightModelName); + + for (size_t i = 0; i < parts.size(); i++) + { + highlightModelBasicList->addPart(parts[i].p()); + } + + highlightModelBasicList->updateBoundingBoxesRecursive(); + overlayScene->addModel(highlightModelBasicList.p()); + } + + if (true) + { + overlayScene->addModel(m_viewer->gridBoxGenerator()->model()); + } + + m_viewer->setOverlayScene(overlayScene.p()); +} + diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 7b8b20769c..e13bac0153 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -31,6 +31,7 @@ #include "cvfArray.h" #include "cvfBase.h" +#include "cvfCollection.h" #include "cvfObject.h" #include @@ -51,6 +52,7 @@ namespace cvf class Scene; class String; class Transform; + class Part; } //================================================================================================== @@ -130,6 +132,7 @@ class RimView : public caf::PdmObject virtual void scheduleGeometryRegen(RivCellSetEnum geometryType) = 0; void scheduleCreateDisplayModelAndRedraw(); void createDisplayModelAndRedraw(); + void createOverlayDisplayModelAndRedraw(); RimViewController* viewController() const; bool isMasterView() const; @@ -158,6 +161,10 @@ class RimView : public caf::PdmObject static void removeModelByName(cvf::Scene* scene, const cvf::String& modelName); virtual void createDisplayModel() = 0; + + void createOverlayDisplayModel(); + virtual void createPartCollectionFromSelection(cvf::Collection* parts) = 0; + virtual void updateDisplayModelVisibility() = 0; virtual void clampCurrentTimestep() = 0; diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index b6fe284201..6a0dcaab39 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -202,7 +202,7 @@ void RiuSelectionChangedHandler::scheduleUpdateForAllVisibleViews() const for (size_t i = 0; i < visibleViews.size(); i++) { - visibleViews[i]->scheduleCreateDisplayModelAndRedraw(); + visibleViews[i]->createOverlayDisplayModelAndRedraw(); } } } From 019c35540d46a1be370ea870da51058684999b96 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 11:44:41 +0100 Subject: [PATCH 047/290] (#266) Added showGridBox to RimView --- ApplicationCode/ProjectDataModel/RimEclipseView.cpp | 1 + ApplicationCode/ProjectDataModel/RimView.cpp | 8 +++++++- ApplicationCode/ProjectDataModel/RimView.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 67d8b58f32..9d300afe4f 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1299,6 +1299,7 @@ void RimEclipseView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& caf::PdmUiGroup* viewGroup = uiOrdering.addNewGroup("Viewer"); viewGroup->add(&name); viewGroup->add(&backgroundColor); + viewGroup->add(&showGridBox); caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Grid Appearance"); gridGroup->add(&scaleZ); diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 3679598883..290023d386 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -101,6 +101,8 @@ RimView::RimView(void) CAF_PDM_InitField(&meshMode, "MeshMode", defaultMeshType, "Grid lines", "", "", ""); CAF_PDM_InitFieldNoDefault(&surfaceMode, "SurfaceMode", "Grid surface", "", "", ""); + CAF_PDM_InitField(&showGridBox, "ShowGridBox", true, "Show Grid Box", "", "", ""); + CAF_PDM_InitField(&m_disableLighting, "DisableLighting", false, "Disable Results Lighting", "", "Disable light model for scalar result colors", ""); CAF_PDM_InitFieldNoDefault(&windowGeometry, "WindowGeometry", "", "", "", ""); @@ -509,6 +511,10 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV updateDisplayModelVisibility(); RiuMainWindow::instance()->refreshDrawStyleActions(); } + else if (changedField == &showGridBox) + { + createOverlayDisplayModelAndRedraw(); + } else if (changedField == &m_disableLighting) { createDisplayModel(); @@ -831,7 +837,7 @@ void RimView::createOverlayDisplayModel() overlayScene->addModel(highlightModelBasicList.p()); } - if (true) + if (showGridBox) { overlayScene->addModel(m_viewer->gridBoxGenerator()->model()); } diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index e13bac0153..65c4a28c5c 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -108,6 +108,7 @@ class RimView : public caf::PdmObject caf::PdmField< caf::AppEnum< MeshModeType > > meshMode; caf::PdmField< caf::AppEnum< SurfaceModeType > > surfaceMode; + caf::PdmField showGridBox; void setMeshOnlyDrawstyle(); void setMeshSurfDrawstyle(); From 2c1b96025153c84e04f74bf2350d0cb963491b38 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 12:08:53 +0100 Subject: [PATCH 048/290] (#266) Update grid box model in optimizeClippingPlanes --- ApplicationCode/ProjectDataModel/RimView.cpp | 2 +- ApplicationCode/UserInterface/RiuViewer.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 290023d386..d9f503573b 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -271,8 +271,8 @@ void RimView::createDisplayModelAndRedraw() this->clampCurrentTimestep(); createDisplayModel(); - updateDisplayModelVisibility(); createOverlayDisplayModel(); + updateDisplayModelVisibility(); if (cameraPosition().isIdentity()) { diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 25554260fe..ff3f7fc1cf 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -502,8 +502,6 @@ void RiuViewer::navigationPolicyUpdate() { viewLinker->updateCamera(m_rimView); } - - m_gridBoxGenerator->updateFromCamera(mainCamera()); } } @@ -587,7 +585,8 @@ void RiuViewer::optimizeClippingPlanes() { caf::Viewer::optimizeClippingPlanes(); - copyCameraView(m_mainCamera.p(), m_overlayRendering->camera()); + m_gridBoxGenerator->updateFromCamera(mainCamera()); + copyCameraView(mainCamera(), m_overlayRendering->camera()); } //-------------------------------------------------------------------------------------------------- From a7656e236759556014697d7d6dc628024d612c26 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 13:37:13 +0100 Subject: [PATCH 049/290] (#266) Added edge visibility calculation for when to show legend --- .../GridBox/RivGridBoxGenerator.cpp | 80 ++++++++++++++++++- .../GridBox/RivGridBoxGenerator.h | 33 ++++---- 2 files changed, 94 insertions(+), 19 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 849ef34c43..24a3c0181e 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -107,6 +107,7 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) if (m_gridBoxSideParts.size() == 0) return; + std::vector sideVisibility(6, false); for (size_t i = POS_X; i <= NEG_Z; i++) { cvf::Vec3f sideNorm = sideNormalOutwards((FaceType)i); @@ -117,12 +118,87 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) if (sideNorm.dot(cvf::Vec3f(camToSide)) < 0.0) { m_gridBoxModel->addPart(m_gridBoxSideParts[i].p()); + sideVisibility[i] = true; } } - for (size_t i = 0; i < m_gridBoxLegendParts.size(); i++) + std::vector edgeVisibility(12, false); + computeEdgeVisibility(sideVisibility, edgeVisibility); + + // We have two parts for each edge - line and text + CVF_ASSERT(m_gridBoxLegendParts.size() == (NEG_X_NEG_Y + 1)*2); + for (size_t i = POS_Z_POS_X; i <= NEG_X_NEG_Y; i++) + { + if (edgeVisibility[i]) + { + m_gridBoxModel->addPart(m_gridBoxLegendParts[2 * i].p()); + m_gridBoxModel->addPart(m_gridBoxLegendParts[2 * i + 1].p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::computeEdgeVisibility(const std::vector& faceVisibility, std::vector& edgeVisibility) +{ + CVF_ASSERT(faceVisibility.size() == NEG_Z); + CVF_ASSERT(edgeVisibility.size() == NEG_X_NEG_Y); + + // POS Z + if (faceVisibility[POS_Z] ^ faceVisibility[POS_X]) + { + edgeVisibility[POS_Z_POS_X] = true; + } + if (faceVisibility[POS_Z] ^ faceVisibility[NEG_X]) + { + edgeVisibility[POS_Z_NEG_X] = true; + } + if (faceVisibility[POS_Z] ^ faceVisibility[POS_Y]) + { + edgeVisibility[POS_Z_POS_Y] = true; + } + if (faceVisibility[POS_Z] ^ faceVisibility[NEG_Y]) + { + edgeVisibility[POS_Z_NEG_Y] = true; + } + + // NEG Z + if (faceVisibility[NEG_Z] ^ faceVisibility[POS_X]) + { + edgeVisibility[NEG_Z_POS_X] = true; + } + if (faceVisibility[NEG_Z] ^ faceVisibility[NEG_X]) + { + edgeVisibility[NEG_Z_NEG_X] = true; + } + if (faceVisibility[NEG_Z] ^ faceVisibility[POS_Y]) + { + edgeVisibility[NEG_Z_POS_Y] = true; + } + if (faceVisibility[NEG_Z] ^ faceVisibility[NEG_Y]) + { + edgeVisibility[NEG_Z_NEG_Y] = true; + } + + // POS X + if (faceVisibility[POS_X] ^ faceVisibility[POS_Y]) + { + edgeVisibility[POS_X_POS_Y] = true; + } + if (faceVisibility[POS_X] ^ faceVisibility[NEG_Y]) + { + edgeVisibility[POS_X_NEG_Y] = true; + } + + // NEG X + if (faceVisibility[NEG_X] ^ faceVisibility[POS_Y]) + { + edgeVisibility[NEG_X_POS_Y] = true; + } + if (faceVisibility[NEG_X] ^ faceVisibility[NEG_Y]) { - m_gridBoxModel->addPart(m_gridBoxLegendParts[i].p()); + edgeVisibility[NEG_X_NEG_Y] = true; } } diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index 9d5594a3dd..2a42411ba4 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -89,27 +89,21 @@ class RivGridBoxGenerator NEG_X_NEG_Y }; - private: - void createGridBoxSideParts(); - void createGridBoxLegendParts(); - - cvf::Vec3d displayModelCoordFromDomainCoord(const cvf::Vec3d& domainCoord) const; + void createGridBoxSideParts(); + void createGridBoxLegendParts(); + void createLegend(EdgeType edge, cvf::Collection* parts); - void createLegend(EdgeType edge, cvf::Collection* parts); + void computeEdgeVisibility(const std::vector& faceVisibility, std::vector& edgeVisibility); - cvf::Vec3f sideNormalOutwards(FaceType face); - cvf::Vec3d pointOnSide(FaceType face); - cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); + void computeDisplayCoords(); + cvf::Vec3d displayModelCoordFromDomainCoord(const cvf::Vec3d& domainCoord) const; - void computeDisplayCoords(); + cvf::Vec3f sideNormalOutwards(FaceType face); + cvf::Vec3d pointOnSide(FaceType face); + cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); private: - cvf::Collection m_gridBoxSideParts; - cvf::Collection m_gridBoxLegendParts; - - cvf::ref m_gridBoxModel; - cvf::BoundingBox m_domainCoordsBoundingBox; std::vector m_domainCoordsXValues; std::vector m_domainCoordsYValues; @@ -120,7 +114,12 @@ class RivGridBoxGenerator std::vector m_displayCoordsYValues; std::vector m_displayCoordsZValues; - double m_scaleZ; - cvf::Vec3d m_displayModelOffset; + double m_scaleZ; + cvf::Vec3d m_displayModelOffset; + + cvf::Collection m_gridBoxSideParts; + cvf::Collection m_gridBoxLegendParts; + + cvf::ref m_gridBoxModel; }; From 401cfe81a10338957d5ba46814de85ec927761ec Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 14:08:17 +0100 Subject: [PATCH 050/290] (#266) Refactoring Limit usage of RivGridBoxGenerator to only RiuViewer Update colors of grid box based on background color Use dark gray instead of pure black --- .../GridBox/RivGridBoxGenerator.cpp | 57 ++++++++++++------- .../GridBox/RivGridBoxGenerator.h | 10 +++- .../ProjectDataModel/RimEclipseView.cpp | 35 +++--------- .../ProjectDataModel/RimEclipseView.h | 3 +- .../ProjectDataModel/RimGeoMechView.cpp | 1 - ApplicationCode/ProjectDataModel/RimView.cpp | 24 ++++---- ApplicationCode/ProjectDataModel/RimView.h | 4 +- ApplicationCode/UserInterface/RiuViewer.cpp | 44 +++++++++++--- ApplicationCode/UserInterface/RiuViewer.h | 7 ++- 9 files changed, 108 insertions(+), 77 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 24a3c0181e..b85a3050ff 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -35,6 +35,8 @@ /// //-------------------------------------------------------------------------------------------------- RivGridBoxGenerator::RivGridBoxGenerator() + : m_gridColor(cvf::Color3f::LIGHT_GRAY), + m_gridLegendColor(cvf::Color3f::BLACK) { m_gridBoxModel = new cvf::ModelBasicList; @@ -94,7 +96,7 @@ void RivGridBoxGenerator::createGridBoxParts() { computeDisplayCoords(); - createGridBoxSideParts(); + createGridBoxFaceParts(); createGridBoxLegendParts(); } @@ -105,9 +107,9 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) { m_gridBoxModel->removeAllParts(); - if (m_gridBoxSideParts.size() == 0) return; + if (m_gridBoxFaceParts.size() == 0) return; - std::vector sideVisibility(6, false); + std::vector faceVisibility(6, false); for (size_t i = POS_X; i <= NEG_Z; i++) { cvf::Vec3f sideNorm = sideNormalOutwards((FaceType)i); @@ -117,20 +119,20 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) if (sideNorm.dot(cvf::Vec3f(camToSide)) < 0.0) { - m_gridBoxModel->addPart(m_gridBoxSideParts[i].p()); - sideVisibility[i] = true; + m_gridBoxModel->addPart(m_gridBoxFaceParts[i].p()); + faceVisibility[i] = true; } } std::vector edgeVisibility(12, false); - computeEdgeVisibility(sideVisibility, edgeVisibility); + computeEdgeVisibility(faceVisibility, edgeVisibility); - // We have two parts for each edge - line and text CVF_ASSERT(m_gridBoxLegendParts.size() == (NEG_X_NEG_Y + 1)*2); for (size_t i = POS_Z_POS_X; i <= NEG_X_NEG_Y; i++) { if (edgeVisibility[i]) { + // We have two parts for each edge - line and text m_gridBoxModel->addPart(m_gridBoxLegendParts[2 * i].p()); m_gridBoxModel->addPart(m_gridBoxLegendParts[2 * i + 1].p()); } @@ -142,8 +144,8 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) //-------------------------------------------------------------------------------------------------- void RivGridBoxGenerator::computeEdgeVisibility(const std::vector& faceVisibility, std::vector& edgeVisibility) { - CVF_ASSERT(faceVisibility.size() == NEG_Z); - CVF_ASSERT(edgeVisibility.size() == NEG_X_NEG_Y); + CVF_ASSERT(faceVisibility.size() == NEG_Z + 1); + CVF_ASSERT(edgeVisibility.size() == NEG_X_NEG_Y + 1); // POS Z if (faceVisibility[POS_Z] ^ faceVisibility[POS_X]) @@ -213,9 +215,9 @@ cvf::Model* RivGridBoxGenerator::model() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivGridBoxGenerator::createGridBoxSideParts() +void RivGridBoxGenerator::createGridBoxFaceParts() { - m_gridBoxSideParts.clear(); + m_gridBoxFaceParts.clear(); CVF_ASSERT(m_displayCoordsBoundingBox.isValid()); CVF_ASSERT(m_displayCoordsXValues.size() > 0); @@ -292,12 +294,12 @@ void RivGridBoxGenerator::createGridBoxSideParts() part->updateBoundingBox(); cvf::ref eff; - caf::MeshEffectGenerator effGen(cvf::Color3f::GRAY); + caf::MeshEffectGenerator effGen(m_gridColor); eff = effGen.generateCachedEffect(); part->setEffect(eff.p()); - m_gridBoxSideParts.push_back(part.p()); + m_gridBoxFaceParts.push_back(part.p()); } } } @@ -495,13 +497,12 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection geo->addPrimitiveSet(primSet.p()); cvf::ref part = new cvf::Part; - part->setName("Legend lines "); + part->setName("Legend lines"); part->setDrawable(geo.p()); - part->updateBoundingBox(); cvf::ref eff; - caf::MeshEffectGenerator effGen(cvf::Color3f::WHITE); + caf::MeshEffectGenerator effGen(m_gridLegendColor); eff = effGen.generateCachedEffect(); part->setEffect(eff.p()); @@ -514,10 +515,9 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection cvf::ref geo = new cvf::DrawableText; geo->setFont(new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD)); - geo->setTextColor(cvf::Color3::WHITE); + geo->setTextColor(m_gridLegendColor); geo->setDrawBackground(false); geo->setDrawBorder(false); - //textGeo->setCheckPosVisible(false); for (size_t idx = 0; idx < domainCoordsTickValues->size(); idx++) { @@ -525,15 +525,13 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection } cvf::ref part = new cvf::Part; + part->setName("Legend text"); part->setDrawable(geo.p()); part->updateBoundingBox(); cvf::ref eff = new cvf::Effect; part->setEffect(eff.p()); - //textPart->setPriority(11); - part->setName("Legend text"); - parts->push_back(part.p()); } } @@ -598,6 +596,23 @@ cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) return dir; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f backgroundColor) +{ + if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) + { + m_gridColor = cvf::Color3f::LIGHT_GRAY; + m_gridLegendColor = cvf::Color3f::fromByteColor(10, 10, 10); + } + else + { + m_gridColor = cvf::Color3f::DARK_GRAY; + m_gridLegendColor = cvf::Color3f::WHITE; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index 2a42411ba4..26e59e12ea 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -47,6 +47,8 @@ class RivGridBoxGenerator void setScaleZ(double scaleZ); void setDisplayModelOffset(cvf::Vec3d offset); void setGridBoxDomainCoordBoundingBox(const cvf::BoundingBox& boundingBox); + void updateFromBackgroundColor(const cvf::Color3f backgroundColor); + void createGridBoxParts(); void updateFromCamera(const cvf::Camera* camera); @@ -90,7 +92,7 @@ class RivGridBoxGenerator }; private: - void createGridBoxSideParts(); + void createGridBoxFaceParts(); void createGridBoxLegendParts(); void createLegend(EdgeType edge, cvf::Collection* parts); @@ -102,7 +104,6 @@ class RivGridBoxGenerator cvf::Vec3f sideNormalOutwards(FaceType face); cvf::Vec3d pointOnSide(FaceType face); cvf::Vec3f cornerDirection(FaceType face1, FaceType face2); - private: cvf::BoundingBox m_domainCoordsBoundingBox; std::vector m_domainCoordsXValues; @@ -117,9 +118,12 @@ class RivGridBoxGenerator double m_scaleZ; cvf::Vec3d m_displayModelOffset; - cvf::Collection m_gridBoxSideParts; + cvf::Collection m_gridBoxFaceParts; cvf::Collection m_gridBoxLegendParts; cvf::ref m_gridBoxModel; + + cvf::Color3f m_gridColor; + cvf::Color3f m_gridLegendColor; }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 9d300afe4f..368752b653 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -70,7 +70,6 @@ #include #include -#include "RivGridBoxGenerator.h" @@ -1647,6 +1646,14 @@ void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseView::showActiveCellsOnly() +{ + return !showInactiveCells; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1677,32 +1684,6 @@ void RimEclipseView::createPartCollectionFromSelection(cvf::CollectiongridBoxGenerator(); - - gridBoxGen->setScaleZ(scaleZ); - - if (showInactiveCells) - { - gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->allCellsBoundingBox()); - } - else - { - gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->activeCellsBoundingBox()); - } - - gridBoxGen->setDisplayModelOffset(ownerCase()->displayModelOffset()); - - gridBoxGen->createGridBoxParts(); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 7f6819fdad..04db15fb42 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -126,8 +126,6 @@ class RimEclipseView : public RimView const std::vector& visibleGridParts() const { return m_visibleGridParts;} cvf::cref reservoirGridPartManager() const { return m_reservoirGridPartManager.p(); } - virtual void updateGridBoxData(); - // Does this belong here, really ? void calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleCells, RigGridBase * grid); @@ -141,6 +139,7 @@ class RimEclipseView : public RimView virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); virtual void createPartCollectionFromSelection(cvf::Collection* parts); + virtual bool showActiveCellsOnly(); private: void createDisplayModel(); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index b4fb832a75..1cbe88b322 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -43,7 +43,6 @@ #include "RivGeoMechPartMgr.h" #include "RivGeoMechPartMgrCache.h" #include "RivGeoMechVizLogic.h" -#include "RivGridBoxGenerator.h" #include "RivSingleCellPartGenerator.h" #include "cafCadNavigation.h" diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index d9f503573b..680ce1767d 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -19,7 +19,6 @@ #include "RiuMainWindow.h" #include "RiuViewer.h" -#include "RivGridBoxGenerator.h" #include "RivWellPathCollectionPartMgr.h" #include "cafFrameAnimationControl.h" @@ -181,7 +180,6 @@ void RimView::updateViewerWidget() m_viewer = new RiuViewer(glFormat, NULL); m_viewer->setOwnerReservoirView(this); - this->updateGridBoxData(); RiuMainWindow::instance()->addViewer(m_viewer->layoutWidget(), windowGeometry()); m_viewer->setMinNearPlaneDistance(10); @@ -199,6 +197,8 @@ void RimView::updateViewerWidget() if (isViewerCreated) m_viewer->mainCamera()->setViewMatrix(cameraPosition); m_viewer->mainCamera()->viewport()->setClearColor(cvf::Color4f(backgroundColor())); + this->updateGridBoxData(); + m_viewer->update(); } else @@ -787,15 +787,9 @@ void RimView::removeModelByName(cvf::Scene* scene, const cvf::String& modelName) //-------------------------------------------------------------------------------------------------- void RimView::updateGridBoxData() { - if (viewer()) + if (m_viewer) { - RivGridBoxGenerator* gridBoxGen = viewer()->gridBoxGenerator(); - - gridBoxGen->setScaleZ(scaleZ); - gridBoxGen->setDisplayModelOffset(cvf::Vec3d::ZERO); - gridBoxGen->setGridBoxDomainCoordBoundingBox(ownerCase()->allCellsBoundingBox()); - - gridBoxGen->createGridBoxParts(); + m_viewer->updateGridBoxData(); } } @@ -839,9 +833,17 @@ void RimView::createOverlayDisplayModel() if (showGridBox) { - overlayScene->addModel(m_viewer->gridBoxGenerator()->model()); + overlayScene->addModel(m_viewer->gridBoxModel()); } m_viewer->setOverlayScene(overlayScene.p()); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimView::showActiveCellsOnly() +{ + return false; +} + diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 65c4a28c5c..f9687552f8 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -141,7 +141,7 @@ class RimView : public caf::PdmObject cvf::ref currentTotalCellVisibility(); - virtual void updateGridBoxData(); + virtual bool showActiveCellsOnly(); public: virtual void loadDataAndUpdate() = 0; @@ -164,6 +164,8 @@ class RimView : public caf::PdmObject virtual void createDisplayModel() = 0; void createOverlayDisplayModel(); + void updateGridBoxData(); + virtual void createPartCollectionFromSelection(cvf::Collection* parts) = 0; virtual void updateDisplayModelVisibility() = 0; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index ff3f7fc1cf..9793bc147a 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -23,6 +23,7 @@ #include "RiaApplication.h" #include "RiaBaseDefs.h" +#include "RimCase.h" #include "RimProject.h" #include "RimView.h" #include "RimViewController.h" @@ -526,14 +527,6 @@ RimView* RiuViewer::ownerReservoirView() return m_rimView; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RivGridBoxGenerator* RiuViewer::gridBoxGenerator() const -{ - return m_gridBoxGenerator; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -598,3 +591,38 @@ void RiuViewer::resizeGL(int width, int height) m_overlayRendering->camera()->viewport()->set(0, 0, width, height); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateGridBoxData() +{ + if (ownerReservoirView() && ownerReservoirView()->ownerCase()) + { + RimView* rimView = ownerReservoirView(); + RimCase* rimCase = rimView->ownerCase(); + + m_gridBoxGenerator->setScaleZ(rimView->scaleZ); + m_gridBoxGenerator->setDisplayModelOffset(rimCase->displayModelOffset()); + m_gridBoxGenerator->updateFromBackgroundColor(rimView->backgroundColor); + + if (rimView->showActiveCellsOnly()) + { + m_gridBoxGenerator->setGridBoxDomainCoordBoundingBox(rimCase->activeCellsBoundingBox()); + } + else + { + m_gridBoxGenerator->setGridBoxDomainCoordBoundingBox(rimCase->allCellsBoundingBox()); + } + + m_gridBoxGenerator->createGridBoxParts(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Model* RiuViewer::gridBoxModel() const +{ + return m_gridBoxGenerator->model(); +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index b9ca85bb5e..b6015e6602 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -39,8 +39,9 @@ class QProgressBar; namespace cvf { - class Part; + class Model; class OverlayItem; + class Part; } //================================================================================================== @@ -71,7 +72,8 @@ class RiuViewer : public caf::Viewer void setHistogram(double min, double max, const std::vector& histogram); void setHistogramPercentiles(double pmin, double pmax, double mean); - RivGridBoxGenerator* gridBoxGenerator() const; + void updateGridBoxData(); + cvf::Model* gridBoxModel() const; void showAnimationProgress(bool enable); @@ -100,7 +102,6 @@ public slots: void setupRenderingSequence(); static void copyCameraView(cvf::Camera* srcCamera, cvf::Camera* dstCamera); - private: QLabel* m_InfoLabel; QLabel* m_versionInfoLabel; From d9044e2e7b2f290f3a77917f820e972ad4fe0efd Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 21:10:41 +0100 Subject: [PATCH 051/290] (#266) Expand bounding box to get some space between model and grid box --- .../GridBox/RivGridBoxGenerator.cpp | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index b85a3050ff..804d442573 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -65,7 +65,25 @@ void RivGridBoxGenerator::setDisplayModelOffset(cvf::Vec3d offset) //-------------------------------------------------------------------------------------------------- void RivGridBoxGenerator::setGridBoxDomainCoordBoundingBox(const cvf::BoundingBox& bb) { - m_domainCoordsBoundingBox = bb; + cvf::BoundingBox expandedBB; + { + double expandFactor = 0.05; + + cvf::Vec3d expandedMin; + expandedMin.x() = bb.min().x() - bb.extent().x() * expandFactor; + expandedMin.y() = bb.min().y() - bb.extent().y() * expandFactor; + expandedMin.z() = bb.min().z() - bb.extent().z() * expandFactor; + + cvf::Vec3d expandedMax; + expandedMax.x() = bb.max().x() + bb.extent().x() * expandFactor; + expandedMax.y() = bb.max().y() + bb.extent().y() * expandFactor; + expandedMax.z() = bb.max().z() + bb.extent().z() * expandFactor; + + expandedBB.add(expandedMin); + expandedBB.add(expandedMax); + } + + m_domainCoordsBoundingBox = expandedBB; m_domainCoordsXValues.clear(); m_domainCoordsYValues.clear(); From 96acc1e75d5fdef1a6ab98238c06f0ef5966b0d6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 16 Nov 2015 21:17:12 +0100 Subject: [PATCH 052/290] (#266) Improved label display --- .../GridBox/RivGridBoxGenerator.cpp | 21 ++++++++++++------- .../GridBox/RivGridBoxGenerator.h | 5 ++++- ApplicationCode/UserInterface/RiuViewer.cpp | 9 +++++++- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 804d442573..57e365e6ea 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -34,7 +34,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivGridBoxGenerator::RivGridBoxGenerator() +RivGridBoxGenerator::RivGridBoxGenerator(cvf::ShaderProgram* textShaderProgram) : m_gridColor(cvf::Color3f::LIGHT_GRAY), m_gridLegendColor(cvf::Color3f::BLACK) { @@ -42,6 +42,12 @@ RivGridBoxGenerator::RivGridBoxGenerator() m_scaleZ = 1.0; m_displayModelOffset = cvf::Vec3d::ZERO; + + m_textEffect = new cvf::Effect; + if (textShaderProgram) + { + m_textEffect->setShaderProgram(textShaderProgram); + } } //-------------------------------------------------------------------------------------------------- @@ -93,17 +99,18 @@ void RivGridBoxGenerator::setGridBoxDomainCoordBoundingBox(const cvf::BoundingBo cvf::Vec3d max = m_domainCoordsBoundingBox.max(); cvf::ScalarMapperDiscreteLinear m_linDiscreteScalarMapper; + size_t levelCount = 6; m_linDiscreteScalarMapper.setRange(min.x(), max.x()); - m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.setLevelCount(levelCount, true); m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsXValues); m_linDiscreteScalarMapper.setRange(min.y(), max.y()); - m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.setLevelCount(levelCount, true); m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsYValues); m_linDiscreteScalarMapper.setRange(min.z(), max.z()); - m_linDiscreteScalarMapper.setLevelCount(5, true); + m_linDiscreteScalarMapper.setLevelCount(levelCount, true); m_linDiscreteScalarMapper.majorTickValues(&m_domainCoordsZValues); } @@ -537,7 +544,8 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection geo->setDrawBackground(false); geo->setDrawBorder(false); - for (size_t idx = 0; idx < domainCoordsTickValues->size(); idx++) + // Do not draw legend labels at first/last tick mark + for (size_t idx = 1; idx < domainCoordsTickValues->size() - 1; idx++) { geo->addText(cvf::String(domainCoordsTickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); } @@ -547,8 +555,7 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection part->setDrawable(geo.p()); part->updateBoundingBox(); - cvf::ref eff = new cvf::Effect; - part->setEffect(eff.p()); + part->setEffect(m_textEffect.p()); parts->push_back(part.p()); } diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index 26e59e12ea..79712c4691 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -32,6 +32,7 @@ namespace cvf { class Camera; + class ShaderProgram; } @@ -42,7 +43,7 @@ namespace cvf class RivGridBoxGenerator { public: - RivGridBoxGenerator(); + RivGridBoxGenerator(cvf::ShaderProgram* textShaderProgram); void setScaleZ(double scaleZ); void setDisplayModelOffset(cvf::Vec3d offset); @@ -125,5 +126,7 @@ class RivGridBoxGenerator cvf::Color3f m_gridColor; cvf::Color3f m_gridLegendColor; + + cvf::ref m_textEffect; }; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 9793bc147a..738ca198d8 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -39,6 +39,7 @@ #include "cafCeetronPlusNavigation.h" #include "cafEffectGenerator.h" + #include "cvfCamera.h" #include "cvfFont.h" #include "cvfOverlayAxisCross.h" @@ -46,6 +47,7 @@ #include "cvfRenderSequence.h" #include "cvfRendering.h" #include "cvfScene.h" +#include "cvfOpenGLResourceManager.h" #include #include @@ -165,7 +167,12 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) // which solves the problem setContextMenuPolicy(Qt::PreventContextMenu); - m_gridBoxGenerator = new RivGridBoxGenerator; + cvf::ShaderProgram* textShaderProgram = NULL; + if (format.directRendering()) + { + textShaderProgram = cvfOpenGLContext()->resourceManager()->getLinkedTextShaderProgram(cvfOpenGLContext()); + } + m_gridBoxGenerator = new RivGridBoxGenerator(textShaderProgram); setupRenderingSequence(); } From c6454300d8b5d0b69a693143303d6b4b7e1bcb7d Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 10:53:41 +0100 Subject: [PATCH 053/290] (#266) Added static model interface --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 76 ++++++++++++++++++++++++++++++ Fwk/AppFwk/cafViewer/cafViewer.h | 22 +++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 88e6a236ae..4feea1b921 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -200,6 +200,8 @@ cvf::Camera* caf::Viewer::mainCamera() //-------------------------------------------------------------------------------------------------- void caf::Viewer::setMainScene(cvf::Scene* scene) { + appendAllStaticModelsToFrame(scene); + m_mainScene = scene; m_mainRendering->setScene(scene); } @@ -544,6 +546,8 @@ void caf::Viewer::zoomAll() //-------------------------------------------------------------------------------------------------- void caf::Viewer::addFrame(cvf::Scene* scene) { + appendAllStaticModelsToFrame(scene); + m_frameScenes.push_back(scene); m_animationControl->setNumFrames(static_cast(m_frameScenes.size())); } @@ -816,3 +820,75 @@ void caf::Viewer::navigationPolicyUpdate() update(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::addStaticModel(cvf::Model* model) +{ + if (m_staticModels.contains(model)) return; + + m_staticModels.push_back(model); + + appendModelToAllFrames(model); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::removeStaticModel(cvf::Model* model) +{ + removeModelFromAllFrames(model); + + m_staticModels.erase(model); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::removeAllStaticModels() +{ + for (size_t i = 0; i < m_staticModels.size(); i++) + { + removeModelFromAllFrames(m_staticModels.at(i)); + } + + m_staticModels.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::removeModelFromAllFrames(cvf::Model* model) +{ + for (size_t i = 0; i < m_frameScenes.size(); i++) + { + cvf::Scene* scene = m_frameScenes.at(i); + + scene->removeModel(model); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::appendModelToAllFrames(cvf::Model* model) +{ + for (size_t i = 0; i < m_frameScenes.size(); i++) + { + cvf::Scene* scene = m_frameScenes.at(i); + + scene->addModel(model); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::appendAllStaticModelsToFrame(cvf::Scene* scene) +{ + for (size_t i = 0; i < m_staticModels.size(); i++) + { + scene->addModel(m_staticModels.at(i)); + } +} + diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 96f0f242aa..c4c132b6a7 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -49,19 +49,20 @@ namespace cvf { class Camera; - class Scene; - class Rendering; - class RenderSequence; - class OverlayScalarMapperLegend; class HitItemCollection; + class Model; class OverlayImage; + class OverlayScalarMapperLegend; + class RenderSequence; + class Rendering; + class Scene; class TextureImage; } namespace caf { class FrameAnimationControl; - class Viewer; class NavigationPolicy; + class Viewer; } class QInputEvent; @@ -93,6 +94,12 @@ class Viewer : public caf::OpenGLWidget cvf::Scene* frame(size_t frameIndex); void removeAllFrames(); + // Static models to be shown in all frames + void addStaticModel(cvf::Model* model); + void removeStaticModel(cvf::Model* model); + void removeAllStaticModels(); + + // Recursively traverse all the scenes managed by the viewer and make sure all cached values are up-to-date // Use when changing the contents inside the objects in the scene. // As of yet: Only updates bounding boxes. Other things might be added later. @@ -169,6 +176,10 @@ public slots: private: void setupMainRendering(); void setupRenderingSequence(); + + void appendAllStaticModelsToFrame(cvf::Scene* scene); + void appendModelToAllFrames(cvf::Model* model); + void removeModelFromAllFrames(cvf::Model* model); void updateCamera(int width, int height); @@ -195,6 +206,7 @@ public slots: caf::FrameAnimationControl* m_animationControl; cvf::Collection m_frameScenes; + cvf::Collection m_staticModels; }; } // End namespace caf From 9a672eccad45b7dedb5a6eaa7c0fa8d785e3b888 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 10:53:56 +0100 Subject: [PATCH 054/290] (#266) Use static model interface for static geometry --- ApplicationCode/ProjectDataModel/RimView.cpp | 8 ++- ApplicationCode/UserInterface/RiuViewer.cpp | 57 -------------------- ApplicationCode/UserInterface/RiuViewer.h | 7 --- 3 files changed, 3 insertions(+), 69 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 680ce1767d..8fd8a11bf0 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -811,7 +811,7 @@ void RimView::createOverlayDisplayModelAndRedraw() //-------------------------------------------------------------------------------------------------- void RimView::createOverlayDisplayModel() { - cvf::ref overlayScene = new cvf::Scene; + m_viewer->removeAllStaticModels(); cvf::Collection parts; createPartCollectionFromSelection(&parts); @@ -828,15 +828,13 @@ void RimView::createOverlayDisplayModel() } highlightModelBasicList->updateBoundingBoxesRecursive(); - overlayScene->addModel(highlightModelBasicList.p()); + m_viewer->addStaticModel(highlightModelBasicList.p()); } if (showGridBox) { - overlayScene->addModel(m_viewer->gridBoxModel()); + m_viewer->addStaticModel(m_viewer->gridBoxModel()); } - - m_viewer->setOverlayScene(overlayScene.p()); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 738ca198d8..945a2615a5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -173,8 +173,6 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) textShaderProgram = cvfOpenGLContext()->resourceManager()->getLinkedTextShaderProgram(cvfOpenGLContext()); } m_gridBoxGenerator = new RivGridBoxGenerator(textShaderProgram); - - setupRenderingSequence(); } @@ -534,50 +532,6 @@ RimView* RiuViewer::ownerReservoirView() return m_rimView; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewer::setupRenderingSequence() -{ - m_overlayRendering = new cvf::Rendering; - m_overlayRendering->setCamera(new cvf::Camera); - m_overlayRendering->setRenderQueueSorter(new cvf::RenderQueueSorterBasic(cvf::RenderQueueSorterBasic::EFFECT_ONLY)); - m_overlayRendering->setClearMode(cvf::Viewport::DO_NOT_CLEAR); - - // Set fixed function rendering if QGLFormat does not support directRendering - if (!this->format().directRendering()) - { - m_overlayRendering->renderEngine()->enableForcedImmediateMode(true); - } - - m_renderingSequence->addRendering(m_overlayRendering.p()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewer::setOverlayScene(cvf::Scene* scene) -{ - m_overlayRendering->setScene(scene); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewer::copyCameraView(cvf::Camera* srcCamera, cvf::Camera* dstCamera) -{ - if (srcCamera->projection() == cvf::Camera::PERSPECTIVE) - { - dstCamera->setProjectionAsPerspective(srcCamera->fieldOfViewYDeg(), srcCamera->nearPlane(), srcCamera->farPlane()); - } - else - { - dstCamera->setProjectionAsOrtho(srcCamera->frontPlaneFrustumHeight(), srcCamera->nearPlane(), srcCamera->farPlane()); - } - - dstCamera->setViewMatrix(srcCamera->viewMatrix()); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -586,17 +540,6 @@ void RiuViewer::optimizeClippingPlanes() caf::Viewer::optimizeClippingPlanes(); m_gridBoxGenerator->updateFromCamera(mainCamera()); - copyCameraView(mainCamera(), m_overlayRendering->camera()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewer::resizeGL(int width, int height) -{ - caf::Viewer::resizeGL(width, height); - - m_overlayRendering->camera()->viewport()->set(0, 0, width, height); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index b6015e6602..04b5c89376 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -57,8 +57,6 @@ class RiuViewer : public caf::Viewer RiuViewer(const QGLFormat& format, QWidget* parent); ~RiuViewer(); - void setOverlayScene(cvf::Scene* scene); - void setDefaultView(); cvf::Vec3d pointOfInterest(); void setPointOfInterest(cvf::Vec3d poi); @@ -92,7 +90,6 @@ public slots: protected: virtual void optimizeClippingPlanes(); - virtual void resizeGL(int width, int height); private: void paintOverlayItems(QPainter* painter); @@ -100,8 +97,6 @@ public slots: void mouseReleaseEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - void setupRenderingSequence(); - static void copyCameraView(cvf::Camera* srcCamera, cvf::Camera* dstCamera); private: QLabel* m_InfoLabel; QLabel* m_versionInfoLabel; @@ -122,7 +117,5 @@ public slots: RiuViewerCommands* m_viewerCommands; RivGridBoxGenerator* m_gridBoxGenerator; - - cvf::ref m_overlayRendering; }; From 518ce2d2a75711b48d000bdd31c8d906daaf736e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 11:29:15 +0100 Subject: [PATCH 055/290] (#266) Default no grid box --- ApplicationCode/ProjectDataModel/RimView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 8fd8a11bf0..634448e013 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -100,7 +100,7 @@ RimView::RimView(void) CAF_PDM_InitField(&meshMode, "MeshMode", defaultMeshType, "Grid lines", "", "", ""); CAF_PDM_InitFieldNoDefault(&surfaceMode, "SurfaceMode", "Grid surface", "", "", ""); - CAF_PDM_InitField(&showGridBox, "ShowGridBox", true, "Show Grid Box", "", "", ""); + CAF_PDM_InitField(&showGridBox, "ShowGridBox", false, "Show Grid Box", "", "", ""); CAF_PDM_InitField(&m_disableLighting, "DisableLighting", false, "Disable Results Lighting", "", "Disable light model for scalar result colors", ""); From 031ca38a53f42bad99eab08d4069c2a0d7ca43f7 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 11:29:27 +0100 Subject: [PATCH 056/290] (#266) No depth test for legend lines --- .../GridBox/RivGridBoxGenerator.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 57e365e6ea..7cc5c21a33 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -23,6 +23,7 @@ #include "RivPatchGenerator.h" #include "cafEffectGenerator.h" + #include "cvfCamera.h" #include "cvfDrawableText.h" #include "cvfFixedAtlasFont.h" @@ -30,6 +31,7 @@ #include "cvfGeometryBuilderFaceList.h" #include "cvfMeshEdgeExtractor.h" #include "cvfPrimitiveSetIndexedUInt.h" +#include "cvfRenderStateDepth.h" //-------------------------------------------------------------------------------------------------- /// @@ -528,8 +530,13 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection cvf::ref eff; caf::MeshEffectGenerator effGen(m_gridLegendColor); - eff = effGen.generateCachedEffect(); + eff = effGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + part->setPriority(1500); part->setEffect(eff.p()); parts->push_back(part.p()); @@ -628,12 +635,12 @@ void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f backgroun { if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) { - m_gridColor = cvf::Color3f::LIGHT_GRAY; + m_gridColor = cvf::Color3f::DARK_GRAY; m_gridLegendColor = cvf::Color3f::fromByteColor(10, 10, 10); } else { - m_gridColor = cvf::Color3f::DARK_GRAY; + m_gridColor = cvf::Color3f::LIGHT_GRAY; m_gridLegendColor = cvf::Color3f::WHITE; } } From 98bdb6ea6e9866aa1542d88cb1f885971f871824 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 11:51:37 +0100 Subject: [PATCH 057/290] (#266) Move far clipping plane further away --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 4feea1b921..93b3c78be1 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -278,7 +278,7 @@ void caf::Viewer::optimizeClippingPlanes() double distEyeBoxCenterAlongViewDir = (bb.center() - eye)*viewdir; - double farPlaneDist = distEyeBoxCenterAlongViewDir + bb.radius(); + double farPlaneDist = distEyeBoxCenterAlongViewDir + bb.radius() * 1.2; farPlaneDist = CVF_MIN(farPlaneDist, m_maxFarPlaneDistance); double nearPlaneDist = distEyeBoxCenterAlongViewDir - bb.radius(); @@ -830,6 +830,8 @@ void caf::Viewer::addStaticModel(cvf::Model* model) m_staticModels.push_back(model); appendModelToAllFrames(model); + + updateCachedValuesInScene(); } //-------------------------------------------------------------------------------------------------- @@ -840,6 +842,8 @@ void caf::Viewer::removeStaticModel(cvf::Model* model) removeModelFromAllFrames(model); m_staticModels.erase(model); + + updateCachedValuesInScene(); } //-------------------------------------------------------------------------------------------------- @@ -853,6 +857,8 @@ void caf::Viewer::removeAllStaticModels() } m_staticModels.clear(); + + updateCachedValuesInScene(); } //-------------------------------------------------------------------------------------------------- From 4469d32a2dd101793c0ac7c95da9d41d8f66f618 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 05:00:35 -0800 Subject: [PATCH 058/290] Fixed Linux issues --- .../GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h | 1 + ApplicationCode/ProjectDataModel/RimCase.h | 1 + 2 files changed, 2 insertions(+) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h index d9791721ae..de214036f3 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.h @@ -1,6 +1,7 @@ #pragma once +#include "cvfBase.h" #include "cvfObject.h" #include "cvfArray.h" diff --git a/ApplicationCode/ProjectDataModel/RimCase.h b/ApplicationCode/ProjectDataModel/RimCase.h index 37dc1a9229..fefae0e538 100644 --- a/ApplicationCode/ProjectDataModel/RimCase.h +++ b/ApplicationCode/ProjectDataModel/RimCase.h @@ -22,6 +22,7 @@ #include "cafPdmField.h" #include "cafPdmObject.h" +#include "cvfBase.h" #include "cvfVector3.h" #include From 08c04f505200cadb2e1672086ea0bab3e00050f0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 16:26:07 +0100 Subject: [PATCH 059/290] (#656) Added text effect to effect generator --- .../GridBox/RivGridBoxGenerator.cpp | 12 ++--- .../GridBox/RivGridBoxGenerator.h | 4 +- ApplicationCode/UserInterface/RiuViewer.cpp | 7 +-- Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp | 50 +++++++++++++++++++ Fwk/AppFwk/CommonCode/cafEffectGenerator.h | 19 +++++++ 5 files changed, 75 insertions(+), 17 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 7cc5c21a33..7ddd02bc63 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -36,7 +36,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivGridBoxGenerator::RivGridBoxGenerator(cvf::ShaderProgram* textShaderProgram) +RivGridBoxGenerator::RivGridBoxGenerator() : m_gridColor(cvf::Color3f::LIGHT_GRAY), m_gridLegendColor(cvf::Color3f::BLACK) { @@ -44,12 +44,6 @@ RivGridBoxGenerator::RivGridBoxGenerator(cvf::ShaderProgram* textShaderProgram) m_scaleZ = 1.0; m_displayModelOffset = cvf::Vec3d::ZERO; - - m_textEffect = new cvf::Effect; - if (textShaderProgram) - { - m_textEffect->setShaderProgram(textShaderProgram); - } } //-------------------------------------------------------------------------------------------------- @@ -562,7 +556,9 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection part->setDrawable(geo.p()); part->updateBoundingBox(); - part->setEffect(m_textEffect.p()); + caf::TextEffectGenerator textGen; + cvf::ref eff = textGen.generateCachedEffect(); + part->setEffect(eff.p()); parts->push_back(part.p()); } diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index 79712c4691..a5268af07f 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -43,7 +43,7 @@ namespace cvf class RivGridBoxGenerator { public: - RivGridBoxGenerator(cvf::ShaderProgram* textShaderProgram); + RivGridBoxGenerator(); void setScaleZ(double scaleZ); void setDisplayModelOffset(cvf::Vec3d offset); @@ -126,7 +126,5 @@ class RivGridBoxGenerator cvf::Color3f m_gridColor; cvf::Color3f m_gridLegendColor; - - cvf::ref m_textEffect; }; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 945a2615a5..cf76402a35 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -167,12 +167,7 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) // which solves the problem setContextMenuPolicy(Qt::PreventContextMenu); - cvf::ShaderProgram* textShaderProgram = NULL; - if (format.directRendering()) - { - textShaderProgram = cvfOpenGLContext()->resourceManager()->getLinkedTextShaderProgram(cvfOpenGLContext()); - } - m_gridBoxGenerator = new RivGridBoxGenerator(textShaderProgram); + m_gridBoxGenerator = new RivGridBoxGenerator; } diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp index 920c923b31..e97e8f7851 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.cpp @@ -887,4 +887,54 @@ EffectGenerator* MeshEffectGenerator::copy() const +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TextEffectGenerator::TextEffectGenerator() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool TextEffectGenerator::isEqual(const EffectGenerator* other) const +{ + const TextEffectGenerator* otherSurfaceEffect = dynamic_cast(other); + if (otherSurfaceEffect) + { + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +EffectGenerator* TextEffectGenerator::copy() const +{ + TextEffectGenerator* effGen = new TextEffectGenerator; + + return effGen; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void TextEffectGenerator::updateForShaderBasedRendering(cvf::Effect* effect) const +{ + // See OpenGLResourceManager::getLinkedTextShaderProgram for code to be used here + // Detected some issues on RHEL 6 related to text, so use an empty effect for now + // Will fall back to fixed function rendering +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void TextEffectGenerator::updateForFixedFunctionRendering(cvf::Effect* effect) const +{ + +} + } // End namespace caf diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h index 9483f255a2..3854e0c254 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h @@ -253,4 +253,23 @@ class MeshEffectGenerator : public EffectGenerator }; +//================================================================================================== +// +// MeshEffectGenerator +// +//================================================================================================== +class TextEffectGenerator : public EffectGenerator +{ +public: + TextEffectGenerator(); + +protected: + virtual bool isEqual(const EffectGenerator* other) const; + virtual EffectGenerator* copy() const; + + virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; + virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; +}; + + } From 3c1b549064bef076d3272432794c21bb562bc1d4 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 16:58:37 +0100 Subject: [PATCH 060/290] (#266) Fixed issue for labels disappearing for white background DrawableText::labelAnchorVisible hides all labels if the background is set to white --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 7ddd02bc63..04a43613f0 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -542,6 +542,7 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection cvf::ref geo = new cvf::DrawableText; geo->setFont(new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD)); geo->setTextColor(m_gridLegendColor); + geo->setCheckPosVisible(false); geo->setDrawBackground(false); geo->setDrawBorder(false); From cf38d1e6fe319e2f2778b3a1752b09ef471998d6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 17:00:12 +0100 Subject: [PATCH 061/290] (#266) Use application font for performance --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 04a43613f0..46ab78ed9b 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -20,6 +20,8 @@ #include "RivGridBoxGenerator.h" +#include "RiaApplication.h" + #include "RivPatchGenerator.h" #include "cafEffectGenerator.h" @@ -540,7 +542,10 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection // Text labels cvf::ref geo = new cvf::DrawableText; - geo->setFont(new cvf::FixedAtlasFont(cvf::FixedAtlasFont::STANDARD)); + + cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + + geo->setFont(standardFont); geo->setTextColor(m_gridLegendColor); geo->setCheckPosVisible(false); geo->setDrawBackground(false); From ecba44d7c8c1d11af0a06d8f3c863d6f6c19482b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 17 Nov 2015 17:04:49 +0100 Subject: [PATCH 062/290] Use correct type in loop --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 46ab78ed9b..f5a4c28c01 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -345,7 +345,7 @@ void RivGridBoxGenerator::createGridBoxLegendParts() createLegend((EdgeType)edge, &parts); - for (int i = 0; i < parts.size(); i++) + for (size_t i = 0; i < parts.size(); i++) { m_gridBoxLegendParts.push_back(parts.at(i)); } From 4b9312ff74825cc2734fdf65dd9705b4f8ef3d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 16 Nov 2015 10:50:54 +0100 Subject: [PATCH 063/290] Adjusted comment --- ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp index 17db4bee2c..59d2322949 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp @@ -507,7 +507,7 @@ inline double triArea3D(const cvf::Vec3d& v0, //-------------------------------------------------------------------------------------------------- /// Barycentric coordinates of a Quad -/// See http://geometry.caltech.edu/pubs/MHBD02.pdf for details +/// See http://geometry.caltech.edu/pubs/MHBD02.pdf for details Eqn. 6. /// W_i = a_i / Sum(a_0 ... a_3) /// a_i = Area(v_(i-1), v_i, v_(i+1))*Area(p, v_(i-2), v_(i-1))*Area(p, v_(i+1), v_(i+2)) From cfefddac09a56d1b6afb714de6375902b4a40fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 16 Nov 2015 10:52:38 +0100 Subject: [PATCH 064/290] (#166) WIP: Preliminary geometry functions starting to get in place --- .../RivCrossSectionGeometryGenerator.cpp | 830 ++++++++++++++++++ .../RivCrossSectionGeometryGenerator.h | 62 ++ 2 files changed, 892 insertions(+) create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp new file mode 100644 index 0000000000..15fee1583b --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -0,0 +1,830 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivCrossSectionGeometryGenerator.h" +#include "cvfBoundingBox.h" +#include "RigMainGrid.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionGeometryGenerator::~RivCrossSectionGeometryGenerator() +{ + +} + + +//-------------------------------------------------------------------------------------------------- +/// Find intersection between a line segment and a plane +/// +/// \param a Start of line segment +/// \param b End of line segment +/// \param intersection Returns intersection point along the infinite line defined by a-b +/// \param normalizedDistFromA Returns the normalized (0..1) position from a to b of the intersection point. +/// Will return values along the complete line, and HUGE_VAL if plane and line are parallel. +/// +/// \return True if line segment intersects the plane +//-------------------------------------------------------------------------------------------------- +bool planeLineIntersect(const cvf::Plane& plane, const cvf::Vec3d& a, const cvf::Vec3d& b, cvf::Vec3d* intersection, double* normalizedDistFromA) +{ + // From Real-Time Collision Detection by Christer Eriscon, published by Morgen Kaufmann Publishers, (c) 2005 Elsevier Inc + + cvf::Vec3d ab = b - a; + cvf::Vec3d normal = plane.normal(); + + double normDotAB = normal * ab; + if (normDotAB == 0) + { + (*normalizedDistFromA) = HUGE_VAL; + return false; + } + + double interpolationParameter = (-plane.D() - (normal * a)) / normDotAB; + + (*intersection) = a + interpolationParameter * ab; + (*normalizedDistFromA) = interpolationParameter; + + return (interpolationParameter >= 0.0 && interpolationParameter <= 1.0); +} + + +struct ClipVx +{ + cvf::Vec3d vx; + double normDistFromEdgeVx1; + int clippedEdgeVx1Id; + int clippedEdgeVx2Id; +}; + +//-------------------------------------------------------------------------------------------------- +/// Returns whether the triangle was hit by the plane +/// isMostVxesOnPositiveSide returns true if all or two of the vxes is on the positive side of the plane +/// newVx1/2.vx1ClippedEdge returns the index of the single vx that is alone on one side +/// Going newVx1 to newVx2 will make the top triangle same winding as the original triangle, +/// and thus the quad opposite winding + +// Except for the trivial cases where all vertices are in front +// or behind plane, these are the permutations +// +// Single vertex on positive side of plane +// => return a triangle +// +// +\ /\c /\c /+ /\c . +// \ / \ / \ / + / \ + . +// \ \ / \/ ---/----\--- . +// / \ \ / /\ / \ . +// a/___\____\b a/_____/__\b a/________\b . +// +\ /+ +// +// Two vertices vertex on positive side of plane +// => return a quad +// +// \+ /\c /\c +/ /\c . +// \ / \ / \ / / \ . +// \ \ / \/ ___/____\___ . +// / \ \ / /\ + / \ + . +// a/___\____\b a/_____/__\b a/________\b . +// \+ +/ +//-------------------------------------------------------------------------------------------------- + +bool planeTriangleIntersection(const cvf::Plane& plane, + const cvf::Vec3d& p1, int p1Id, + const cvf::Vec3d& p2, int p2Id, + const cvf::Vec3d& p3, int p3Id, + ClipVx* newVx1, ClipVx* newVx2, + bool * isMostVxesOnPositiveSide) +{ + int onPosSide[3]; + onPosSide[0] = plane.distanceSquared(p1) >= 0 ; + onPosSide[1] = plane.distanceSquared(p2) >= 0 ; + onPosSide[2] = plane.distanceSquared(p3) >= 0 ; + + const int numPositiveVertices = onPosSide[0] + onPosSide[1] + onPosSide[2]; + + // The entire triangle is on the negative side + // Clip everything + if (numPositiveVertices == 0) + { + (*isMostVxesOnPositiveSide) = false; + return false; + } + + // All triangle vertices are on the positive side + if (numPositiveVertices == 3) + { + (*isMostVxesOnPositiveSide) = true; + return false; + } + + (*isMostVxesOnPositiveSide) = (numPositiveVertices == 2); + + int topVx = 0; + if (numPositiveVertices == 1) + { + if (onPosSide[0]) topVx = 1; + if (onPosSide[1]) topVx = 2; + if (onPosSide[2]) topVx = 3; + } + else if (numPositiveVertices == 2) + { + if (!onPosSide[0]) topVx = 1; + if (!onPosSide[1]) topVx = 2; + if (!onPosSide[2]) topVx = 3; + } + else + { + CVF_ASSERT(false); + } + + cvf::Vec3d intersection; + double normDistFromP1 = 0; + if (topVx = 1) + { + planeLineIntersect(plane, p1, p2, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p1Id; + (*newVx1).clippedEdgeVx1Id = p2Id; + planeLineIntersect(plane, p1, p3, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p1Id; + (*newVx1).clippedEdgeVx1Id = p3Id; + } + else if (topVx = 2) + { + planeLineIntersect(plane, p2, p3, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p2Id; + (*newVx1).clippedEdgeVx1Id = p3Id; + planeLineIntersect(plane, p2, p1, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p2Id; + (*newVx1).clippedEdgeVx1Id = p1Id; + } + else if (topVx = 3) + { + planeLineIntersect(plane, p3, p1, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p3Id; + (*newVx1).clippedEdgeVx1Id = p1Id; + planeLineIntersect(plane, p3, p2, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx1).clippedEdgeVx1Id = p3Id; + (*newVx1).clippedEdgeVx1Id = p2Id; + } + else + { + CVF_ASSERT(false); + } + + return true; +} + +#if 0 +bool planeTriangleIntersection(const cvf::Plane& plane, + const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, + ClipVx* newVx1, ClipVx* newVx2) +{ +} +#endif + + + +#if 0 +static void planeHexCellIntersectionOnTriangles(const cvf::Plane& plane, + const cvf::Vec3d hexCorners[8], + const int hexCornersIds[8], + std::vector* polygon) +{ + CVF_ASSERT(polygon != NULL); + + int intersectionCount = 0; + + std::vector > polygonEdges; + for (int face = 0; face < 6 ; ++face) + { + cvf::ubyte faceVertexIndices[4]; + cvf::StructGridInterface::cellFaceVertexIndices(static_cast(face), faceVertexIndices); + + ClipVx newVx1; + ClipVx newVx2; + + bool isClipped = planeTriangleIntersection(plane, + hexCorners[faceVertexIndices[0]], hexCornersIds[faceVertexIndices[0]], + hexCorners[faceVertexIndices[1]], hexCornersIds[faceVertexIndices[1]], + hexCorners[faceVertexIndices[2]], hexCornersIds[faceVertexIndices[2]], + &newVx1, &newVx2); + if (isClipped) + { + polygonEdges.push_back(std::make_pair(newVx1, newVx2)); + } + + isClipped = planeTriangleIntersection(plane, + hexCorners[faceVertexIndices[0]], hexCornersIds[faceVertexIndices[0]], + hexCorners[faceVertexIndices[2]], hexCornersIds[faceVertexIndices[2]], + hexCorners[faceVertexIndices[3]], hexCornersIds[faceVertexIndices[3]], + &newVx1, &newVx2); + if (isClipped) + { + polygonEdges.push_back(std::make_pair(newVx1, newVx2)); + } + + } + + if (polygonEdges.size >= 3) + { + // Sort polygon edges in polygon order. + // Do this by finding polygon vxes cutting the same edge. + // And grow from the first edge + (*polygon).push_back(polygonEdges[0].first); + (*polygon).push_back(polygonEdges[0].second); + //for () + } +} +#endif + +//-------------------------------------------------------------------------------------------------- +/// Will return the intersection point. If the plane is outside the line, it returns the closest line endpoint +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d planeLineIntersectionForMC(const cvf::Plane& plane, const cvf::Vec3d& p1, const cvf::Vec3d& p2, double* normalizedDistFromP1) +{ + // From http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/ + // + // P1 (x1,y1,z1) and P2 (x2,y2,z2) + // + // P = P1 + u (P2 - P1) + // + // A*x1 + B*y1 + C*z1 + D + // u = --------------------------------- + // A*(x1-x2) + B*(y1-y2) + C*(z1-z2) + + CVF_TIGHT_ASSERT(normalizedDistFromP1); + + const cvf::Vec3d v = p2 - p1; + + (*normalizedDistFromP1) = 0.0; + + double denominator = -(plane.A()*v.x() + plane.B()*v.y() + plane.C()*v.z()); + if (denominator != 0) + { + double u = (plane.A()*p1.x() + plane.B()*p1.y() + plane.C()*p1.z() + plane.D())/denominator; + (*normalizedDistFromP1) = u; + if (u > 0.0 && u < 1.0) + { + return (p1 + u*v); + } + else + { + if (u >= 1.0) + { + return p2; + } + else + { + return p1; + } + } + } + else + { + return p1; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int planeHexIntersectionMC(const cvf::Plane& plane, + const cvf::Vec3d cell[8], + const int hexCornersIds[8], + std::vector* triangles) +{ + +// Based on description and implementation from Paul Bourke: +// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/ + + static const uint cubeIdxToCutEdgeBitfield[256] = + { + 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, + 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, + 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c, + 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac, + 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, + 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, + 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c, + 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc, + 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, + 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, + 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, + 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, + 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, + 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, + 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, + 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, + 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 + }; + + static const int cubeIdxToTriangleIndices[256][16] = + { + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, + { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, + { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, + { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, + { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, + { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, + { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, + { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, + { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, + { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, + { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, + { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, + { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, + { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, + { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, + { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, + { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, + { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, + { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, + { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, + { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, + { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, + { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, + { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, + { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, + { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, + { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, + { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, + { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, + { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, + { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, + { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, + { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, + { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, + { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, + { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, + { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, + { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, + { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, + { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, + { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, + { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, + { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, + { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, + { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, + { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, + { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, + { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, + { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, + { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, + { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, + { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, + { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, + { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, + { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, + { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, + { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, + { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, + { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, + { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, + { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, + { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, + { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, + { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, + { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, + { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, + { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, + { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, + { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, + { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, + { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, + { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, + { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, + { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, + { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, + { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, + { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, + { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, + { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, + { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, + { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, + { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, + { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, + { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, + { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, + { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, + { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, + { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, + { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, + { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, + { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, + { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, + { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, + { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, + { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, + { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, + { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, + { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, + { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, + { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, + { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, + { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, + { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, + { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, + { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, + { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, + { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, + { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, + { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, + { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, + { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } + }; + + static const int edgeTable[12][2] = + { + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + {4, 5}, + {5, 6}, + {6, 7}, + {7, 4}, + {0, 4}, + {1, 5}, + {2, 6}, + {3, 7} + }; + + int cubeIndex = 0; + if (plane.distanceSquared(cell[0]) < 0) cubeIndex |= 1; + if (plane.distanceSquared(cell[1]) < 0) cubeIndex |= 2; + if (plane.distanceSquared(cell[2]) < 0) cubeIndex |= 4; + if (plane.distanceSquared(cell[3]) < 0) cubeIndex |= 8; + if (plane.distanceSquared(cell[4]) < 0) cubeIndex |= 16; + if (plane.distanceSquared(cell[5]) < 0) cubeIndex |= 32; + if (plane.distanceSquared(cell[6]) < 0) cubeIndex |= 64; + if (plane.distanceSquared(cell[7]) < 0) cubeIndex |= 128; + + if (cubeIdxToCutEdgeBitfield[cubeIndex] == 0) + { + return 0; + } + + cvf::Vec3d edgeIntersections[12]; + double normDistAlongEdge[12]; + + + // Compute vertex coordinates on the edges where we have intersections + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 1) edgeIntersections[0] = planeLineIntersectionForMC(plane, cell[0], cell[1], &normDistAlongEdge[0] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 2) edgeIntersections[1] = planeLineIntersectionForMC(plane, cell[1], cell[2], &normDistAlongEdge[1] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 4) edgeIntersections[2] = planeLineIntersectionForMC(plane, cell[2], cell[3], &normDistAlongEdge[2] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 8) edgeIntersections[3] = planeLineIntersectionForMC(plane, cell[3], cell[0], &normDistAlongEdge[3] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 16) edgeIntersections[4] = planeLineIntersectionForMC(plane, cell[4], cell[5], &normDistAlongEdge[4] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 32) edgeIntersections[5] = planeLineIntersectionForMC(plane, cell[5], cell[6], &normDistAlongEdge[5] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 64) edgeIntersections[6] = planeLineIntersectionForMC(plane, cell[6], cell[7], &normDistAlongEdge[6] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 128) edgeIntersections[7] = planeLineIntersectionForMC(plane, cell[7], cell[4], &normDistAlongEdge[7] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 256) edgeIntersections[8] = planeLineIntersectionForMC(plane, cell[0], cell[4], &normDistAlongEdge[8] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 512) edgeIntersections[9] = planeLineIntersectionForMC(plane, cell[1], cell[5], &normDistAlongEdge[9] ); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 1024) edgeIntersections[10] = planeLineIntersectionForMC(plane, cell[2], cell[6], &normDistAlongEdge[10]); + if (cubeIdxToCutEdgeBitfield[cubeIndex] & 2048) edgeIntersections[11] = planeLineIntersectionForMC(plane, cell[3], cell[7], &normDistAlongEdge[11]); + + + // Create the triangles + + const int* triConnects = cubeIdxToTriangleIndices[cubeIndex]; + uint n = 0; + int edgeIdx = triConnects[n]; + while (edgeIdx != -1) + { + ClipVx cvx; + cvx.vx = edgeIntersections[edgeIdx]; + cvx.normDistFromEdgeVx1 = normDistAlongEdge[edgeIdx]; + cvx.clippedEdgeVx1Id = hexCornersIds[edgeTable[edgeIdx][0]]; + cvx.clippedEdgeVx2Id = hexCornersIds[edgeTable[edgeIdx][1]]; + + (*triangles).push_back(cvx); + ++n; + edgeIdx = triConnects[n]; + } + + uint numTriangles = n/3; + + return numTriangles; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector &polyline, + const cvf::Vec3d& extrusionDirection, + const RigMainGrid* grid) +{ + cvf::BoundingBox gridBBox = grid->boundingBox(); + cvf::Vec3d extDir = extrusionDirection.getNormalized(); + + size_t lineCount = polyline.size(); + for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) + { + cvf::Vec3d p1 = polyline[lIdx]; + cvf::Vec3d p2 = polyline[lIdx+1]; + + cvf::BoundingBox sectionBBox; + sectionBBox.add(p1); + sectionBBox.add(p1); + double maxSectionHeight = gridBBox.radius(); + sectionBBox.add(p1 + extDir*maxSectionHeight); + sectionBBox.add(p1 - extDir*maxSectionHeight); + sectionBBox.add(p2 + extDir*maxSectionHeight); + sectionBBox.add(p2 - extDir*maxSectionHeight); + + std::vector columnCellCandidates; + grid->findIntersectingCells(sectionBBox, &columnCellCandidates); + + cvf::Plane plane; + plane.setFromPoints(p1, p2, p2 + extDir*maxSectionHeight); + + cvf::Plane p1Plane; + p1Plane.setFromPoints(p1, p1 + extDir*maxSectionHeight, p1 + plane.normal()); + cvf::Plane p2Plane; + p2Plane.setFromPoints(p2, p2 + extDir*maxSectionHeight, p2 + plane.normal() ); + + + std::vector triangleVxes; + triangleVxes.reserve(5*3); + + for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) + { + triangleVxes.clear(); + size_t globalCellIdx = columnCellCandidates[cccIdx]; + + cvf::Vec3d cellCorners[8]; + grid->cellCornerVertices(globalCellIdx, cellCorners); + + const caf::SizeTArray8& cornerIndices = grid->cells()[globalCellIdx].cornerIndices(); + int hexCornersIds[8]; + hexCornersIds[0] = static_cast(cornerIndices[0]); + hexCornersIds[1] = static_cast(cornerIndices[1]); + hexCornersIds[2] = static_cast(cornerIndices[2]); + hexCornersIds[3] = static_cast(cornerIndices[3]); + hexCornersIds[4] = static_cast(cornerIndices[4]); + hexCornersIds[5] = static_cast(cornerIndices[5]); + hexCornersIds[6] = static_cast(cornerIndices[6]); + hexCornersIds[7] = static_cast(cornerIndices[7]); + + uint triangleCount = planeHexIntersectionMC(plane, + cellCorners, + hexCornersIds, + &triangleVxes); + + if (triangleCount) + { + #if 1 + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + { + // Accumulate to geometry + int triVxIdx = tIdx*3; + m_triangleVxes.push_back(triangleVxes[triVxIdx+0].vx); + m_triangleVxes.push_back(triangleVxes[triVxIdx+1].vx); + m_triangleVxes.push_back(triangleVxes[triVxIdx+2].vx); + + m_triangleToCellIdxMap.push_back(globalCellIdx); + } + #else + + // Clip triangles with plane 1 + std::vector clippedTriangleVxes; + for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) + { + ClipVx newVx1; + ClipVx newVx2; + bool isMostVxesOnPositiveSide = false; + int triVxIdx = tIdx*3; + bool isIntersecting = planeTriangleIntersection(p1Plane, + triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, + triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, + triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, + &newVx1, &newVx2, &isMostVxesOnPositiveSide); + + if (!isIntersecting && !isMostVxesOnPositiveSide) + { + // Discard triangle + } + else if (!isIntersecting && isMostVxesOnPositiveSide) + { + // Keep the triangle + clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 0]); + clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 1]); + clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 2]); + } + else if (isIntersecting && isMostVxesOnPositiveSide) + { + // Split the resulting quad and add the two triangles + clippedTriangleVxes.push_back(newVx2); + clippedTriangleVxes.push_back(newVx1); + clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx2Id]); + + clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(triangleVxes[newVx2.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(newVx2); + + } + else if (isIntersecting && !isMostVxesOnPositiveSide) + { + // Add the top triangle + clippedTriangleVxes.push_back(newVx1); + clippedTriangleVxes.push_back(newVx2); + clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx1Id]); + + } + } + + // Clip triangles with plane 2 + for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) + { + + + } + + for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) + { + + // Accumulate to geometry + + } + #endif + } + } + + } +} diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h new file mode 100644 index 0000000000..9261f5bf95 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cvfObject.h" +#include "cvfVector3.h" +#include "cvfArray.h" + +#include + +class RigMainGrid; + + +namespace cvf +{ + class ScalarMapper; + class DrawableGeo; +} + + +class RivCrossSectionGeometryGenerator : public cvf::Object +{ +public: + RivCrossSectionGeometryGenerator(const std::vector &polyline, + const cvf::Vec3d& extrusionDirection, + const RigMainGrid* grid ); + + ~RivCrossSectionGeometryGenerator(); + + void textureCoordinates(cvf::Vec2fArray* textureCoords, + const cvf::ScalarMapper* mapper, size_t scalarResultIndex) const; + + // Mapping between cells and geometry + cvf::ref > triangleToCellIndex() const; + + // Generated geometry + cvf::ref generateSurface(); + cvf::ref createMeshDrawable(); +private: + void calculateArrays(); + + std::vector m_triangleVxes; + std::vector m_triangleToCellIdxMap; + +}; + From 7845d9bd3ca864a4bef2617c7bdc0cc3910c5554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 16 Nov 2015 12:12:42 +0100 Subject: [PATCH 065/290] (#166) WIP: Preliminary cross section geometry builder ready for testing --- .../RivCrossSectionGeometryGenerator.cpp | 127 ++++++++++++++---- .../RivCrossSectionGeometryGenerator.h | 24 ++-- 2 files changed, 117 insertions(+), 34 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 15fee1583b..682e15695b 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -20,8 +20,24 @@ #include "RivCrossSectionGeometryGenerator.h" #include "cvfBoundingBox.h" #include "RigMainGrid.h" +#include "cvfDrawableGeo.h" +#include "RigResultAccessor.h" +#include "cvfScalarMapper.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector &polyline, + const cvf::Vec3d& extrusionDirection, + const RigMainGrid* grid) + : m_polyLine(polyline), + m_extrusionDirection(extrusionDirection), + m_mainGrid(grid) +{ + m_triangleVxes = new cvf::Vec3fArray; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -683,41 +699,41 @@ int planeHexIntersectionMC(const cvf::Plane& plane, } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector &polyline, - const cvf::Vec3d& extrusionDirection, - const RigMainGrid* grid) +void RivCrossSectionGeometryGenerator::calculateArrays() { - cvf::BoundingBox gridBBox = grid->boundingBox(); - cvf::Vec3d extDir = extrusionDirection.getNormalized(); + if (m_triangleVxes->size()) return; + + std::vector triangleVertices; + + + cvf::BoundingBox gridBBox = m_mainGrid->boundingBox(); + m_extrusionDirection.normalize(); - size_t lineCount = polyline.size(); + size_t lineCount = m_polyLine.size(); for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) { - cvf::Vec3d p1 = polyline[lIdx]; - cvf::Vec3d p2 = polyline[lIdx+1]; + cvf::Vec3d p1 = m_polyLine[lIdx]; + cvf::Vec3d p2 = m_polyLine[lIdx+1]; cvf::BoundingBox sectionBBox; sectionBBox.add(p1); sectionBBox.add(p1); double maxSectionHeight = gridBBox.radius(); - sectionBBox.add(p1 + extDir*maxSectionHeight); - sectionBBox.add(p1 - extDir*maxSectionHeight); - sectionBBox.add(p2 + extDir*maxSectionHeight); - sectionBBox.add(p2 - extDir*maxSectionHeight); + sectionBBox.add(p1 + m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p1 - m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p2 + m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p2 - m_extrusionDirection*maxSectionHeight); std::vector columnCellCandidates; - grid->findIntersectingCells(sectionBBox, &columnCellCandidates); + m_mainGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); cvf::Plane plane; - plane.setFromPoints(p1, p2, p2 + extDir*maxSectionHeight); + plane.setFromPoints(p1, p2, p2 + m_extrusionDirection*maxSectionHeight); cvf::Plane p1Plane; - p1Plane.setFromPoints(p1, p1 + extDir*maxSectionHeight, p1 + plane.normal()); + p1Plane.setFromPoints(p1, p1 + m_extrusionDirection*maxSectionHeight, p1 + plane.normal()); cvf::Plane p2Plane; - p2Plane.setFromPoints(p2, p2 + extDir*maxSectionHeight, p2 + plane.normal() ); + p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 + plane.normal() ); std::vector triangleVxes; @@ -729,9 +745,9 @@ RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::ve size_t globalCellIdx = columnCellCandidates[cccIdx]; cvf::Vec3d cellCorners[8]; - grid->cellCornerVertices(globalCellIdx, cellCorners); + m_mainGrid->cellCornerVertices(globalCellIdx, cellCorners); - const caf::SizeTArray8& cornerIndices = grid->cells()[globalCellIdx].cornerIndices(); + const caf::SizeTArray8& cornerIndices = m_mainGrid->cells()[globalCellIdx].cornerIndices(); int hexCornersIds[8]; hexCornersIds[0] = static_cast(cornerIndices[0]); hexCornersIds[1] = static_cast(cornerIndices[1]); @@ -742,7 +758,7 @@ RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::ve hexCornersIds[6] = static_cast(cornerIndices[6]); hexCornersIds[7] = static_cast(cornerIndices[7]); - uint triangleCount = planeHexIntersectionMC(plane, + int triangleCount = planeHexIntersectionMC(plane, cellCorners, hexCornersIds, &triangleVxes); @@ -754,9 +770,9 @@ RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::ve { // Accumulate to geometry int triVxIdx = tIdx*3; - m_triangleVxes.push_back(triangleVxes[triVxIdx+0].vx); - m_triangleVxes.push_back(triangleVxes[triVxIdx+1].vx); - m_triangleVxes.push_back(triangleVxes[triVxIdx+2].vx); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx)); m_triangleToCellIdxMap.push_back(globalCellIdx); } @@ -827,4 +843,65 @@ RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::ve } } + + m_triangleVxes->assign(triangleVertices); +} + + +//-------------------------------------------------------------------------------------------------- +/// Generate surface drawable geo from the specified region +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivCrossSectionGeometryGenerator::generateSurface() +{ + calculateArrays(); + + CVF_ASSERT(m_triangleVxes.notNull()); + + if (m_triangleVxes->size() == 0) return NULL; + + cvf::ref geo = new cvf::DrawableGeo; + geo->setFromTriangleVertexArray(m_triangleVxes.p()); + + return geo; +} + + + +//-------------------------------------------------------------------------------------------------- +/// Calculates the texture coordinates in a "nearly" one dimentional texture. +/// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5 +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, + const RigResultAccessor* resultAccessor, + const cvf::ScalarMapper* mapper) const +{ + if (!resultAccessor) return; + + size_t numVertices = m_triangleVxes->size(); + + textureCoords->resize(numVertices); + cvf::Vec2f* rawPtr = textureCoords->ptr(); + + double cellScalarValue; + cvf::Vec2f texCoord; + + int triangleCount = static_cast(m_triangleToCellIdxMap.size()); + +#pragma omp parallel for private(texCoord, cellScalarValue) + for (int tIdx = 0; tIdx < triangleCount; tIdx++) + { + cellScalarValue = resultAccessor->cellScalarGlobIdx(m_triangleToCellIdxMap[tIdx]); + texCoord = mapper->mapToTextureCoord(cellScalarValue); + if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's + { + texCoord[1] = 1.0f; + } + + size_t j; + for (j = 0; j < 3; j++) + { + rawPtr[tIdx*3 + j] = texCoord; + } + } } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 9261f5bf95..fa9ccff894 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -25,7 +25,7 @@ #include class RigMainGrid; - +class RigResultAccessor; namespace cvf { @@ -43,20 +43,26 @@ class RivCrossSectionGeometryGenerator : public cvf::Object ~RivCrossSectionGeometryGenerator(); - void textureCoordinates(cvf::Vec2fArray* textureCoords, - const cvf::ScalarMapper* mapper, size_t scalarResultIndex) const; + + void textureCoordinates(cvf::Vec2fArray* textureCoords, + const RigResultAccessor* resultAccessor, + const cvf::ScalarMapper* mapper) const; // Mapping between cells and geometry - cvf::ref > triangleToCellIndex() const; + const std::vector& triangleToCellIndex() const; // Generated geometry - cvf::ref generateSurface(); - cvf::ref createMeshDrawable(); + cvf::ref generateSurface(); + //cvf::ref createMeshDrawable(); + private: - void calculateArrays(); + void calculateArrays(); - std::vector m_triangleVxes; - std::vector m_triangleToCellIdxMap; + cvf::ref m_triangleVxes; + std::vector m_triangleToCellIdxMap; + cvf::cref m_mainGrid; + std::vector m_polyLine; + cvf::Vec3d m_extrusionDirection; }; From 57f7c1229a07b738ec9f3cdc8b35a38555d99ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 17 Nov 2015 09:23:33 +0100 Subject: [PATCH 066/290] (#166) WIP: First visible section with hacks --- .../ModelVisualization/CMakeLists_files.cmake | 4 + .../RivCrossSectionGeometryGenerator.cpp | 21 +- .../RivCrossSectionGeometryGenerator.h | 2 +- .../RivCrossSectionPartMgr.cpp | 252 ++++++++++++++++++ .../RivCrossSectionPartMgr.h | 73 +++++ .../ProjectDataModel/RimEclipseView.cpp | 10 + .../ProjectDataModel/RimEclipseView.h | 2 + 7 files changed, 358 insertions(+), 6 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index 7c86908d4f..13163351b8 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -9,6 +9,8 @@ ${CEE_CURRENT_LIST_DIR}RivCellEdgeEffectGenerator.h ${CEE_CURRENT_LIST_DIR}RivColorTableArray.h ${CEE_CURRENT_LIST_DIR}RivFaultPartMgr.h ${CEE_CURRENT_LIST_DIR}RivFaultGeometryGenerator.h +${CEE_CURRENT_LIST_DIR}RivCrossSectionGeometryGenerator.h +${CEE_CURRENT_LIST_DIR}RivCrossSectionPartMgr.h ${CEE_CURRENT_LIST_DIR}RivNNCGeometryGenerator.h ${CEE_CURRENT_LIST_DIR}RivGridPartMgr.h ${CEE_CURRENT_LIST_DIR}RivTernarySaturationOverlayItem.h @@ -40,6 +42,8 @@ ${CEE_CURRENT_LIST_DIR}RivCellEdgeEffectGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivColorTableArray.cpp ${CEE_CURRENT_LIST_DIR}RivFaultPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivNNCGeometryGenerator.cpp +${CEE_CURRENT_LIST_DIR}RivCrossSectionGeometryGenerator.cpp +${CEE_CURRENT_LIST_DIR}RivCrossSectionPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivFaultGeometryGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivGridPartMgr.cpp ${CEE_CURRENT_LIST_DIR}RivTernarySaturationOverlayItem.cpp diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 682e15695b..937b18b79f 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -704,7 +704,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (m_triangleVxes->size()) return; std::vector triangleVertices; - + cvf::Vec3d displayOffset = m_mainGrid->displayModelOffset(); cvf::BoundingBox gridBBox = m_mainGrid->boundingBox(); m_extrusionDirection.normalize(); @@ -741,9 +741,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) { - triangleVxes.clear(); size_t globalCellIdx = columnCellCandidates[cccIdx]; + if (m_mainGrid->cells()[globalCellIdx].isInvalid()) continue; + + triangleVxes.clear(); cvf::Vec3d cellCorners[8]; m_mainGrid->cellCornerVertices(globalCellIdx, cellCorners); @@ -770,9 +772,9 @@ void RivCrossSectionGeometryGenerator::calculateArrays() { // Accumulate to geometry int triVxIdx = tIdx*3; - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx - displayOffset)); m_triangleToCellIdxMap.push_back(globalCellIdx); } @@ -867,6 +869,15 @@ cvf::ref RivCrossSectionGeometryGenerator::generateSurface() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivCrossSectionGeometryGenerator::createMeshDrawable() +{ + cvf::ref geo = new cvf::DrawableGeo; + return geo; +} + //-------------------------------------------------------------------------------------------------- /// Calculates the texture coordinates in a "nearly" one dimentional texture. diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index fa9ccff894..1ecaee1907 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -53,7 +53,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object // Generated geometry cvf::ref generateSurface(); - //cvf::ref createMeshDrawable(); + cvf::ref createMeshDrawable(); private: void calculateArrays(); diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp new file mode 100644 index 0000000000..37dfdd7f2e --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -0,0 +1,252 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivCrossSectionPartMgr.h" + +//#include "RiaApplication.h" +//#include "RiaPreferences.h" + +#include "RigCaseCellResultsData.h" +#include "RigCaseData.h" +#include "RigResultAccessor.h" +#include "RigResultAccessorFactory.h" + +#include "RimEclipseCase.h" +#include "RimEclipseView.h" +#include "RimEclipseCellColors.h" +#include "RimTernaryLegendConfig.h" + +//#include "RimCrossSectionCollection.h" + +#include "RivResultToTextureMapper.h" +#include "RivScalarMapperUtils.h" +#include "RivTernaryScalarMapper.h" + +#include "cvfDrawableGeo.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfPrimitiveSetDirect.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionPartMgr::RivCrossSectionPartMgr( const RigMainGrid* grid, + const RimCrossSectionCollection* rimCrossSectionCollection, + const RimCrossSection* rimCrossSection) + : m_grid(grid), + m_rimCrossSectionCollection(rimCrossSectionCollection), + m_rimCrossSection(rimCrossSection), + m_defaultColor(cvf::Color3::WHITE) +{ + std::vector polyLine; + polyLine.push_back(grid->boundingBox().max()); + polyLine.push_back(grid->boundingBox().min()); + + m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine, cvf::Vec3d(0,0,1.0), grid ); + + m_nativeCrossSectionFacesTextureCoords = new cvf::Vec2fArray; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::applySingleColorEffect() +{ + m_defaultColor = cvf::Color3f::OLIVE;//m_rimCrossSection->CrossSectionColor(); + this->updatePartEffect(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +{ + CVF_ASSERT(cellResultColors); + + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); + RimEclipseView* eclipseView = cellResultColors->reservoirView(); + RigCaseData* eclipseCase = eclipseView->eclipseCase()->reservoirData(); + + // CrossSections + if (m_nativeCrossSectionFaces.notNull()) + { + if (cellResultColors->isTernarySaturationSelected()) + { + //RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), + // timeStepIndex, + // m_grid->gridIndex(), + // m_nativeCrossSectionGenerator->quadToCellFaceMapper()); + // + //texturer.createTextureCoords(m_nativeCrossSectionFacesTextureCoords.p()); + + CVF_ASSERT(false); // Todo + + const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); + RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_nativeCrossSectionFaces.p(), + m_nativeCrossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + eclipseView->isLightingDisabled()); + } + else + { + const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); + + cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), + 0, + RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), + timeStepIndex, + cellResultColors->resultVariable()); + + m_nativeCrossSectionGenerator->textureCoordinates(m_nativeCrossSectionFacesTextureCoords.p(), resultAccessor.p() ,mapper); + + + RivScalarMapperUtils::applyTextureResultsToPart(m_nativeCrossSectionFaces.p(), + m_nativeCrossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + eclipseView->isLightingDisabled()); + } + } + +} + +const int priCrossSectionGeo = 1; +const int priNncGeo = 2; +const int priMesh = 3; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::generatePartGeometry() +{ + + bool useBufferObjects = true; + // Surface geometry + { + cvf::ref geo = m_nativeCrossSectionGenerator->generateSurface(); + if (geo.notNull()) + { + geo->computeNormals(); + + if (useBufferObjects) + { + geo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); + } + + cvf::ref part = new cvf::Part; + part->setName("Cross Section "); + part->setDrawable(geo.p()); + + // Set mapping from triangle face index to cell index + //cvf::ref si = new RivSourceInfo(m_grid->gridIndex()); + //si->m_cellFaceFromTriangleMapper = m_nativeCrossSectionGenerator->triangleToCellFaceMapper(); + //part->setSourceInfo(si.p()); + + part->updateBoundingBox(); + part->setEnableMask(surfaceBit); + part->setPriority(priCrossSectionGeo); + + m_nativeCrossSectionFaces = part; + } + } + + // Mesh geometry + { + cvf::ref geoMesh = m_nativeCrossSectionGenerator->createMeshDrawable(); + if (geoMesh.notNull()) + { + if (useBufferObjects) + { + geoMesh->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); + } + + cvf::ref part = new cvf::Part; + part->setName("Cross Section mesh" ); + part->setDrawable(geoMesh.p()); + + part->updateBoundingBox(); + part->setEnableMask(meshSurfaceBit); + part->setPriority(priMesh); + + m_nativeCrossSectionGridLines = part; + } + } + + updatePartEffect(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::updatePartEffect() +{ + // Set deCrossSection effect + caf::SurfaceEffectGenerator geometryEffgen(m_defaultColor, caf::PO_1); + + cvf::ref geometryOnlyEffect = geometryEffgen.generateCachedEffect(); + + if (m_nativeCrossSectionFaces.notNull()) + { + m_nativeCrossSectionFaces->setEffect(geometryOnlyEffect.p()); + } + + // Update mesh colors as well, in case of change + //RiaPreferences* prefs = RiaApplication::instance()->preferences(); + + cvf::ref eff; + caf::MeshEffectGenerator CrossSectionEffGen(cvf::Color3::WHITE);//prefs->defaultCrossSectionGridLineColors()); + eff = CrossSectionEffGen.generateCachedEffect(); + + if (m_nativeCrossSectionGridLines.notNull()) + { + m_nativeCrossSectionGridLines->setEffect(eff.p()); + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model) +{ + if (m_nativeCrossSectionFaces.isNull()) + { + generatePartGeometry(); + } + + if (m_nativeCrossSectionFaces.notNull()) + { + model->addPart(m_nativeCrossSectionFaces.p()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* model) +{ + if (m_nativeCrossSectionGridLines.notNull()) model->addPart(m_nativeCrossSectionGridLines.p()); +} + diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h new file mode 100644 index 0000000000..11cfb3b697 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cvfBase.h" +#include "cvfObject.h" + +//#include "RimCrossSection.h" +#include "RivCrossSectionGeometryGenerator.h" +#include "cvfColor4.h" + +namespace cvf +{ + class ModelBasicList; + class Transform; + class Part; +} + +class RimEclipseCellColors; +class RimCellEdgeColors; +class RimCrossSectionCollection; +class RimCrossSection; + +//================================================================================================== +/// +/// +//================================================================================================== + +class RivCrossSectionPartMgr : public cvf::Object +{ +public: + RivCrossSectionPartMgr(const RigMainGrid* grid, + const RimCrossSectionCollection* rimCrossSectionCollection, + const RimCrossSection* rimCrossSection); + + void applySingleColorEffect(); + void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); + + void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model); + void appendMeshLinePartsToModel(cvf::ModelBasicList* model); + +private: + void updatePartEffect(); + void generatePartGeometry(); + + cvf::cref m_grid; + const RimCrossSection* m_rimCrossSection; + const RimCrossSectionCollection* m_rimCrossSectionCollection; + + cvf::Color3f m_defaultColor; + + cvf::ref m_nativeCrossSectionGenerator; + cvf::ref m_nativeCrossSectionFaces; + cvf::ref m_nativeCrossSectionGridLines; + cvf::ref m_nativeCrossSectionFacesTextureCoords; + +}; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 368752b653..a98f24b1a5 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -70,6 +70,7 @@ #include #include +#include "RivCrossSectionPartMgr.h" @@ -416,6 +417,15 @@ void RimEclipseView::createDisplayModel() } + { + if (m_csPartmgr.isNull()) m_csPartmgr = new RivCrossSectionPartMgr(m_reservoir->reservoirData()->mainGrid(), NULL, NULL); + for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx) + { + m_csPartmgr->appendNativeCrossSectionFacesToModel(frameModels[frameIdx].p()); + frameModels[frameIdx]->part(frameModels[frameIdx]->partCount()-1)->setTransform(m_reservoirGridPartManager->scaleTransform()); + } + } + // Compute triangle count, Debug only /* if (false) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 04db15fb42..e69fea4038 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -55,6 +55,7 @@ class RimEclipseCellColors; class RimEclipseWellCollection; class RiuViewer; class RivReservoirPipesPartMgr; +class RivCrossSectionPartMgr; namespace cvf { @@ -181,6 +182,7 @@ class RimEclipseView : public RimView cvf::ref m_reservoirGridPartManager; cvf::ref m_pipesPartManager; + cvf::ref m_csPartmgr; std::vector m_visibleGridParts; }; From 5840f165ea30a6f4877ed2b0bde1912e10003b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 17 Nov 2015 17:19:25 +0100 Subject: [PATCH 067/290] Added an interface to retreive the simulation well centerline --- .../ModelVisualization/RivReservoirPipesPartMgr.cpp | 13 +++++++++++++ .../ModelVisualization/RivReservoirPipesPartMgr.h | 3 +++ .../ModelVisualization/RivWellPipesPartMgr.cpp | 6 +++--- .../ModelVisualization/RivWellPipesPartMgr.h | 3 +++ 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp index 75b18cb451..a8a3744588 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp @@ -139,3 +139,16 @@ void RivReservoirPipesPartMgr::updatePipeResultColor(size_t frameIndex) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector< std::vector >* RivReservoirPipesPartMgr::centerLineOfWellBranches(int wellIdx) +{ + if (wellIdx < m_wellPipesPartMgrs.size()) + { + return &(m_wellPipesPartMgrs[wellIdx]->centerLineOfWellBranches()); + } + + return NULL; +} + diff --git a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.h b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.h index c41daa123e..8736ed0a75 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.h @@ -21,6 +21,7 @@ #include "RimEclipseWellCollection.h" #include "cvfCollection.h" +#include "cvfVector3.h" namespace cvf { @@ -46,6 +47,8 @@ class RivReservoirPipesPartMgr : public cvf::Object void appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, size_t frameIndex); void updatePipeResultColor(size_t frameIndex); + const std::vector< std::vector >* centerLineOfWellBranches(int wellIdx); + private: caf::PdmPointer m_reservoirView; cvf::ref m_scaleTransform; diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index 4dcb02367f..5372356ff4 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -97,10 +97,10 @@ void RivWellPipesPartMgr::buildWellPipeParts() m_wellBranches.clear(); - std::vector< std::vector > pipeBranchesCLCoords; + m_pipeBranchesCLCoords.clear(); std::vector< std::vector > pipeBranchesCellIds; - calculateWellPipeCenterline(pipeBranchesCLCoords, pipeBranchesCellIds); + calculateWellPipeCenterline(m_pipeBranchesCLCoords, pipeBranchesCellIds); double characteristicCellSize = m_rimReservoirView->eclipseCase()->reservoirData()->mainGrid()->characteristicIJCellSize(); double pipeRadius = m_rimReservoirView->wellCollection()->pipeRadiusScaleFactor() *m_rimWell->pipeRadiusScaleFactor() * characteristicCellSize; @@ -119,7 +119,7 @@ void RivWellPipesPartMgr::buildWellPipeParts() pbd.m_pipeGeomGenerator->setPipeColor( m_rimWell->wellPipeColor()); cvf::ref cvfCoords = new cvf::Vec3dArray; - cvfCoords->assign(pipeBranchesCLCoords[brIdx]); + cvfCoords->assign(m_pipeBranchesCLCoords[brIdx]); // Scale the centerline coordinates using the Z-scale transform of the grid and correct for the display offset. const RigMainGrid* mainGrid = m_rimReservoirView->eclipseCase()->reservoirData()->mainGrid(); diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h index bad5f24be4..383984dd0b 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h @@ -53,6 +53,7 @@ class RivWellPipesPartMgr : public cvf::Object void appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, size_t frameIndex); void updatePipeResultColor(size_t frameIndex); + const std::vector< std::vector >& centerLineOfWellBranches() { return m_pipeBranchesCLCoords;} private: caf::PdmPointer m_rimReservoirView; @@ -89,4 +90,6 @@ class RivWellPipesPartMgr : public cvf::Object cvf::ref m_scalarMapper; cvf::ref m_scalarMapperSurfaceEffect; cvf::ref m_scalarMapperMeshEffect; + + std::vector< std::vector > m_pipeBranchesCLCoords; }; From 40713a3c840d40765d9d748c65e1f089e5459717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 17 Nov 2015 17:21:53 +0100 Subject: [PATCH 068/290] (#166) Added clipping of the clipped cells, with fixes of errors. --- .../RivCrossSectionGeometryGenerator.cpp | 248 ++++++++++++++---- .../RivCrossSectionGeometryGenerator.h | 3 +- .../RivCrossSectionPartMgr.cpp | 24 +- .../RivCrossSectionPartMgr.h | 7 +- 4 files changed, 213 insertions(+), 69 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 937b18b79f..70c9a17b4d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -83,6 +83,7 @@ bool planeLineIntersect(const cvf::Plane& plane, const cvf::Vec3d& a, const cvf: struct ClipVx { + ClipVx() : vx(cvf::Vec3d::ZERO), normDistFromEdgeVx1(HUGE_VAL), clippedEdgeVx1Id(-1), clippedEdgeVx2Id(-1) {} cvf::Vec3d vx; double normDistFromEdgeVx1; int clippedEdgeVx1Id; @@ -169,39 +170,41 @@ bool planeTriangleIntersection(const cvf::Plane& plane, CVF_ASSERT(false); } - cvf::Vec3d intersection; - double normDistFromP1 = 0; - if (topVx = 1) + bool ok1, ok2; + if (topVx == 1) { - planeLineIntersect(plane, p1, p2, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); + ok1 = planeLineIntersect(plane, p1, p2, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); (*newVx1).clippedEdgeVx1Id = p1Id; - (*newVx1).clippedEdgeVx1Id = p2Id; - planeLineIntersect(plane, p1, p3, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); - (*newVx1).clippedEdgeVx1Id = p1Id; - (*newVx1).clippedEdgeVx1Id = p3Id; + (*newVx1).clippedEdgeVx2Id = p2Id; + ok2 = planeLineIntersect(plane, p1, p3, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx2).clippedEdgeVx1Id = p1Id; + (*newVx2).clippedEdgeVx2Id = p3Id; + CVF_TIGHT_ASSERT(ok1 && ok2); } - else if (topVx = 2) + else if (topVx == 2) { - planeLineIntersect(plane, p2, p3, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); - (*newVx1).clippedEdgeVx1Id = p2Id; - (*newVx1).clippedEdgeVx1Id = p3Id; - planeLineIntersect(plane, p2, p1, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + ok1 = planeLineIntersect(plane, p2, p3, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); (*newVx1).clippedEdgeVx1Id = p2Id; - (*newVx1).clippedEdgeVx1Id = p1Id; + (*newVx1).clippedEdgeVx2Id = p3Id; + ok2 = planeLineIntersect(plane, p2, p1, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx2).clippedEdgeVx1Id = p2Id; + (*newVx2).clippedEdgeVx2Id = p1Id; } - else if (topVx = 3) + else if (topVx == 3) { - planeLineIntersect(plane, p3, p1, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); - (*newVx1).clippedEdgeVx1Id = p3Id; - (*newVx1).clippedEdgeVx1Id = p1Id; - planeLineIntersect(plane, p3, p2, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + ok1 = planeLineIntersect(plane, p3, p1, &((*newVx1).vx), &((*newVx1).normDistFromEdgeVx1)); (*newVx1).clippedEdgeVx1Id = p3Id; - (*newVx1).clippedEdgeVx1Id = p2Id; + (*newVx1).clippedEdgeVx2Id = p1Id; + ok2 = planeLineIntersect(plane, p3, p2, &((*newVx2).vx), &((*newVx2).normDistFromEdgeVx1)); + (*newVx2).clippedEdgeVx1Id = p3Id; + (*newVx2).clippedEdgeVx2Id = p2Id; } else { CVF_ASSERT(false); } + + CVF_TIGHT_ASSERT(ok1 && ok2); return true; } @@ -703,21 +706,23 @@ void RivCrossSectionGeometryGenerator::calculateArrays() { if (m_triangleVxes->size()) return; + m_extrusionDirection.normalize(); + + adjustPolyline(); + std::vector triangleVertices; cvf::Vec3d displayOffset = m_mainGrid->displayModelOffset(); - cvf::BoundingBox gridBBox = m_mainGrid->boundingBox(); - m_extrusionDirection.normalize(); - size_t lineCount = m_polyLine.size(); + size_t lineCount = m_adjustedPolyline.size(); for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) { - cvf::Vec3d p1 = m_polyLine[lIdx]; - cvf::Vec3d p2 = m_polyLine[lIdx+1]; + cvf::Vec3d p1 = m_adjustedPolyline[lIdx]; + cvf::Vec3d p2 = m_adjustedPolyline[lIdx+1]; cvf::BoundingBox sectionBBox; sectionBBox.add(p1); - sectionBBox.add(p1); + sectionBBox.add(p2); double maxSectionHeight = gridBBox.radius(); sectionBBox.add(p1 + m_extrusionDirection*maxSectionHeight); sectionBBox.add(p1 - m_extrusionDirection*maxSectionHeight); @@ -733,7 +738,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() cvf::Plane p1Plane; p1Plane.setFromPoints(p1, p1 + m_extrusionDirection*maxSectionHeight, p1 + plane.normal()); cvf::Plane p2Plane; - p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 + plane.normal() ); + p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 - plane.normal() ); std::vector triangleVxes; @@ -767,7 +772,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (triangleCount) { - #if 1 + #if 0 for (int tIdx = 0; tIdx < triangleCount; ++tIdx) { // Accumulate to geometry @@ -782,64 +787,169 @@ void RivCrossSectionGeometryGenerator::calculateArrays() // Clip triangles with plane 1 std::vector clippedTriangleVxes; - for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) { - ClipVx newVx1; - ClipVx newVx2; - bool isMostVxesOnPositiveSide = false; + int triVxIdx = tIdx*3; - bool isIntersecting = planeTriangleIntersection(p1Plane, + + ClipVx newVx1OnP1; + ClipVx newVx2OnP1; + bool isMostVxesOnPositiveSideOfP1 = false; + bool isIntersectingP1 = planeTriangleIntersection(p1Plane, triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, - &newVx1, &newVx2, &isMostVxesOnPositiveSide); + &newVx1OnP1, &newVx2OnP1, &isMostVxesOnPositiveSideOfP1); - if (!isIntersecting && !isMostVxesOnPositiveSide) + if (!isIntersectingP1 && !isMostVxesOnPositiveSideOfP1) { - // Discard triangle + continue; // Discard triangle } - else if (!isIntersecting && isMostVxesOnPositiveSide) + + + ClipVx newVx1OnP2; + ClipVx newVx2OnP2; + bool isMostVxesOnPositiveSideOfP2 = false; + bool isIntersectingP2 = planeTriangleIntersection(p2Plane, + triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, + triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, + triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, + &newVx1OnP2, &newVx2OnP2, &isMostVxesOnPositiveSideOfP2); + + if (!isIntersectingP2 && !isMostVxesOnPositiveSideOfP2) + { + continue; // Discard triangle + } + + bool p1KeepAll = (!isIntersectingP1 && isMostVxesOnPositiveSideOfP1); + bool p2KeepAll = (!isIntersectingP2 && isMostVxesOnPositiveSideOfP2); + bool p1KeepQuad = (isIntersectingP1 && isMostVxesOnPositiveSideOfP1); + bool p2KeepQuad = (isIntersectingP2 && isMostVxesOnPositiveSideOfP2); + bool p1KeepTop = (isIntersectingP1 && !isMostVxesOnPositiveSideOfP1); + bool p2KeepTop = (isIntersectingP2 && !isMostVxesOnPositiveSideOfP2); + + if (p1KeepAll && p2KeepAll) { // Keep the triangle clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 0]); clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 1]); clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 2]); + continue; } - else if (isIntersecting && isMostVxesOnPositiveSide) + + if (p1KeepQuad && p2KeepAll) { // Split the resulting quad and add the two triangles - clippedTriangleVxes.push_back(newVx2); - clippedTriangleVxes.push_back(newVx1); - clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(newVx1OnP1); + clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); + + clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(newVx2OnP1); + continue; + } - clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx2Id]); - clippedTriangleVxes.push_back(triangleVxes[newVx2.clippedEdgeVx2Id]); - clippedTriangleVxes.push_back(newVx2); + if (p2KeepQuad && p1KeepAll) + { + // Split the resulting quad and add the two triangles + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(triangleVxes[newVx1OnP2.clippedEdgeVx2Id]); + clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + continue; + } + if (p1KeepTop && p2KeepAll) + { + // Add the top triangle + clippedTriangleVxes.push_back(newVx1OnP1); + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx1Id]); + continue; } - else if (isIntersecting && !isMostVxesOnPositiveSide) + + if (p2KeepTop && p1KeepAll) { // Add the top triangle - clippedTriangleVxes.push_back(newVx1); - clippedTriangleVxes.push_back(newVx2); - clippedTriangleVxes.push_back(triangleVxes[newVx1.clippedEdgeVx1Id]); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(triangleVxes[newVx1OnP2.clippedEdgeVx1Id]); + continue; + } + if (p1KeepQuad && p2KeepQuad) + { + // We end up with a penthagon. + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(newVx1OnP1); + clippedTriangleVxes.push_back(newVx2OnP2); + + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(newVx2OnP1); + + // Two variants. The original point might be along newVx1OnP1 to newVx2OnP2 or along newVx2OnP1 to newVx1OnP2 + if (newVx1OnP1.clippedEdgeVx2Id == newVx2OnP2.clippedEdgeVx1Id) + { + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); + } + else + { + + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(newVx1OnP1); + clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + } + continue; } - } - - // Clip triangles with plane 2 - for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) - { + if (p1KeepQuad && p2KeepTop) + { + // We end up with a quad. + clippedTriangleVxes.push_back(newVx1OnP1); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(newVx2OnP1); + + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(newVx2OnP1); + continue; + } + if (p2KeepQuad && p1KeepTop) + { + // We end up with a quad. + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(newVx2OnP2); + clippedTriangleVxes.push_back(newVx1OnP2); + + clippedTriangleVxes.push_back(newVx2OnP1); + clippedTriangleVxes.push_back(newVx1OnP2); + clippedTriangleVxes.push_back(newVx1OnP1); + + continue; + } + + CVF_ASSERT(false); } - for (int triVxIdx = 0; tIdx < triangleCount; ++tIdx) + triangleCount = static_cast(clippedTriangleVxes.size())/3; + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) { - // Accumulate to geometry - - } + int triVxIdx = tIdx*3; + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); + + m_triangleToCellIdxMap.push_back(globalCellIdx); + } #endif } } @@ -916,3 +1026,27 @@ void RivCrossSectionGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textu } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionGeometryGenerator::adjustPolyline() +{ + size_t lineCount = m_polyLine.size(); + if (!m_polyLine.size()) return; + + m_adjustedPolyline.push_back(m_polyLine[0]); + cvf::Vec3d p1 = m_polyLine[0]; + + for (size_t lIdx = 1; lIdx < lineCount; ++lIdx) + { + cvf::Vec3d p2 = m_polyLine[lIdx]; + cvf::Vec3d p1p2 = p2 - p1; + + if ((p1p2 - (p1p2 * m_extrusionDirection)*m_extrusionDirection).length() > 0.1 ) + { + m_adjustedPolyline.push_back(p2); + p1 = p2; + } + } +} diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 1ecaee1907..06178e3edc 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -57,12 +57,13 @@ class RivCrossSectionGeometryGenerator : public cvf::Object private: void calculateArrays(); - + void adjustPolyline(); cvf::ref m_triangleVxes; std::vector m_triangleToCellIdxMap; cvf::cref m_mainGrid; std::vector m_polyLine; cvf::Vec3d m_extrusionDirection; + std::vector m_adjustedPolyline; }; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 37dfdd7f2e..2f621123b9 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -49,17 +49,15 @@ //-------------------------------------------------------------------------------------------------- RivCrossSectionPartMgr::RivCrossSectionPartMgr( const RigMainGrid* grid, const RimCrossSectionCollection* rimCrossSectionCollection, - const RimCrossSection* rimCrossSection) + const RimCrossSection* rimCrossSection, + const std::vector& polyLine) : m_grid(grid), m_rimCrossSectionCollection(rimCrossSectionCollection), m_rimCrossSection(rimCrossSection), m_defaultColor(cvf::Color3::WHITE) { - std::vector polyLine; - polyLine.push_back(grid->boundingBox().max()); - polyLine.push_back(grid->boundingBox().min()); - m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine, cvf::Vec3d(0,0,1.0), grid ); + m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine, cvf::Vec3d(0.0,0,1.0), grid ); m_nativeCrossSectionFacesTextureCoords = new cvf::Vec2fArray; } @@ -228,7 +226,7 @@ void RivCrossSectionPartMgr::updatePartEffect() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model) +void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { if (m_nativeCrossSectionFaces.isNull()) { @@ -237,6 +235,7 @@ void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasi if (m_nativeCrossSectionFaces.notNull()) { + m_nativeCrossSectionFaces->setTransform(scaleTransform); model->addPart(m_nativeCrossSectionFaces.p()); } } @@ -245,8 +244,17 @@ void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* model) +void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { - if (m_nativeCrossSectionGridLines.notNull()) model->addPart(m_nativeCrossSectionGridLines.p()); + if (m_nativeCrossSectionGridLines.isNull()) + { + generatePartGeometry(); + } + + if (m_nativeCrossSectionGridLines.notNull()) + { + m_nativeCrossSectionGridLines->setTransform(scaleTransform); + model->addPart(m_nativeCrossSectionGridLines.p()); + } } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 11cfb3b697..091dccb98b 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -47,13 +47,14 @@ class RivCrossSectionPartMgr : public cvf::Object public: RivCrossSectionPartMgr(const RigMainGrid* grid, const RimCrossSectionCollection* rimCrossSectionCollection, - const RimCrossSection* rimCrossSection); + const RimCrossSection* rimCrossSection, + const std::vector& polyLine); void applySingleColorEffect(); void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); - void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model); - void appendMeshLinePartsToModel(cvf::ModelBasicList* model); + void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); + void appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); private: void updatePartEffect(); From 4f40b3de1f1a2d62c346a303703dde57568a85e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 18 Nov 2015 11:47:52 +0100 Subject: [PATCH 069/290] (#166) Test code commented out of EclipseView --- .../ProjectDataModel/RimEclipseView.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index a98f24b1a5..2d02523ede 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -417,13 +417,19 @@ void RimEclipseView::createDisplayModel() } + // Hack to do testing of cross section { - if (m_csPartmgr.isNull()) m_csPartmgr = new RivCrossSectionPartMgr(m_reservoir->reservoirData()->mainGrid(), NULL, NULL); +#if 0 + cvf::ref tempMod = new cvf::ModelBasicList; + + m_pipesPartManager->appendDynamicGeometryPartsToModel(tempMod.p(), 3); + if (m_csPartmgr.isNull()) m_csPartmgr = new RivCrossSectionPartMgr(m_reservoir->reservoirData()->mainGrid(), NULL, NULL, + (*m_pipesPartManager->centerLineOfWellBranches(0))[0]); for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx) { - m_csPartmgr->appendNativeCrossSectionFacesToModel(frameModels[frameIdx].p()); - frameModels[frameIdx]->part(frameModels[frameIdx]->partCount()-1)->setTransform(m_reservoirGridPartManager->scaleTransform()); + m_csPartmgr->appendNativeCrossSectionFacesToModel(frameModels[frameIdx].p(), m_reservoirGridPartManager->scaleTransform()); } +#endif } // Compute triangle count, Debug only @@ -652,6 +658,11 @@ void RimEclipseView::updateCurrentTimeStep() this->updateFaultColors(); + // Hack to do testing of cross section + { + // this->m_csPartmgr->updateCellResultColor(m_currentTimeStep, this->cellResult()); + } + // Well pipes if (m_viewer) { From 9946df40712ff6bdbdbcb2ec7d51b926c5934274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 18 Nov 2015 15:29:10 +0100 Subject: [PATCH 070/290] (#166) WIP: Added cell border line code. --- .../RivCrossSectionGeometryGenerator.cpp | 587 ++++++++++++------ .../RivCrossSectionGeometryGenerator.h | 6 + .../ProjectDataModel/RimEclipseView.cpp | 1 + 3 files changed, 397 insertions(+), 197 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 70c9a17b4d..948553b167 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -23,6 +23,7 @@ #include "cvfDrawableGeo.h" #include "RigResultAccessor.h" #include "cvfScalarMapper.h" +#include "cvfPrimitiveSetDirect.h" //-------------------------------------------------------------------------------------------------- @@ -36,6 +37,7 @@ RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::ve m_mainGrid(grid) { m_triangleVxes = new cvf::Vec3fArray; + m_cellBorderLineVxes = new cvf::Vec3fArray; } //-------------------------------------------------------------------------------------------------- @@ -209,14 +211,271 @@ bool planeTriangleIntersection(const cvf::Plane& plane, return true; } -#if 0 -bool planeTriangleIntersection(const cvf::Plane& plane, - const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, - ClipVx* newVx1, ClipVx* newVx2) +//-------------------------------------------------------------------------------------------------- +// +// +// P2 P2 P2 P2 +// Keep Keep Keep Keep +// None Top 3 Quad All +// | | + | | +// | | / \ | | +// | | | | / \ | | | | +// | | | | / \ | | | | +// | | | | / \| | | | +// | | | |/ 1+ | | | +// | | | +2 |\ | | | +// | | | /| | \ | | | +// | | | / | | \ | _ | | +// | | | / | | \| |\Dir | | +// | | |/ | | 1+ \ | | +// | | +2 | | |\ \ | | +// | | /| | | | \ | | +// | | / |1 |1 2| 2| \ | | +// | | +--+----+----------+----+---+ | | +// | |1 | | | | 2 | | +// P1 P1 P1 P1 +// Keep Keep Keep Keep +// All Quad Top None +// +// +//-------------------------------------------------------------------------------------------------- + +void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVxes, + const std::vector &isTriangleEdgeInternal, + const cvf::Plane& p1Plane, const cvf::Plane& p2Plane, + std::vector *clippedTriangleVxes, + std::vector *isClippedTriEdgeCellContour) { -} -#endif + int triangleCount = static_cast(triangleVxes.size())/3; + + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + { + + int triVxIdx = tIdx*3; + + ClipVx newVx1OnP1; + ClipVx newVx2OnP1; + bool isMostVxesOnPositiveSideOfP1 = false; + bool isIntersectingP1 = planeTriangleIntersection(p1Plane, + triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, + triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, + triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, + &newVx1OnP1, &newVx2OnP1, &isMostVxesOnPositiveSideOfP1); + + if (!isIntersectingP1 && !isMostVxesOnPositiveSideOfP1) + { + continue; // Discard triangle + } + + + ClipVx newVx1OnP2; + ClipVx newVx2OnP2; + bool isMostVxesOnPositiveSideOfP2 = false; + bool isIntersectingP2 = planeTriangleIntersection(p2Plane, + triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, + triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, + triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, + &newVx1OnP2, &newVx2OnP2, &isMostVxesOnPositiveSideOfP2); + + if (!isIntersectingP2 && !isMostVxesOnPositiveSideOfP2) + { + continue; // Discard triangle + } + + bool p1KeepAll = (!isIntersectingP1 && isMostVxesOnPositiveSideOfP1); + bool p2KeepAll = (!isIntersectingP2 && isMostVxesOnPositiveSideOfP2); + bool p1KeepQuad = (isIntersectingP1 && isMostVxesOnPositiveSideOfP1); + bool p2KeepQuad = (isIntersectingP2 && isMostVxesOnPositiveSideOfP2); + bool p1KeepTop = (isIntersectingP1 && !isMostVxesOnPositiveSideOfP1); + bool p2KeepTop = (isIntersectingP2 && !isMostVxesOnPositiveSideOfP2); + + if (p1KeepAll && p2KeepAll) + { + // Keep the triangle + clippedTriangleVxes->push_back(triangleVxes[triVxIdx + 0]); + clippedTriangleVxes->push_back(triangleVxes[triVxIdx + 1]); + clippedTriangleVxes->push_back(triangleVxes[triVxIdx + 2]); + + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 0]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 1]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 2]); + + continue; + } + + if (p1KeepQuad && p2KeepAll) + { + // Split the resulting quad and add the two triangles + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(newVx1OnP1); + clippedTriangleVxes->push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); + + clippedTriangleVxes->push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); + clippedTriangleVxes->push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); + clippedTriangleVxes->push_back(newVx2OnP1); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(false); + + continue; + } + + if (p2KeepQuad && p1KeepAll) + { + // Split the resulting quad and add the two triangles + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(triangleVxes[newVx1OnP2.clippedEdgeVx2Id]); + clippedTriangleVxes->push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(false); + + continue; + } + + if (p1KeepTop && p2KeepAll) + { + // Add the top triangle + clippedTriangleVxes->push_back(newVx1OnP1); + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(triangleVxes[newVx1OnP1.clippedEdgeVx1Id]); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + + continue; + } + + if (p2KeepTop && p1KeepAll) + { + // Add the top triangle + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(triangleVxes[newVx1OnP2.clippedEdgeVx1Id]); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + + continue; + } + + if (p1KeepQuad && p2KeepQuad) + { + // We end up with a pentagon. + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(newVx1OnP1); + clippedTriangleVxes->push_back(newVx2OnP2); + + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(newVx2OnP1); + + + // Two variants. The original point might be along newVx1OnP1 to newVx2OnP2 or along newVx2OnP1 to newVx1OnP2 + if (newVx1OnP1.clippedEdgeVx2Id == newVx2OnP2.clippedEdgeVx1Id) + { + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + } + else + { + + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(newVx1OnP1); + clippedTriangleVxes->push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + } + + continue; + } + + if (p1KeepQuad && p2KeepTop) + { + // We end up with a quad. + clippedTriangleVxes->push_back(newVx1OnP1); + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(newVx2OnP1); + + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(newVx2OnP1); + + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(false); + + continue; + } + + if (p2KeepQuad && p1KeepTop) + { + // We end up with a quad. + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(newVx2OnP2); + clippedTriangleVxes->push_back(newVx1OnP2); + + clippedTriangleVxes->push_back(newVx2OnP1); + clippedTriangleVxes->push_back(newVx1OnP2); + clippedTriangleVxes->push_back(newVx1OnP1); + + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(false); + + isClippedTriEdgeCellContour->push_back(false); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(false); + + continue; + } + + CVF_ASSERT(false); + } +} #if 0 @@ -326,7 +585,8 @@ cvf::Vec3d planeLineIntersectionForMC(const cvf::Plane& plane, const cvf::Vec3d& int planeHexIntersectionMC(const cvf::Plane& plane, const cvf::Vec3d cell[8], const int hexCornersIds[8], - std::vector* triangles) + std::vector* triangleVxes, + std::vector* isTriEdgeCellContour) { // Based on description and implementation from Paul Bourke: @@ -680,25 +940,70 @@ int planeHexIntersectionMC(const cvf::Plane& plane, // Create the triangles - const int* triConnects = cubeIdxToTriangleIndices[cubeIndex]; - uint n = 0; - int edgeIdx = triConnects[n]; - while (edgeIdx != -1) + const int* triangleIndicesToCubeEdges = cubeIdxToTriangleIndices[cubeIndex]; + uint triangleVxIdx = 0; + int cubeEdgeIdx = triangleIndicesToCubeEdges[triangleVxIdx]; + + + while (cubeEdgeIdx != -1) { ClipVx cvx; - cvx.vx = edgeIntersections[edgeIdx]; - cvx.normDistFromEdgeVx1 = normDistAlongEdge[edgeIdx]; - cvx.clippedEdgeVx1Id = hexCornersIds[edgeTable[edgeIdx][0]]; - cvx.clippedEdgeVx2Id = hexCornersIds[edgeTable[edgeIdx][1]]; - - (*triangles).push_back(cvx); - ++n; - edgeIdx = triConnects[n]; + cvx.vx = edgeIntersections[cubeEdgeIdx]; + cvx.normDistFromEdgeVx1 = normDistAlongEdge[cubeEdgeIdx]; + cvx.clippedEdgeVx1Id = hexCornersIds[edgeTable[cubeEdgeIdx][0]]; + cvx.clippedEdgeVx2Id = hexCornersIds[edgeTable[cubeEdgeIdx][1]]; + + (*triangleVxes).push_back(cvx); + ++triangleVxIdx; + cubeEdgeIdx = triangleIndicesToCubeEdges[triangleVxIdx]; + } + + uint triangleCount = triangleVxIdx/3; + + int triangleEdgeCount[12][12] ={ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }; + + (*isTriEdgeCellContour).clear(); + (*isTriEdgeCellContour).resize(triangleVxIdx, false); + + for (uint tIdx = 0; tIdx < triangleCount; ++tIdx) + { + int triVxIdx = 3*tIdx; + int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx]; + int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1]; + int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2 ]; + + cubeEdgeIdx1 < cubeEdgeIdx2 ? ++triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx2]: ++triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx1]; + cubeEdgeIdx2 < cubeEdgeIdx3 ? ++triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx3]: ++triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx2]; + cubeEdgeIdx3 < cubeEdgeIdx1 ? ++triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx1]: ++triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx3]; } - uint numTriangles = n/3; + for (uint tIdx = 0; tIdx < triangleCount; ++tIdx) + { + int triVxIdx = 3*tIdx; + + int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx]; + int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1]; + int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2 ]; + + (*isTriEdgeCellContour)[triVxIdx+0] = (1 == (cubeEdgeIdx1 < cubeEdgeIdx2 ? triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx2]: triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx1])); + (*isTriEdgeCellContour)[triVxIdx+1] = (1 == (cubeEdgeIdx2 < cubeEdgeIdx3 ? triangleEdgeCount[cubeEdgeIdx2][cubeEdgeIdx3]: triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx2])); + (*isTriEdgeCellContour)[triVxIdx+2] = (1 == (cubeEdgeIdx3 < cubeEdgeIdx1 ? triangleEdgeCount[cubeEdgeIdx3][cubeEdgeIdx1]: triangleEdgeCount[cubeEdgeIdx1][cubeEdgeIdx3])); + } - return numTriangles; + return triangleCount; } @@ -711,6 +1016,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() adjustPolyline(); std::vector triangleVertices; + std::vector cellBorderLineVxes; + cvf::Vec3d displayOffset = m_mainGrid->displayModelOffset(); cvf::BoundingBox gridBBox = m_mainGrid->boundingBox(); @@ -743,6 +1050,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() std::vector triangleVxes; triangleVxes.reserve(5*3); + std::vector isTriangleEdgeCellContour; + isTriangleEdgeCellContour.reserve(5*3); for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) { @@ -768,195 +1077,70 @@ void RivCrossSectionGeometryGenerator::calculateArrays() int triangleCount = planeHexIntersectionMC(plane, cellCorners, hexCornersIds, - &triangleVxes); + &triangleVxes, + &isTriangleEdgeCellContour); - if (triangleCount) + +#if 0 + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) { - #if 0 - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) - { - // Accumulate to geometry - int triVxIdx = tIdx*3; - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx - displayOffset)); + // Accumulate to geometry + int triVxIdx = tIdx*3; + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx - displayOffset)); - m_triangleToCellIdxMap.push_back(globalCellIdx); - } - #else + m_triangleToCellIdxMap.push_back(globalCellIdx); + } +#else + + + std::vector clippedTriangleVxes; + std::vector isClippedTriEdgeCellContour; - // Clip triangles with plane 1 - std::vector clippedTriangleVxes; - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + clipTrianglesBetweenTwoParallelPlanes(triangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); + + triangleCount = static_cast(clippedTriangleVxes.size())/3; + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + { + // Accumulate to geometry + int triVxIdx = tIdx*3; + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); + triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); + + m_triangleToCellIdxMap.push_back(globalCellIdx); + } + + for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + { + // Accumulate to geometry + int triVxIdx = tIdx*3; + if (isClippedTriEdgeCellContour[triVxIdx]) { - - int triVxIdx = tIdx*3; - - ClipVx newVx1OnP1; - ClipVx newVx2OnP1; - bool isMostVxesOnPositiveSideOfP1 = false; - bool isIntersectingP1 = planeTriangleIntersection(p1Plane, - triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, - triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, - triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, - &newVx1OnP1, &newVx2OnP1, &isMostVxesOnPositiveSideOfP1); - - if (!isIntersectingP1 && !isMostVxesOnPositiveSideOfP1) - { - continue; // Discard triangle - } - - - ClipVx newVx1OnP2; - ClipVx newVx2OnP2; - bool isMostVxesOnPositiveSideOfP2 = false; - bool isIntersectingP2 = planeTriangleIntersection(p2Plane, - triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, - triangleVxes[triVxIdx + 1].vx, triVxIdx + 1, - triangleVxes[triVxIdx + 2].vx, triVxIdx + 2, - &newVx1OnP2, &newVx2OnP2, &isMostVxesOnPositiveSideOfP2); - - if (!isIntersectingP2 && !isMostVxesOnPositiveSideOfP2) - { - continue; // Discard triangle - } - - bool p1KeepAll = (!isIntersectingP1 && isMostVxesOnPositiveSideOfP1); - bool p2KeepAll = (!isIntersectingP2 && isMostVxesOnPositiveSideOfP2); - bool p1KeepQuad = (isIntersectingP1 && isMostVxesOnPositiveSideOfP1); - bool p2KeepQuad = (isIntersectingP2 && isMostVxesOnPositiveSideOfP2); - bool p1KeepTop = (isIntersectingP1 && !isMostVxesOnPositiveSideOfP1); - bool p2KeepTop = (isIntersectingP2 && !isMostVxesOnPositiveSideOfP2); - - if (p1KeepAll && p2KeepAll) - { - // Keep the triangle - clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 0]); - clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 1]); - clippedTriangleVxes.push_back(triangleVxes[triVxIdx + 2]); - continue; - } - - if (p1KeepQuad && p2KeepAll) - { - // Split the resulting quad and add the two triangles - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(newVx1OnP1); - clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); - - clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx2Id]); - clippedTriangleVxes.push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); - clippedTriangleVxes.push_back(newVx2OnP1); - continue; - } - - if (p2KeepQuad && p1KeepAll) - { - // Split the resulting quad and add the two triangles - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); - - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(triangleVxes[newVx1OnP2.clippedEdgeVx2Id]); - clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); - continue; - } - - if (p1KeepTop && p2KeepAll) - { - // Add the top triangle - clippedTriangleVxes.push_back(newVx1OnP1); - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(triangleVxes[newVx1OnP1.clippedEdgeVx1Id]); - continue; - } - - if (p2KeepTop && p1KeepAll) - { - // Add the top triangle - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(triangleVxes[newVx1OnP2.clippedEdgeVx1Id]); - continue; - } - - if (p1KeepQuad && p2KeepQuad) - { - // We end up with a penthagon. - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(newVx1OnP1); - clippedTriangleVxes.push_back(newVx2OnP2); - - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(newVx2OnP1); - - // Two variants. The original point might be along newVx1OnP1 to newVx2OnP2 or along newVx2OnP1 to newVx1OnP2 - if (newVx1OnP1.clippedEdgeVx2Id == newVx2OnP2.clippedEdgeVx1Id) - { - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); - } - else - { - - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(newVx1OnP1); - clippedTriangleVxes.push_back(triangleVxes[newVx2OnP2.clippedEdgeVx2Id]); - } - continue; - } - - if (p1KeepQuad && p2KeepTop) - { - // We end up with a quad. - clippedTriangleVxes.push_back(newVx1OnP1); - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(newVx2OnP1); - - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(newVx2OnP1); - continue; - } - - if (p2KeepQuad && p1KeepTop) - { - // We end up with a quad. - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(newVx2OnP2); - clippedTriangleVxes.push_back(newVx1OnP2); - - clippedTriangleVxes.push_back(newVx2OnP1); - clippedTriangleVxes.push_back(newVx1OnP2); - clippedTriangleVxes.push_back(newVx1OnP1); - - continue; - } - - CVF_ASSERT(false); + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); } - - triangleCount = static_cast(clippedTriangleVxes.size())/3; - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + if (isClippedTriEdgeCellContour[triVxIdx+1]) + { + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); + } + if (isClippedTriEdgeCellContour[triVxIdx+2]) { - // Accumulate to geometry - int triVxIdx = tIdx*3; - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); - - m_triangleToCellIdxMap.push_back(globalCellIdx); - } - #endif + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); + cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); + } + } +#endif + } } m_triangleVxes->assign(triangleVertices); + m_cellBorderLineVxes->assign(cellBorderLineVxes); } @@ -984,7 +1168,16 @@ cvf::ref RivCrossSectionGeometryGenerator::generateSurface() //-------------------------------------------------------------------------------------------------- cvf::ref RivCrossSectionGeometryGenerator::createMeshDrawable() { + if (!(m_cellBorderLineVxes.notNull() && m_cellBorderLineVxes->size() != 0)) return NULL; + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray(m_cellBorderLineVxes.p()); + + + cvf::ref prim = new cvf::PrimitiveSetDirect(cvf::PT_LINES); + prim->setIndexCount(m_cellBorderLineVxes->size()); + + geo->addPrimitiveSet(prim.p()); return geo; } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 06178e3edc..270387fb27 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -18,6 +18,7 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once +#include "cvfBase.h" #include "cvfObject.h" #include "cvfVector3.h" #include "cvfArray.h" @@ -57,8 +58,13 @@ class RivCrossSectionGeometryGenerator : public cvf::Object private: void calculateArrays(); + + + void adjustPolyline(); cvf::ref m_triangleVxes; + cvf::ref m_cellBorderLineVxes; + std::vector m_triangleToCellIdxMap; cvf::cref m_mainGrid; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 2d02523ede..9a75b970ba 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -428,6 +428,7 @@ void RimEclipseView::createDisplayModel() for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx) { m_csPartmgr->appendNativeCrossSectionFacesToModel(frameModels[frameIdx].p(), m_reservoirGridPartManager->scaleTransform()); + m_csPartmgr->appendMeshLinePartsToModel(frameModels[frameIdx].p(), m_reservoirGridPartManager->scaleTransform()); } #endif } From 7d60b8e90d36d30be33b7bf9196ebb6f7d83a779 Mon Sep 17 00:00:00 2001 From: Jacob Storen Date: Wed, 18 Nov 2015 06:33:33 -0800 Subject: [PATCH 071/290] Fix Linux warning --- Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewModel.cpp index 8a7a012f37..c01d9d4b32 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewModel.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewModel.cpp @@ -508,7 +508,7 @@ void PdmUiTableViewModel::recreateTableItemEditors() //-------------------------------------------------------------------------------------------------- PdmObjectHandle* PdmUiTableViewModel::pdmObjectForRow(int row) const { - if (m_pdmList && row < m_pdmList->size()) + if (m_pdmList && row < static_cast(m_pdmList->size())) { return m_pdmList->at(row); } From cc1a8cf28d1e33154014948e4f78abc5a9fc9e97 Mon Sep 17 00:00:00 2001 From: Jacob Storen Date: Wed, 18 Nov 2015 06:50:15 -0800 Subject: [PATCH 072/290] Fixed Linux warnings --- ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp | 2 +- .../ModelVisualization/RivSingleCellPartGenerator.cpp | 2 +- ApplicationCode/UserInterface/RiuResultQwtPlot.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp index a8a3744588..a4abb03632 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirPipesPartMgr.cpp @@ -144,7 +144,7 @@ void RivReservoirPipesPartMgr::updatePipeResultColor(size_t frameIndex) //-------------------------------------------------------------------------------------------------- const std::vector< std::vector >* RivReservoirPipesPartMgr::centerLineOfWellBranches(int wellIdx) { - if (wellIdx < m_wellPipesPartMgrs.size()) + if (wellIdx < static_cast(m_wellPipesPartMgrs.size())) { return &(m_wellPipesPartMgrs[wellIdx]->centerLineOfWellBranches()); } diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp index 289c86d5d0..9168a10968 100644 --- a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp @@ -91,7 +91,7 @@ cvf::ref RivSingleCellPartGenerator::createMeshDrawable() else if (m_geoMechCase && m_cellIndex != cvf::UNDEFINED_SIZE_T) { CVF_ASSERT(m_geoMechCase->geoMechData()); - CVF_ASSERT(m_geoMechCase->geoMechData()->femParts()->partCount() > m_gridIndex); + CVF_ASSERT(m_geoMechCase->geoMechData()->femParts()->partCount() > static_cast(m_gridIndex)); RigFemPart* femPart = m_geoMechCase->geoMechData()->femParts()->part(m_gridIndex); CVF_ASSERT(femPart); diff --git a/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp index d7f955910a..f1fc01fa0e 100644 --- a/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp @@ -83,7 +83,7 @@ void RiuResultQwtPlot::addCurve(const QString& curveName, const cvf::Color3f& cu RiuLineSegmentQwtPlotCurve* plotCurve = new RiuLineSegmentQwtPlotCurve("Curve 1"); QPolygonF points; - for (int i = 0; i < filteredDateTimes.size(); i++) + for (size_t i = 0; i < filteredDateTimes.size(); i++) { double milliSecSinceEpoch = QwtDate::toDouble(filteredDateTimes[i]); points << QPointF(milliSecSinceEpoch, filteredTimeHistoryValues[i]); From f2e80624107f08404673845fff2e9f385ea865ab Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 09:15:13 +0100 Subject: [PATCH 073/290] (#657) Added cross section and cross section collection --- .../ProjectDataModel/CMakeLists_files.cmake | 4 + .../ProjectDataModel/RimCrossSection.cpp | 103 ++++++++++++++++++ .../ProjectDataModel/RimCrossSection.h | 68 ++++++++++++ .../RimCrossSectionCollection.cpp | 47 ++++++++ .../RimCrossSectionCollection.h | 47 ++++++++ .../ProjectDataModel/RimEclipseView.cpp | 2 + .../ProjectDataModel/RimGeoMechView.cpp | 2 + ApplicationCode/ProjectDataModel/RimView.cpp | 11 +- ApplicationCode/ProjectDataModel/RimView.h | 3 + 9 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimCrossSection.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimCrossSection.h create mode 100644 ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index ae9966a825..a8873b1e01 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -72,6 +72,8 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurve.h ${CEE_CURRENT_LIST_DIR}RimWellLogFile.h ${CEE_CURRENT_LIST_DIR}RimWellLogFileChannel.h ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.h +${CEE_CURRENT_LIST_DIR}RimCrossSection.h +${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -142,6 +144,8 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurve.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogFile.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogFileChannel.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.cpp +${CEE_CURRENT_LIST_DIR}RimCrossSection.cpp +${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp new file mode 100644 index 0000000000..24e11fbcc6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -0,0 +1,103 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCrossSection.h" + + + + +namespace caf { + + template<> + void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() + { + addItem(RimCrossSection::CS_WELL_PATH, "WELL_PATH", "Well Path"); + addItem(RimCrossSection::CS_SIMULATION_WELL, "SIMULATION_WELL", "Simulation Well"); + addItem(RimCrossSection::CS_USER_DEFINED, "USER_DEFINED", "User defined"); + setDefault(RimCrossSection::CS_WELL_PATH); + } + +} + + +CAF_PDM_SOURCE_INIT(RimCrossSection, "CrossSection"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCrossSection::RimCrossSection() +{ + CAF_PDM_InitObject("Cross Section", "", "", ""); + + CAF_PDM_InitField(&name, "UserDescription", QString("Cross Section Name"), "Name", "", "", ""); + CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); + isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&crossSectionType, "CrossSectionType", "Type", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimCrossSection::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) +{ + QList options; + + if (useOptionsOnly) (*useOptionsOnly) = true; + +/* + if (&gridIndex == fieldNeedingOptions) + { + for (int gIdx = 0; gIdx < parentContainer()->gridCount(); ++gIdx) + { + QString gridName; + + gridName += parentContainer()->gridName(gIdx); + if (gIdx == 0) + { + if (gridName.isEmpty()) + gridName += "Main Grid"; + else + gridName += " (Main Grid)"; + } + + caf::PdmOptionItemInfo item(gridName, (int)gIdx); + options.push_back(item); + } + } +*/ + return options; +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h new file mode 100644 index 0000000000..40144aa18c --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +class RimWellPath; +class RimEclipseWell; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RimCrossSection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum CrossSectionEnum + { + CS_WELL_PATH, + CS_SIMULATION_WELL, + CS_USER_DEFINED + }; + +public: + RimCrossSection(); + + caf::PdmField name; + caf::PdmField isActive; + caf::PdmField< caf::AppEnum< CrossSectionEnum > > crossSectionType; + + caf::PdmPtrField wellPath; + caf::PdmPtrField simulationWell; + +protected: + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); +// virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); +// virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); + + virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); + + +private: +}; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp new file mode 100644 index 0000000000..09a899275e --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCrossSectionCollection.h" + +#include "RimCrossSection.h" + + +CAF_PDM_SOURCE_INIT(RimCrossSectionCollection, "CrossSectionCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCrossSectionCollection::RimCrossSectionCollection() +{ + CAF_PDM_InitObject("Cross Sections", ":/undefined_image.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&crossSections, "CrossSections", "Cross Sections", "", "", ""); + crossSections.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); + isActive.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimCrossSectionCollection::objectToggleField() +{ + return &isActive; +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h new file mode 100644 index 0000000000..892d586c09 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" + +class RimCrossSection; + +//================================================================================================== +// +// +// +//================================================================================================== +class RimCrossSectionCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimCrossSectionCollection(); + + caf::PdmField isActive; + caf::PdmChildArrayField crossSections; + +protected: + //virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + //virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); + virtual caf::PdmFieldHandle* objectToggleField(); +}; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 9a75b970ba..df0ddc365a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -31,6 +31,7 @@ #include "Rim3dOverlayInfoConfig.h" #include "RimCellEdgeColors.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSectionCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseFaultColors.h" @@ -1349,6 +1350,7 @@ void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); + uiTreeOrdering.add(m_crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 1cbe88b322..716031add0 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -29,6 +29,7 @@ #include "Rim3dOverlayInfoConfig.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSectionCollection.h" #include "RimEclipseView.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" @@ -636,6 +637,7 @@ void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); + uiTreeOrdering.add(m_crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 634448e013..4fca175e19 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -7,10 +7,12 @@ #include "Rim3dOverlayInfoConfig.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSectionCollection.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimOilField.h" #include "RimProject.h" +#include "RimPropertyFilterCollection.h" #include "RimViewController.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" @@ -31,7 +33,6 @@ #include "cvfViewport.h" #include -#include "RimPropertyFilterCollection.h" namespace caf { @@ -40,8 +41,8 @@ template<> void caf::AppEnum< RimView::MeshModeType >::setUp() { addItem(RimView::FULL_MESH, "FULL_MESH", "All"); - addItem(RimView::FAULTS_MESH, "FAULTS_MESH", "Faults only"); - addItem(RimView::NO_MESH, "NO_MESH", "None"); + addItem(RimView::FAULTS_MESH, "FAULTS_MESH", "Faults only"); + addItem(RimView::NO_MESH, "NO_MESH", "None"); setDefault(RimView::FULL_MESH); } @@ -116,6 +117,10 @@ RimView::RimView(void) m_overrideRangeFilterCollection.xmlCapability()->setIOWritable(false); m_overrideRangeFilterCollection.xmlCapability()->setIOReadable(false); + CAF_PDM_InitFieldNoDefault(&m_crossSectionCollection, "CrossSections", "Cross Sections", "", "", ""); + m_crossSectionCollection.uiCapability()->setUiHidden(true); + m_crossSectionCollection = new RimCrossSectionCollection(); + m_previousGridModeMeshLinesWasFaults = false; } diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index f9687552f8..cc4d2bb8ed 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -44,6 +44,7 @@ class RiuViewer; class RimViewLinker; class RimViewController; class RimPropertyFilterCollection; +class RimCrossSectionCollection; namespace cvf { @@ -190,6 +191,8 @@ class RimView : public caf::PdmObject caf::PdmChildField m_rangeFilterCollection; caf::PdmChildField m_overrideRangeFilterCollection; + + caf::PdmChildField m_crossSectionCollection; // Overridden PDM methods: virtual void setupBeforeSave(); From fec506121249322e60bafd5e448bd5c45aef052c Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 09:35:38 +0100 Subject: [PATCH 074/290] Moved context command builder into separate file --- .../ProjectDataModel/CMakeLists_files.cmake | 2 + .../RimContextCommandBuilder.cpp | 277 ++++++++++++++++++ .../RimContextCommandBuilder.h | 32 ++ .../ProjectDataModel/RimProject.cpp | 254 +--------------- 4 files changed, 318 insertions(+), 247 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index a8873b1e01..c276e011c4 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -74,6 +74,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogFileChannel.h ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.h ${CEE_CURRENT_LIST_DIR}RimCrossSection.h ${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.h +${CEE_CURRENT_LIST_DIR}RimContextCommandBuilder.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -146,6 +147,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogFileChannel.cpp ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.cpp ${CEE_CURRENT_LIST_DIR}RimCrossSection.cpp ${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.cpp +${CEE_CURRENT_LIST_DIR}RimContextCommandBuilder.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp new file mode 100644 index 0000000000..68ff16993d --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -0,0 +1,277 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimContextCommandBuilder.h" + +#include "RimCalcScript.h" +#include "RimCaseCollection.h" +#include "RimCellRangeFilter.h" +#include "RimCellRangeFilterCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCaseCollection.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseInputProperty.h" +#include "RimEclipseInputPropertyCollection.h" +#include "RimEclipsePropertyFilter.h" +#include "RimEclipsePropertyFilterCollection.h" +#include "RimEclipseStatisticsCase.h" +#include "RimEclipseView.h" +#include "RimGeoMechCase.h" +#include "RimGeoMechPropertyFilter.h" +#include "RimGeoMechPropertyFilterCollection.h" +#include "RimGeoMechView.h" +#include "RimIdenticalGridCaseGroup.h" +#include "RimScriptCollection.h" +#include "RimViewController.h" +#include "RimViewLinker.h" +#include "RimWellLogCurve.h" +#include "RimWellLogFileChannel.h" +#include "RimWellLogPlot.h" +#include "RimWellLogPlotCollection.h" +#include "RimWellLogTrack.h" +#include "RimWellPath.h" +#include "RimWellPathCollection.h" + +#include "ToggleCommands/RicToggleItemsFeatureImpl.h" + +#include "cafPdmUiItem.h" +#include "cafSelectionManager.h" +#include "cvfAssert.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimContextCommandBuilder::commandsFromSelection() +{ + QStringList commandIds; + + std::vector uiItems; + caf::SelectionManager::instance()->selectedItems(uiItems); + + if (uiItems.size() == 0) + { + commandIds << "RicNewWellLogPlotFeature"; + } + else if (uiItems.size() > 1) + { + caf::PdmUiItem* uiItem = uiItems[0]; + if (dynamic_cast(uiItem)) + { + commandIds << "RicAddWellLogToPlotFeature"; + } + } + else if (uiItems.size() == 1) + { + caf::PdmUiItem* uiItem = uiItems[0]; + CVF_ASSERT(uiItem); + + if (dynamic_cast(uiItem)) + { + commandIds << "RicImportEclipseCaseFeature"; + commandIds << "RicImportInputEclipseCaseFeature"; + commandIds << "RicCreateGridCaseGroupFeature"; + commandIds << "RicEclipseCaseNewGroupFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewViewFeature"; + commandIds << "RicCopyReferencesToClipboardFeature"; + commandIds << "RicPasteGeoMechViewsFeature"; + commandIds << "RicDeleteItemFeature"; + commandIds << "Separator"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewViewFeature"; + commandIds << "RicCopyReferencesToClipboardFeature"; + commandIds << "RicPasteEclipseViewsFeature"; + commandIds << "RicDeleteItemFeature"; + commandIds << "Separator"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicPasteEclipseCasesFeature"; + commandIds << "RicNewStatisticsCaseFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewViewFeature"; + commandIds << "RicComputeStatisticsFeature"; + commandIds << "RicCloseCaseFeature"; + commandIds << "RicExecuteScriptForCasesFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicCopyReferencesToClipboardFeature"; + + commandIds << "RicPasteEclipseCasesFeature"; + commandIds << "RicPasteEclipseViewsFeature"; + + commandIds << "RicCloseCaseFeature"; + commandIds << "RicNewViewFeature"; + commandIds << "RicEclipseCaseNewGroupFeature"; + commandIds << "RicExecuteScriptForCasesFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicPasteGeoMechViewsFeature"; + commandIds << "RicNewViewFeature"; + commandIds << "Separator"; + + commandIds << "RicCloseCaseFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicEclipseCaseNewGroupFeature"; + commandIds << "RicPasteEclipseCasesFeature"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicSaveEclipseResultAsInputPropertyFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicAddEclipseInputPropertyFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicDeleteItemFeature"; + commandIds << "RicSaveEclipseInputPropertyFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicRangeFilterNewFeature"; + commandIds << "RicRangeFilterNewSliceIFeature"; + commandIds << "RicRangeFilterNewSliceJFeature"; + commandIds << "RicRangeFilterNewSliceKFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicRangeFilterInsertFeature"; + commandIds << "RicRangeFilterNewSliceIFeature"; + commandIds << "RicRangeFilterNewSliceJFeature"; + commandIds << "RicRangeFilterNewSliceKFeature"; + commandIds << "Separator"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicEclipsePropertyFilterNewFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicEclipsePropertyFilterInsertFeature"; + commandIds << "Separator"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicGeoMechPropertyFilterNewFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicGeoMechPropertyFilterInsertFeature"; + commandIds << "Separator"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicWellPathsDeleteAllFeature"; + commandIds << "RicWellPathsImportFileFeature"; + commandIds << "RicWellPathsImportSsihubFeature"; + commandIds << "RicWellLogsImportFileFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewWellLogFileCurveFeature"; + commandIds << "RicNewWellLogCurveExtractionFeature"; + commandIds << "RicWellPathDeleteFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicEditScriptFeature"; + commandIds << "RicNewScriptFeature"; + commandIds << "Separator"; + commandIds << "RicExecuteScriptFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicAddScriptPathFeature"; + commandIds << "RicDeleteScriptPathFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicShowAllLinkedViewsFeature"; + commandIds << "Separator"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicShowAllLinkedViewsFeature"; + commandIds << "Separator"; + commandIds << "RicDeleteAllLinkedViewsFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewWellLogPlotFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewWellLogPlotTrackFeature"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewWellLogCurveExtractionFeature"; + commandIds << "RicNewWellLogFileCurveFeature"; + commandIds << "RicDeleteWellLogPlotTrackFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicExportToLasFileFeature"; + commandIds << "RicDeleteItemFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicAddWellLogToPlotFeature"; + } + + if (dynamic_cast(uiItem)) + { + commandIds << "RicLinkVisibleViewsFeature"; + commandIds << "RicLinkViewFeature"; + commandIds << "RicUnLinkViewFeature"; + commandIds << "RicShowLinkOptionsFeature"; + commandIds << "RicSetMasterViewFeature"; + } + } + + if (RicToggleItemsFeatureImpl::isToggleCommandsAvailable()) + { + commandIds << "Separator"; + commandIds << "RicToggleItemsOnFeature"; + commandIds << "RicToggleItemsOffFeature"; + commandIds << "RicToggleItemsFeature"; + } + + return commandIds; +} diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h new file mode 100644 index 0000000000..be9a221762 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +//================================================================================================== +/// +/// +//================================================================================================== +class RimContextCommandBuilder +{ +public: + static QStringList commandsFromSelection(); +}; diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 0d63a23332..e4628d2bb1 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -20,47 +20,42 @@ #include "RimProject.h" - #include "RiaApplication.h" #include "RiaVersionInfo.h" #include "RigCaseData.h" -#include "RiaApplication.h" #include "RimCalcScript.h" +#include "RimCase.h" #include "RimCaseCollection.h" #include "RimCommandObject.h" +#include "RimContextCommandBuilder.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" -#include "RimEclipseInputProperty.h" -#include "RimEclipseInputPropertyCollection.h" -#include "RimEclipseStatisticsCase.h" -#include "RimEclipseStatisticsCaseCollection.h" -#include "RimEclipseView.h" #include "RimGeoMechCase.h" #include "RimGeoMechModels.h" #include "RimIdenticalGridCaseGroup.h" -#include "RimViewController.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" #include "RimScriptCollection.h" +#include "RimView.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" -#include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" -#include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPathImport.h" #include "RiuMainWindow.h" -#include "ToggleCommands/RicToggleItemsFeatureImpl.h" #include "OctaveScriptCommands/RicExecuteScriptForCasesFeature.h" #include "cafCmdFeature.h" +#include "cafCmdFeatureManager.h" #include "cafPdmUiTreeOrdering.h" #include +#include + CAF_PDM_SOURCE_INIT(RimProject, "ResInsightProject"); //-------------------------------------------------------------------------------------------------- @@ -606,247 +601,12 @@ void RimProject::computeUtmAreaOfInterest() } } - - - - - - -#include "cafCmdFeatureManager.h" -#include "cafSelectionManager.h" - -#include "RimCellRangeFilterCollection.h" -#include "RimCellRangeFilter.h" -#include "RimEclipsePropertyFilterCollection.h" -#include "RimEclipsePropertyFilter.h" -#include "RimGeoMechPropertyFilterCollection.h" -#include "RimGeoMechPropertyFilter.h" -#include "RimGeoMechView.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseFaultColors.h" -#include "RimWellLogPlot.h" -#include "RimWellLogTrack.h" -#include "RimWellLogCurve.h" -#include "RimWellLogFileChannel.h" -#include - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimProject::actionsBasedOnSelection(QMenu& contextMenu) { - QStringList commandIds; - - std::vector uiItems; - caf::SelectionManager::instance()->selectedItems(uiItems); - - if (uiItems.size() == 0) - { - commandIds << "RicNewWellLogPlotFeature"; - } - else if (uiItems.size() > 1) - { - caf::PdmUiItem* uiItem = uiItems[0]; - if (dynamic_cast(uiItem)) - { - commandIds << "RicAddWellLogToPlotFeature"; - } - } - else if (uiItems.size() == 1) - { - caf::PdmUiItem* uiItem = uiItems[0]; - CVF_ASSERT(uiItem); - - if (dynamic_cast(uiItem)) - { - commandIds << "RicImportEclipseCaseFeature"; - commandIds << "RicImportInputEclipseCaseFeature"; - commandIds << "RicCreateGridCaseGroupFeature"; - commandIds << "RicEclipseCaseNewGroupFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewViewFeature"; - commandIds << "RicCopyReferencesToClipboardFeature"; - commandIds << "RicPasteGeoMechViewsFeature"; - commandIds << "RicDeleteItemFeature"; - commandIds << "Separator"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewViewFeature"; - commandIds << "RicCopyReferencesToClipboardFeature"; - commandIds << "RicPasteEclipseViewsFeature"; - commandIds << "RicDeleteItemFeature"; - commandIds << "Separator"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicPasteEclipseCasesFeature"; - commandIds << "RicNewStatisticsCaseFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewViewFeature"; - commandIds << "RicComputeStatisticsFeature"; - commandIds << "RicCloseCaseFeature"; - commandIds << "RicExecuteScriptForCasesFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicCopyReferencesToClipboardFeature"; - - commandIds << "RicPasteEclipseCasesFeature"; - commandIds << "RicPasteEclipseViewsFeature"; - - commandIds << "RicCloseCaseFeature"; - commandIds << "RicNewViewFeature"; - commandIds << "RicEclipseCaseNewGroupFeature"; - commandIds << "RicExecuteScriptForCasesFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicPasteGeoMechViewsFeature"; - commandIds << "RicNewViewFeature"; - commandIds << "Separator"; - - commandIds << "RicCloseCaseFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicEclipseCaseNewGroupFeature"; - commandIds << "RicPasteEclipseCasesFeature"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicSaveEclipseResultAsInputPropertyFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicAddEclipseInputPropertyFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicDeleteItemFeature"; - commandIds << "RicSaveEclipseInputPropertyFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicRangeFilterNewFeature"; - commandIds << "RicRangeFilterNewSliceIFeature"; - commandIds << "RicRangeFilterNewSliceJFeature"; - commandIds << "RicRangeFilterNewSliceKFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicRangeFilterInsertFeature"; - commandIds << "RicRangeFilterNewSliceIFeature"; - commandIds << "RicRangeFilterNewSliceJFeature"; - commandIds << "RicRangeFilterNewSliceKFeature"; - commandIds << "Separator"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicEclipsePropertyFilterNewFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicEclipsePropertyFilterInsertFeature"; - commandIds << "Separator"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicGeoMechPropertyFilterNewFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicGeoMechPropertyFilterInsertFeature"; - commandIds << "Separator"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicWellPathsDeleteAllFeature"; - commandIds << "RicWellPathsImportFileFeature"; - commandIds << "RicWellPathsImportSsihubFeature"; - commandIds << "RicWellLogsImportFileFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewWellLogFileCurveFeature"; - commandIds << "RicNewWellLogCurveExtractionFeature"; - commandIds << "RicWellPathDeleteFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicEditScriptFeature"; - commandIds << "RicNewScriptFeature"; - commandIds << "Separator"; - commandIds << "RicExecuteScriptFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicAddScriptPathFeature"; - commandIds << "RicDeleteScriptPathFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicShowAllLinkedViewsFeature"; - commandIds << "Separator"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicShowAllLinkedViewsFeature"; - commandIds << "Separator"; - commandIds << "RicDeleteAllLinkedViewsFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewWellLogPlotFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewWellLogPlotTrackFeature"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicNewWellLogCurveExtractionFeature"; - commandIds << "RicNewWellLogFileCurveFeature"; - commandIds << "RicDeleteWellLogPlotTrackFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicExportToLasFileFeature"; - commandIds << "RicDeleteItemFeature"; - } - else if (dynamic_cast(uiItem)) - { - commandIds << "RicAddWellLogToPlotFeature"; - } - - if (dynamic_cast(uiItem)) - { - commandIds << "RicLinkVisibleViewsFeature"; - commandIds << "RicLinkViewFeature"; - commandIds << "RicUnLinkViewFeature"; - commandIds << "RicShowLinkOptionsFeature"; - commandIds << "RicSetMasterViewFeature"; - } - } - - if (RicToggleItemsFeatureImpl::isToggleCommandsAvailable()) - { - commandIds << "Separator"; - commandIds << "RicToggleItemsOnFeature"; - commandIds << "RicToggleItemsOffFeature"; - commandIds << "RicToggleItemsFeature"; - } + QStringList commandIds = RimContextCommandBuilder::commandsFromSelection(); caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); for (int i = 0; i < commandIds.size(); i++) From f20dca0e782e053d58d182fc35e1dbf2049006cf Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 10:06:42 +0100 Subject: [PATCH 075/290] (#657) Created append cross section feature --- ApplicationCode/CMakeLists.txt | 1 + .../CMakeLists_files.cmake | 23 ++++ .../RicAppendCrossSectionFeature.cpp | 111 ++++++++++++++++++ .../RicAppendCrossSectionFeature.h | 62 ++++++++++ .../RimContextCommandBuilder.cpp | 11 ++ .../ProjectDataModel/RimCrossSection.cpp | 33 ++++-- .../ProjectDataModel/RimCrossSection.h | 6 +- 7 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.h diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 1e91d60ed5..86117aa398 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -141,6 +141,7 @@ list( APPEND REFERENCED_CMAKE_FILES Commands/ViewLink/CMakeLists_files.cmake Commands/WellLogCommands/CMakeLists_files.cmake Commands/WellPathCommands/CMakeLists_files.cmake + Commands/CrossSectionCommands/CMakeLists_files.cmake ) # Include source file lists from *.cmake files diff --git a/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake new file mode 100644 index 0000000000..cacef2158e --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake @@ -0,0 +1,23 @@ + +# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly +if (${CMAKE_VERSION} VERSION_GREATER "2.8.2") + set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/) +endif() + +set (SOURCE_GROUP_HEADER_FILES +${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "CommandFeature\\CrossSection" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake ) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp new file mode 100644 index 0000000000..77c6b0a448 --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp @@ -0,0 +1,111 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicAppendCrossSectionFeature.h" + +#include "RimCrossSection.h" +#include "RimCrossSectionCollection.h" + +#include "RiuMainWindow.h" + +#include "cafCmdExecCommandManager.h" +#include "cafSelectionManager.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT(RicAppendCrossSectionFeature, "RicAppendCrossSectionFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicAppendCrossSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAppendCrossSectionFeature::onActionTriggered(bool isChecked) +{ + std::vector collection; + caf::SelectionManager::instance()->objectsByType(&collection); + + CVF_ASSERT(collection.size() == 1); + + RicAppendCrossSectionFeatureCmd* cmd = new RicAppendCrossSectionFeatureCmd(collection[0]); + caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAppendCrossSectionFeature::setupActionLook(QAction* actionToSetup) +{ +// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setText("New Cross Section"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicAppendCrossSectionFeatureCmd::RicAppendCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection) + : CmdExecuteCommand(NULL), + m_crossSectionCollection(crossSectionCollection) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicAppendCrossSectionFeatureCmd::~RicAppendCrossSectionFeatureCmd() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicAppendCrossSectionFeatureCmd::name() +{ + return "New Cross Section"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAppendCrossSectionFeatureCmd::redo() +{ + CVF_ASSERT(m_crossSectionCollection); + + RimCrossSection* crossSection = new RimCrossSection(); + crossSection->name = QString("Cross Section (%1)").arg(m_crossSectionCollection->crossSections.size() + 1); + m_crossSectionCollection->crossSections.push_back(crossSection); + + m_crossSectionCollection->updateConnectedEditors(); + RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAppendCrossSectionFeatureCmd::undo() +{ +} diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.h new file mode 100644 index 0000000000..5d65cb6715 --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" +#include "cafCmdExecuteCommand.h" +#include "cafPdmPointer.h" + +class RimCrossSectionCollection; + + +//================================================================================================== +/// +//================================================================================================== +class RicAppendCrossSectionFeatureCmd : public caf::CmdExecuteCommand +{ +public: + RicAppendCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection); + virtual ~RicAppendCrossSectionFeatureCmd(); + + virtual QString name(); + virtual void redo(); + virtual void undo(); + +private: + caf::PdmPointer m_crossSectionCollection; +}; + + + +//================================================================================================== +/// +//================================================================================================== +class RicAppendCrossSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + virtual bool isCommandEnabled(); + virtual void onActionTriggered( bool isChecked ); + virtual void setupActionLook( QAction* actionToSetup ); +}; + + diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index 68ff16993d..4ac94d6ceb 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -23,6 +23,8 @@ #include "RimCaseCollection.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSection.h" +#include "RimCrossSectionCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseCellColors.h" @@ -254,6 +256,15 @@ QStringList RimContextCommandBuilder::commandsFromSelection() { commandIds << "RicAddWellLogToPlotFeature"; } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicAppendCrossSectionFeature"; + } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicAppendCrossSectionFeature"; + commandIds << "RicDeleteItemFeature"; + } if (dynamic_cast(uiItem)) { diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 24e11fbcc6..b34d515aed 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -24,21 +24,20 @@ namespace caf { - template<> - void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() - { - addItem(RimCrossSection::CS_WELL_PATH, "WELL_PATH", "Well Path"); - addItem(RimCrossSection::CS_SIMULATION_WELL, "SIMULATION_WELL", "Simulation Well"); - addItem(RimCrossSection::CS_USER_DEFINED, "USER_DEFINED", "User defined"); - setDefault(RimCrossSection::CS_WELL_PATH); - } +template<> +void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() +{ + addItem(RimCrossSection::CS_WELL_PATH, "WELL_PATH", "Well Path"); + addItem(RimCrossSection::CS_SIMULATION_WELL, "SIMULATION_WELL", "Simulation Well"); + addItem(RimCrossSection::CS_USER_DEFINED, "USER_DEFINED", "User defined"); + setDefault(RimCrossSection::CS_WELL_PATH); +} } CAF_PDM_SOURCE_INIT(RimCrossSection, "CrossSection"); - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -101,3 +100,19 @@ QList RimCrossSection::calculateValueOptions(const caf:: */ return options; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimCrossSection::userDescriptionField() +{ + return &name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimCrossSection::objectToggleField() +{ + return &isActive; +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 40144aa18c..f92849db46 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -55,6 +55,9 @@ class RimCrossSection : public caf::PdmObject caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; + virtual caf::PdmFieldHandle* userDescriptionField(); + virtual caf::PdmFieldHandle* objectToggleField(); + protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); // virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); @@ -62,7 +65,6 @@ class RimCrossSection : public caf::PdmObject // virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); - - private: + }; From 13c5dbfbd2691e67cbd01a4b7be62f7fc6d027e8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 11:37:55 +0100 Subject: [PATCH 076/290] [Fwk] Do not show children if object hides children --- .../cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.cpp index 63e692b0ec..8a61cfd718 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.cpp @@ -195,7 +195,7 @@ void PdmUiObjectHandle::expandUiTree(PdmUiTreeOrdering* root, QString uiConfigNa } } } - else if (root->isRepresentingObject()) + else if (root->isRepresentingObject() && !root->object()->uiCapability()->isUiChildrenHidden(uiConfigName)) { uiObj(root->object())->defineUiTreeOrdering(*root, uiConfigName); uiObj(root->object())->addDefaultUiTreeChildren(root); From 77d66f59af2e534b6294cb29da55331e63e6c9c0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 12:16:04 +0100 Subject: [PATCH 077/290] (#657) Added option items for well path and simulation wells --- .../ProjectDataModel/RimCrossSection.cpp | 91 ++++++++++++++++--- .../ProjectDataModel/RimCrossSection.h | 4 +- .../ProjectDataModel/RimEclipseWell.cpp | 1 - .../ProjectDataModel/RimEclipseWell.h | 3 +- .../ProjectDataModel/RimWellPath.cpp | 1 - .../ProjectDataModel/RimWellPath.h | 5 +- 6 files changed, 84 insertions(+), 21 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index b34d515aed..70d76f906f 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -19,6 +19,14 @@ #include "RimCrossSection.h" +#include "RiaApplication.h" + +#include "RimEclipseView.h" +#include "RimEclipseWell.h" +#include "RimEclipseWellCollection.h" +#include "RimOilField.h" +#include "RimProject.h" +#include "RimWellPath.h" @@ -49,7 +57,11 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&crossSectionType, "CrossSectionType", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); + CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); + CAF_PDM_InitFieldNoDefault(&crossSectionType, "CrossSectionType", "Type", "", "", ""); + + uiCapability()->setUiChildrenHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -65,7 +77,23 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, //-------------------------------------------------------------------------------------------------- void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { + uiOrdering.add(&name); + uiOrdering.add(&crossSectionType); + + if (crossSectionType == CS_WELL_PATH) + { + uiOrdering.add(&wellPath); + } + else if (crossSectionType == CS_SIMULATION_WELL) + { + uiOrdering.add(&simulationWell); + } + else + { + } + + uiOrdering.setForgetRemainingFields(true); } //-------------------------------------------------------------------------------------------------- @@ -75,29 +103,46 @@ QList RimCrossSection::calculateValueOptions(const caf:: { QList options; - if (useOptionsOnly) (*useOptionsOnly) = true; + if (fieldNeedingOptions == &wellPath) + { + RimProject* proj = RiaApplication::instance()->project(); + if (proj->activeOilField()->wellPathCollection()) + { + caf::PdmChildArrayField& wellPaths = proj->activeOilField()->wellPathCollection()->wellPaths; + + QIcon wellIcon(":/Well.png"); + for (size_t i = 0; i < wellPaths.size(); i++) + { + options.push_back(caf::PdmOptionItemInfo(wellPaths[i]->name(), QVariant::fromValue(caf::PdmPointer(wellPaths[i])), false, wellIcon)); + } + } -/* - if (&gridIndex == fieldNeedingOptions) + if (options.size() == 0) + { + options.push_front(caf::PdmOptionItemInfo("None", QVariant::fromValue(caf::PdmPointer(NULL)))); + } + } + else if (fieldNeedingOptions == &simulationWell) { - for (int gIdx = 0; gIdx < parentContainer()->gridCount(); ++gIdx) + RimEclipseWellCollection* coll = simulationWellCollection(); + if (coll) { - QString gridName; + caf::PdmChildArrayField& eclWells = coll->wells; - gridName += parentContainer()->gridName(gIdx); - if (gIdx == 0) + QIcon simWellIcon(":/Well.png"); + for (size_t i = 0; i < eclWells.size(); i++) { - if (gridName.isEmpty()) - gridName += "Main Grid"; - else - gridName += " (Main Grid)"; + options.push_back(caf::PdmOptionItemInfo(eclWells[i]->name(), QVariant::fromValue(caf::PdmPointer(eclWells[i])), false, simWellIcon)); } - caf::PdmOptionItemInfo item(gridName, (int)gIdx); - options.push_back(item); + } + + if (options.size() == 0) + { + options.push_front(caf::PdmOptionItemInfo("None", QVariant::fromValue(caf::PdmPointer(NULL)))); } } -*/ + return options; } @@ -116,3 +161,19 @@ caf::PdmFieldHandle* RimCrossSection::objectToggleField() { return &isActive; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseWellCollection* RimCrossSection::simulationWellCollection() +{ + RimEclipseView* eclipseView = NULL; + firstAnchestorOrThisOfType(eclipseView); + + if (eclipseView) + { + return eclipseView->wellCollection; + } + + return NULL; +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index f92849db46..2edba255fb 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -26,6 +26,7 @@ class RimWellPath; class RimEclipseWell; +class RimEclipseWellCollection; //================================================================================================== @@ -65,6 +66,7 @@ class RimCrossSection : public caf::PdmObject // virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); -private: +private: + RimEclipseWellCollection* simulationWellCollection(); }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp index f48113e4e4..7fbad606e0 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp @@ -20,7 +20,6 @@ #include "RimEclipseWell.h" -#include "RigSingleWellResultsData.h" #include "RimEclipseView.h" #include "RimEclipseWellCollection.h" diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWell.h b/ApplicationCode/ProjectDataModel/RimEclipseWell.h index fc8ec77433..e1b938a7f9 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWell.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseWell.h @@ -20,6 +20,8 @@ #pragma once +#include "RigSingleWellResultsData.h" + #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmPointer.h" @@ -30,7 +32,6 @@ // Include to make Pdm work for cvf::Color #include "cafPdmFieldCvfColor.h" -class RigSingleWellResultsData; class RimEclipseView; //================================================================================================== diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.cpp b/ApplicationCode/ProjectDataModel/RimWellPath.cpp index b50b5c535f..b813e3a6a8 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPath.cpp @@ -24,7 +24,6 @@ #include "RimProject.h" #include "RimTools.h" #include "RimWellLogFile.h" -#include "RimWellPathCollection.h" #include "RimProject.h" #include "RimMainPlotCollection.h" #include "RimWellLogPlotCollection.h" diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.h b/ApplicationCode/ProjectDataModel/RimWellPath.h index 940b74edb7..18e814d095 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.h +++ b/ApplicationCode/ProjectDataModel/RimWellPath.h @@ -20,6 +20,9 @@ #pragma once +#include "RigWellPath.h" +#include "RimWellPathCollection.h" + #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmPointer.h" @@ -29,11 +32,9 @@ // Include to make Pdm work for cvf::Color #include "cafPdmFieldCvfColor.h" -#include "RigWellPath.h" class RimProject; class RivWellPathPartMgr; -class RimWellPathCollection; class RimWellLogFile; //================================================================================================== From 773ac384f027fe07dc18551c779dd49a6be2e90a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 14:33:55 +0100 Subject: [PATCH 078/290] Added synthetic well paths for 10k case --- TestModels/TEST10K_FLT_LGR_NNC/wellpath_a.dev | 43 +++++++++++++++++++ TestModels/TEST10K_FLT_LGR_NNC/wellpath_b.dev | 39 +++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 TestModels/TEST10K_FLT_LGR_NNC/wellpath_a.dev create mode 100644 TestModels/TEST10K_FLT_LGR_NNC/wellpath_b.dev diff --git a/TestModels/TEST10K_FLT_LGR_NNC/wellpath_a.dev b/TestModels/TEST10K_FLT_LGR_NNC/wellpath_a.dev new file mode 100644 index 0000000000..788d37e879 --- /dev/null +++ b/TestModels/TEST10K_FLT_LGR_NNC/wellpath_a.dev @@ -0,0 +1,43 @@ +name Well Path A +3736.27 4630.61 4133.5 0 +3896.64 4657.71 4140.22 162.7823863 +3944.64 4665.47 4143.36 211.5068894 +3991.44 4647.9 4149.89 261.9210323 +4038.31 4631.15 4151.36 311.7158141 +4119.37 4708.27 4156.74 423.7299311 +4166.78 4691.07 4157.18 474.1654513 +4214.19 4673.79 4157.61 524.6282237 +4261.43 4656.92 4156.54 574.8015174 +4281.36 4709.82 4158.3 631.3586788 +4343.99 4733.28 4158.8 698.2402046 +4391.31 4716.07 4157.77 748.6031612 +4408.91 4762.88 4158.95 798.6264408 +4426.81 4809.83 4159.42 848.8751562 +4474.03 4792.42 4158.52 899.2104967 +4521.06 4775.57 4156.45 949.2107797 +4538.81 4821.2 4159.88 998.2915733 +4556.6 4868.06 4160.31 1048.416703 +4603.63 4850.92 4158.51 1098.50503 +4650.51 4833.27 4158.24 1148.598241 +4667.96 4880.09 4159.07 1198.571272 +4732.41 4909.84 4157.61 1269.571248 +4796.67 4939.47 4157.07 1340.335477 +4831.82 5033.41 4156.41 1440.638426 +4895.8 5062.99 4155.63 1511.129739 +4959.99 5092.79 4154.32 1581.911885 +5024.16 5122.41 4152.42 1652.613677 +5088.15 5152.17 4150.72 1723.20594 +5105.97 5198.67 4148.41 1773.057104 +5123.89 5245.04 4146.11 1822.822486 +5141.45 5291.66 4146.9 1872.646196 +5187.56 5274.3 4140.91 1922.278664 +5250.83 5304.18 4142.42 1992.265715 +5268.57 5350.83 4143.51 2042.186835 +5286.65 5396.77 4140.33 2091.658872 +5304.79 5443.12 4139.68 2141.436423 +5323.22 5488.97 4136.61 2190.947152 +5341.54 5535.44 4136.08 2240.900772 +5360.2 5581.51 4133.77 2290.659959 +5378.1 5628.61 4134.51 2341.052097 +5396.05 5675.72 4135.26 2391.471509 +5422.32 5747.19 4137.33 2467.644724 diff --git a/TestModels/TEST10K_FLT_LGR_NNC/wellpath_b.dev b/TestModels/TEST10K_FLT_LGR_NNC/wellpath_b.dev new file mode 100644 index 0000000000..964152f162 --- /dev/null +++ b/TestModels/TEST10K_FLT_LGR_NNC/wellpath_b.dev @@ -0,0 +1,39 @@ +name Well Path B +3736.27 4630.61 4133.5 0 +3761.11 4713.48 4142.55 86.984855 +3765.32 4727.62 4145.32 101.9960708 +3780.64 4774.86 4160.16 153.8279683 +3797.32 4822.97 4161.6 204.7678162 +3814.06 4870.14 4168.26 255.2613019 +3785.62 4934.33 4171.96 325.5669183 +3756.59 4998.21 4177.76 395.9731347 +3773.6 5045.37 4180.48 446.1807446 +3758.2 5153.07 4197.74 556.3368049 +3727.14 5216.26 4202.87 626.9343728 +3743.74 5262.95 4203.96 676.4995239 +3757.75 5307.36 4210.53 723.5281651 +3791.42 5401.23 4210.36 823.2541633 +3760.94 5464.85 4212.73 893.838522 +3716.37 5483.85 4210.82 942.3270052 +3735.17 5532.24 4208.22 994.305771 +3752.59 5579.57 4207.89 1044.74082 +3758.62 5584.34 4198.6 1056.799755 +3776.88 5633.04 4197.74 1108.817609 +3795.38 5680.6 4195.5 1159.898146 +3815.15 5729.83 4191.81 1213.077671 +3833.62 5778 4189.73 1264.709214 +3853.88 5827.61 4184.96 1318.508587 +3872.13 5875.57 4182.78 1369.869823 +3892.19 5924.97 4177.75 1423.424136 +3956.55 5955.67 4173.53 1494.855978 +4020.59 5985.54 4170.55 1565.582344 +4055.06 6079.67 4167.88 1665.86079 +4072.67 6126.92 4165.88 1716.325378 +4090.2 6174.1 4163.89 1766.696137 +4107.25 6220.81 4163.04 1816.427909 +4124.23 6267.42 4162.21 1866.041429 +4140.81 6313.68 4162.82 1915.186684 +4158.44 6360.5 4160.8 1965.256732 +4175.11 6406.65 4161.58 2014.331367 +4192.77 6453.18 4159.69 2064.135871 +4210.37 6499.46 4158.28 2113.669561 From 6ca980385c06b6cd83506da060502128e76de3b0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 15:09:50 +0100 Subject: [PATCH 079/290] (#657) Created command feature for adding cross section from simulation well --- .../CMakeLists_files.cmake | 4 + .../RicNewSimWellCrossSectionFeature.cpp | 123 +++++++++++++++++ .../RicNewSimWellCrossSectionFeature.h | 64 +++++++++ .../RicNewWellPathCrossSectionFeature.cpp | 124 ++++++++++++++++++ .../RicNewWellPathCrossSectionFeature.h | 64 +++++++++ .../RimContextCommandBuilder.cpp | 5 + .../ProjectDataModel/RimEclipseView.cpp | 2 +- .../ProjectDataModel/RimGeoMechView.cpp | 2 +- ApplicationCode/ProjectDataModel/RimView.cpp | 6 +- ApplicationCode/ProjectDataModel/RimView.h | 3 +- 10 files changed, 390 insertions(+), 7 deletions(-) create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h diff --git a/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake index cacef2158e..8bf1591780 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake @@ -6,10 +6,14 @@ endif() set (SOURCE_GROUP_HEADER_FILES ${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.h +${CEE_CURRENT_LIST_DIR}RicNewSimWellCrossSectionFeature.h +${CEE_CURRENT_LIST_DIR}RicNewWellPathCrossSectionFeature.h ) set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.cpp +${CEE_CURRENT_LIST_DIR}RicNewSimWellCrossSectionFeature.cpp +${CEE_CURRENT_LIST_DIR}RicNewWellPathCrossSectionFeature.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp new file mode 100644 index 0000000000..8d592eaca5 --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewSimWellCrossSectionFeature.h" + +#include "RimCrossSection.h" +#include "RimCrossSectionCollection.h" + +#include "RiuMainWindow.h" + +#include "cafCmdExecCommandManager.h" +#include "cafSelectionManager.h" + +#include "cvfAssert.h" + +#include +#include "RimEclipseView.h" +#include "RimEclipseWell.h" + +CAF_CMD_SOURCE_INIT(RicNewSimWellCrossSectionFeature, "RicNewSimWellCrossSectionFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewSimWellCrossSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewSimWellCrossSectionFeature::onActionTriggered(bool isChecked) +{ + std::vector collection; + caf::SelectionManager::instance()->objectsByType(&collection); + CVF_ASSERT(collection.size() == 1); + + RimEclipseWell* eclWell = collection[0]; + + RimEclipseView* eclView = NULL; + eclWell->firstAnchestorOrThisOfType(eclView); + CVF_ASSERT(eclView); + + RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(eclView->crossSectionCollection, eclWell); + caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewSimWellCrossSectionFeature::setupActionLook(QAction* actionToSetup) +{ +// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setText("New Cross Section"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewWellPathCrossSectionFeatureCmd::RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell) + : CmdExecuteCommand(NULL), + m_crossSectionCollection(crossSectionCollection), + m_wellPath(simWell) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewWellPathCrossSectionFeatureCmd::~RicNewWellPathCrossSectionFeatureCmd() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicNewWellPathCrossSectionFeatureCmd::name() +{ + return "Create Cross Section From Well"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeatureCmd::redo() +{ + CVF_ASSERT(m_crossSectionCollection); + CVF_ASSERT(m_wellPath); + + RimCrossSection* crossSection = new RimCrossSection(); + crossSection->name = m_wellPath->name; + crossSection->crossSectionType = RimCrossSection::CS_SIMULATION_WELL; + crossSection->simulationWell = m_wellPath; + + m_crossSectionCollection->crossSections.push_back(crossSection); + + m_crossSectionCollection->updateConnectedEditors(); + RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeatureCmd::undo() +{ +} diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h new file mode 100644 index 0000000000..10d438053e --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" +#include "cafCmdExecuteCommand.h" +#include "cafPdmPointer.h" + +class RimCrossSectionCollection; +class RimEclipseWell; + + +//================================================================================================== +/// +//================================================================================================== +class RicNewWellPathCrossSectionFeatureCmd : public caf::CmdExecuteCommand +{ +public: + RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell); + virtual ~RicNewWellPathCrossSectionFeatureCmd(); + + virtual QString name(); + virtual void redo(); + virtual void undo(); + +private: + caf::PdmPointer m_crossSectionCollection; + caf::PdmPointer m_wellPath; +}; + + + +//================================================================================================== +/// +//================================================================================================== +class RicNewSimWellCrossSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + virtual bool isCommandEnabled(); + virtual void onActionTriggered( bool isChecked ); + virtual void setupActionLook( QAction* actionToSetup ); +}; + + diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp new file mode 100644 index 0000000000..c09a678827 --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -0,0 +1,124 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewWellPathCrossSectionFeature.h" + +#include "RimCrossSection.h" +#include "RimCrossSectionCollection.h" +#include "RimWellPath.h" + +#include "RiuMainWindow.h" + +#include "cafCmdExecCommandManager.h" +#include "cafSelectionManager.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT(RicNewWellPathCrossSectionFeature, "RicNewWellPathCrossSectionFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewWellPathCrossSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) +{ +/* + std::vector collection; + caf::SelectionManager::instance()->objectsByType(&collection); + CVF_ASSERT(collection.size() == 1); + + RimEclipseWell* eclWell = collection[0]; + + RimEclipseView* eclView = NULL; + eclWell->firstAnchestorOrThisOfType(eclView); + CVF_ASSERT(eclView); + + RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(eclView->crossSectionCollection, eclWell); + caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); +*/ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeature::setupActionLook(QAction* actionToSetup) +{ +// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setText("New Cross Section"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewWellPathCrossSectionFeatureCmd::RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimWellPath* wellPath) + : CmdExecuteCommand(NULL), + m_crossSectionCollection(crossSectionCollection), + m_wellPath(wellPath) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewWellPathCrossSectionFeatureCmd::~RicNewWellPathCrossSectionFeatureCmd() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicNewWellPathCrossSectionFeatureCmd::name() +{ + return "Create Cross Section From Well Path"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeatureCmd::redo() +{ + CVF_ASSERT(m_crossSectionCollection); + CVF_ASSERT(m_wellPath); + + RimCrossSection* crossSection = new RimCrossSection(); + crossSection->name = m_wellPath->name; + crossSection->crossSectionType = RimCrossSection::CS_WELL_PATH; + crossSection->wellPath = m_wellPath; + + m_crossSectionCollection->crossSections.push_back(crossSection); + + m_crossSectionCollection->updateConnectedEditors(); + RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeatureCmd::undo() +{ +} diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h new file mode 100644 index 0000000000..905bd07d9f --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" +#include "cafCmdExecuteCommand.h" +#include "cafPdmPointer.h" + +class RimCrossSectionCollection; +class RimWellPath; + + +//================================================================================================== +/// +//================================================================================================== +class RicNewWellPathCrossSectionFeatureCmd : public caf::CmdExecuteCommand +{ +public: + RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimWellPath* wellPath); + virtual ~RicNewWellPathCrossSectionFeatureCmd(); + + virtual QString name(); + virtual void redo(); + virtual void undo(); + +private: + caf::PdmPointer m_crossSectionCollection; + caf::PdmPointer m_wellPath; +}; + + + +//================================================================================================== +/// +//================================================================================================== +class RicNewWellPathCrossSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + virtual bool isCommandEnabled(); + virtual void onActionTriggered( bool isChecked ); + virtual void setupActionLook( QAction* actionToSetup ); +}; + + diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index 4ac94d6ceb..60f6f5c3b2 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -34,6 +34,7 @@ #include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseStatisticsCase.h" #include "RimEclipseView.h" +#include "RimEclipseWell.h" #include "RimGeoMechCase.h" #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechPropertyFilterCollection.h" @@ -265,6 +266,10 @@ QStringList RimContextCommandBuilder::commandsFromSelection() commandIds << "RicAppendCrossSectionFeature"; commandIds << "RicDeleteItemFeature"; } + else if (dynamic_cast(uiItem)) + { + commandIds << "RicNewSimWellCrossSectionFeature"; + } if (dynamic_cast(uiItem)) { diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index df0ddc365a..355970f3f3 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1350,7 +1350,7 @@ void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); - uiTreeOrdering.add(m_crossSectionCollection()); + uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 716031add0..4fd8e0c4e7 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -637,7 +637,7 @@ void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); - uiTreeOrdering.add(m_crossSectionCollection()); + uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 4fca175e19..608515a850 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -117,9 +117,9 @@ RimView::RimView(void) m_overrideRangeFilterCollection.xmlCapability()->setIOWritable(false); m_overrideRangeFilterCollection.xmlCapability()->setIOReadable(false); - CAF_PDM_InitFieldNoDefault(&m_crossSectionCollection, "CrossSections", "Cross Sections", "", "", ""); - m_crossSectionCollection.uiCapability()->setUiHidden(true); - m_crossSectionCollection = new RimCrossSectionCollection(); + CAF_PDM_InitFieldNoDefault(&crossSectionCollection, "CrossSections", "Cross Sections", "", "", ""); + crossSectionCollection.uiCapability()->setUiHidden(true); + crossSectionCollection = new RimCrossSectionCollection(); m_previousGridModeMeshLinesWasFaults = false; } diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index cc4d2bb8ed..03d2e2aa1b 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -90,6 +90,7 @@ class RimView : public caf::PdmObject caf::PdmField< std::vector > windowGeometry; + caf::PdmChildField crossSectionCollection; // Draw style @@ -192,8 +193,6 @@ class RimView : public caf::PdmObject caf::PdmChildField m_rangeFilterCollection; caf::PdmChildField m_overrideRangeFilterCollection; - caf::PdmChildField m_crossSectionCollection; - // Overridden PDM methods: virtual void setupBeforeSave(); From 91e159810ccb0a172b863eeb0bc6527325a77bf6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 15:55:05 +0100 Subject: [PATCH 080/290] (#657) Added poly line access function and cross section direction --- .../RicNewSimWellCrossSectionFeature.cpp | 18 +++---- .../RicNewSimWellCrossSectionFeature.h | 6 +-- .../RicNewWellPathCrossSectionFeature.cpp | 2 +- .../ProjectDataModel/RimCrossSection.cpp | 54 +++++++++++++++---- .../ProjectDataModel/RimCrossSection.h | 19 +++++-- 5 files changed, 73 insertions(+), 26 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp index 8d592eaca5..f5d89e6154 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp @@ -21,6 +21,8 @@ #include "RimCrossSection.h" #include "RimCrossSectionCollection.h" +#include "RimEclipseView.h" +#include "RimEclipseWell.h" #include "RiuMainWindow.h" @@ -30,8 +32,6 @@ #include "cvfAssert.h" #include -#include "RimEclipseView.h" -#include "RimEclipseWell.h" CAF_CMD_SOURCE_INIT(RicNewSimWellCrossSectionFeature, "RicNewSimWellCrossSectionFeature"); @@ -58,7 +58,7 @@ void RicNewSimWellCrossSectionFeature::onActionTriggered(bool isChecked) eclWell->firstAnchestorOrThisOfType(eclView); CVF_ASSERT(eclView); - RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(eclView->crossSectionCollection, eclWell); + RicNewSimWellCrossSectionCmd* cmd = new RicNewSimWellCrossSectionCmd(eclView->crossSectionCollection, eclWell); caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); } @@ -74,7 +74,7 @@ void RicNewSimWellCrossSectionFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicNewWellPathCrossSectionFeatureCmd::RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell) +RicNewSimWellCrossSectionCmd::RicNewSimWellCrossSectionCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell) : CmdExecuteCommand(NULL), m_crossSectionCollection(crossSectionCollection), m_wellPath(simWell) @@ -84,14 +84,14 @@ RicNewWellPathCrossSectionFeatureCmd::RicNewWellPathCrossSectionFeatureCmd(RimCr //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicNewWellPathCrossSectionFeatureCmd::~RicNewWellPathCrossSectionFeatureCmd() +RicNewSimWellCrossSectionCmd::~RicNewSimWellCrossSectionCmd() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RicNewWellPathCrossSectionFeatureCmd::name() +QString RicNewSimWellCrossSectionCmd::name() { return "Create Cross Section From Well"; } @@ -99,14 +99,14 @@ QString RicNewWellPathCrossSectionFeatureCmd::name() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicNewWellPathCrossSectionFeatureCmd::redo() +void RicNewSimWellCrossSectionCmd::redo() { CVF_ASSERT(m_crossSectionCollection); CVF_ASSERT(m_wellPath); RimCrossSection* crossSection = new RimCrossSection(); crossSection->name = m_wellPath->name; - crossSection->crossSectionType = RimCrossSection::CS_SIMULATION_WELL; + crossSection->type = RimCrossSection::CS_SIMULATION_WELL; crossSection->simulationWell = m_wellPath; m_crossSectionCollection->crossSections.push_back(crossSection); @@ -118,6 +118,6 @@ void RicNewWellPathCrossSectionFeatureCmd::redo() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicNewWellPathCrossSectionFeatureCmd::undo() +void RicNewSimWellCrossSectionCmd::undo() { } diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h index 10d438053e..69a9d7cd7f 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.h @@ -30,11 +30,11 @@ class RimEclipseWell; //================================================================================================== /// //================================================================================================== -class RicNewWellPathCrossSectionFeatureCmd : public caf::CmdExecuteCommand +class RicNewSimWellCrossSectionCmd : public caf::CmdExecuteCommand { public: - RicNewWellPathCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell); - virtual ~RicNewWellPathCrossSectionFeatureCmd(); + RicNewSimWellCrossSectionCmd(RimCrossSectionCollection* crossSectionCollection, RimEclipseWell* simWell); + virtual ~RicNewSimWellCrossSectionCmd(); virtual QString name(); virtual void redo(); diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index c09a678827..58e9fc6cb6 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -107,7 +107,7 @@ void RicNewWellPathCrossSectionFeatureCmd::redo() RimCrossSection* crossSection = new RimCrossSection(); crossSection->name = m_wellPath->name; - crossSection->crossSectionType = RimCrossSection::CS_WELL_PATH; + crossSection->type = RimCrossSection::CS_WELL_PATH; crossSection->wellPath = m_wellPath; m_crossSectionCollection->crossSections.push_back(crossSection); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 70d76f906f..43d84d1324 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -35,12 +35,20 @@ namespace caf { template<> void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() { - addItem(RimCrossSection::CS_WELL_PATH, "WELL_PATH", "Well Path"); - addItem(RimCrossSection::CS_SIMULATION_WELL, "SIMULATION_WELL", "Simulation Well"); - addItem(RimCrossSection::CS_USER_DEFINED, "USER_DEFINED", "User defined"); + addItem(RimCrossSection::CS_WELL_PATH, "CS_WELL_PATH", "Well Path"); + addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); + addItem(RimCrossSection::CS_USER_DEFINED, "CS_USER_DEFINED", "User defined"); setDefault(RimCrossSection::CS_WELL_PATH); } +template<> +void caf::AppEnum< RimCrossSection::CrossSectionDirEnum >::setUp() +{ + addItem(RimCrossSection::CS_VERTICAL, "CS_VERTICAL", "Vertical"); + addItem(RimCrossSection::CS_HORIZONTAL, "CS_HORIZONTAL", "Horizontal"); + setDefault(RimCrossSection::CS_VERTICAL); +} + } @@ -57,9 +65,10 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); - CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); - CAF_PDM_InitFieldNoDefault(&crossSectionType, "CrossSectionType", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); + CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); + CAF_PDM_InitFieldNoDefault(&type, "Type", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); uiCapability()->setUiChildrenHidden(true); } @@ -78,13 +87,14 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&name); - uiOrdering.add(&crossSectionType); + uiOrdering.add(&type); + uiOrdering.add(&direction); - if (crossSectionType == CS_WELL_PATH) + if (type == CS_WELL_PATH) { uiOrdering.add(&wellPath); } - else if (crossSectionType == CS_SIMULATION_WELL) + else if (type == CS_SIMULATION_WELL) { uiOrdering.add(&simulationWell); } @@ -177,3 +187,29 @@ RimEclipseWellCollection* RimCrossSection::simulationWellCollection() return NULL; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector< std::vector > RimCrossSection::polyLines() const +{ + std::vector< std::vector > line; + if (type == CS_WELL_PATH) + { + if (wellPath) + { + line.push_back(wellPath->wellPathGeometry()->m_wellPathPoints); + } + } + else if (type == CS_SIMULATION_WELL) + { + + } + else + { + + } + + return line; +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 2edba255fb..d47d4a5f95 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -24,9 +24,12 @@ #include "cafPdmObject.h" #include "cafPdmPtrField.h" -class RimWellPath; +#include "cvfBase.h" +#include "cvfVector3.h" + class RimEclipseWell; class RimEclipseWellCollection; +class RimWellPath; //================================================================================================== @@ -46,24 +49,32 @@ class RimCrossSection : public caf::PdmObject CS_USER_DEFINED }; + enum CrossSectionDirEnum + { + CS_VERTICAL, + CS_HORIZONTAL + }; + public: RimCrossSection(); caf::PdmField name; caf::PdmField isActive; - caf::PdmField< caf::AppEnum< CrossSectionEnum > > crossSectionType; + + caf::PdmField< caf::AppEnum< CrossSectionEnum > > type; + caf::PdmField< caf::AppEnum< CrossSectionDirEnum > > direction; caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; + std::vector< std::vector > polyLines() const; + virtual caf::PdmFieldHandle* userDescriptionField(); virtual caf::PdmFieldHandle* objectToggleField(); protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); -// virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); -// virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); From dc894928b53fa01accdaf5f5ad06cc44e323290f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 17:55:05 +0100 Subject: [PATCH 081/290] (#657) Added support for creating a cross section from well path context menu in 3D viewer --- .../RicNewWellPathCrossSectionFeature.cpp | 31 +++++++++++++------ .../RicNewWellPathCrossSectionFeature.h | 10 ++++++ .../UserInterface/RiuViewerCommands.cpp | 14 +++++++-- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index 58e9fc6cb6..90764d6501 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -34,6 +34,15 @@ CAF_CMD_SOURCE_INIT(RicNewWellPathCrossSectionFeature, "RicNewWellPathCrossSectionFeature"); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewWellPathCrossSectionFeature::RicNewWellPathCrossSectionFeature() + : m_view(NULL) +{ +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -47,20 +56,16 @@ bool RicNewWellPathCrossSectionFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) { -/* - std::vector collection; + if (!m_view) return; + + std::vector collection; caf::SelectionManager::instance()->objectsByType(&collection); CVF_ASSERT(collection.size() == 1); - RimEclipseWell* eclWell = collection[0]; + RimWellPath* wellPath = collection[0]; - RimEclipseView* eclView = NULL; - eclWell->firstAnchestorOrThisOfType(eclView); - CVF_ASSERT(eclView); - - RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(eclView->crossSectionCollection, eclWell); + RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(m_view->crossSectionCollection, wellPath); caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); -*/ } //-------------------------------------------------------------------------------------------------- @@ -72,6 +77,14 @@ void RicNewWellPathCrossSectionFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setText("New Cross Section"); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewWellPathCrossSectionFeature::setView(RimView* view) +{ + m_view = view; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h index 905bd07d9f..063ab0c9dd 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h @@ -19,6 +19,8 @@ #pragma once +#include "RimView.h" + #include "cafCmdFeature.h" #include "cafCmdExecuteCommand.h" #include "cafPdmPointer.h" @@ -54,11 +56,19 @@ class RicNewWellPathCrossSectionFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; +public: + RicNewWellPathCrossSectionFeature(); + + void setView(RimView* view); + protected: // Overrides virtual bool isCommandEnabled(); virtual void onActionTriggered( bool isChecked ); virtual void setupActionLook( QAction* actionToSetup ); + +private: + caf::PdmPointer m_view; }; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 593a0f7d83..5dff91acd6 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -22,8 +22,10 @@ #include "RicEclipsePropertyFilterNewExec.h" #include "RicGeoMechPropertyFilterNewExec.h" #include "RicRangeFilterNewExec.h" -#include "Commands/WellLogCommands/RicNewWellLogFileCurveFeature.h" -#include "Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.h" + +#include "CrossSectionCommands/RicNewWellPathCrossSectionFeature.h" +#include "WellLogCommands/RicNewWellLogCurveExtractionFeature.h" +#include "WellLogCommands/RicNewWellLogFileCurveFeature.h" #include "RigCaseData.h" #include "RigFemPartCollection.h" @@ -238,6 +240,14 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) { menu.addAction(newExtractionCurveFeature->action()); } + + RicNewWellPathCrossSectionFeature* newWellPathCrossSectionFeature = dynamic_cast(commandManager->getCommandFeature("RicNewWellPathCrossSectionFeature")); + if (newWellPathCrossSectionFeature) + { + newWellPathCrossSectionFeature->setView(m_reservoirView); + + menu.addAction(newWellPathCrossSectionFeature->action()); + } } } } From 69e30dc8bc1620170a089ff66940c295773151ac Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 18 Nov 2015 18:21:22 +0100 Subject: [PATCH 082/290] (#657) Added support for creation of cross section from simulation well context menu --- .../ModelVisualization/CMakeLists_files.cmake | 3 +- .../RivWellPipeSourceInfo.cpp | 39 ++++++++++++++++++ .../RivWellPipeSourceInfo.h | 37 +++++++++++++++++ .../RivWellPipesPartMgr.cpp | 41 +++++++++++-------- .../UserInterface/RiuViewerCommands.cpp | 23 ++++++++++- 5 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.cpp create mode 100644 ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.h diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index 13163351b8..d3ab43480f 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -35,6 +35,7 @@ ${CEE_CURRENT_LIST_DIR}RivScalarMapperUtils.h ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.h ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.h ${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.h +${CEE_CURRENT_LIST_DIR}RivWellPipeSourceInfo.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -66,7 +67,7 @@ ${CEE_CURRENT_LIST_DIR}RivScalarMapperUtils.cpp ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.cpp ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.cpp ${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.cpp - +${CEE_CURRENT_LIST_DIR}RivWellPipeSourceInfo.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.cpp new file mode 100644 index 0000000000..2e90f699bb --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.cpp @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivWellPipeSourceInfo.h" + +#include "RimEclipseWell.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivEclipseWellSourceInfo::RivEclipseWellSourceInfo(RimEclipseWell* eclipseWell) + : m_eclipseWell(eclipseWell) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseWell* RivEclipseWellSourceInfo::well() const +{ + return m_eclipseWell.p(); +} diff --git a/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.h b/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.h new file mode 100644 index 0000000000..41472b6dd1 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivWellPipeSourceInfo.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +class RimEclipseWell; + +class RivEclipseWellSourceInfo : public cvf::Object +{ +public: + RivEclipseWellSourceInfo(RimEclipseWell* eclipseWell); + + RimEclipseWell* well() const; + +private: + caf::PdmPointer m_eclipseWell; +}; diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index 5372356ff4..b326f2a4a1 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -20,34 +20,35 @@ #include "RivWellPipesPartMgr.h" -#include "cvfLibCore.h" -#include "cvfModelBasicList.h" -#include "cvfTransform.h" -#include "cvfPart.h" -#include "cvfScalarMapperDiscreteLinear.h" -#include "cvfDrawableGeo.h" -#include "cvfRay.h" - -#include "cafEffectGenerator.h" -#include "cafPdmFieldCvfColor.h" -#include "cafPdmFieldCvfMat4d.h" - #include "RigCaseData.h" #include "RigCell.h" -#include "RivPipeGeometryGenerator.h" +#include "Rim3dOverlayInfoConfig.h" +#include "RimCellEdgeColors.h" +#include "RimCellRangeFilterCollection.h" #include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimEclipseWellCollection.h" #include "RimReservoirCellResultsStorage.h" -#include "RimEclipseCellColors.h" -#include "RimCellEdgeColors.h" -#include "RimCellRangeFilterCollection.h" -#include "RimEclipsePropertyFilterCollection.h" -#include "Rim3dOverlayInfoConfig.h" +#include "RivPipeGeometryGenerator.h" +#include "RivWellPathSourceInfo.h" +#include "RivWellPipeSourceInfo.h" + +#include "cafEffectGenerator.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfMat4d.h" +#include "cvfDrawableGeo.h" +#include "cvfLibCore.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfRay.h" +#include "cvfScalarMapperDiscreteLinear.h" +#include "cvfTransform.h" //-------------------------------------------------------------------------------------------------- @@ -105,6 +106,8 @@ void RivWellPipesPartMgr::buildWellPipeParts() double characteristicCellSize = m_rimReservoirView->eclipseCase()->reservoirData()->mainGrid()->characteristicIJCellSize(); double pipeRadius = m_rimReservoirView->wellCollection()->pipeRadiusScaleFactor() *m_rimWell->pipeRadiusScaleFactor() * characteristicCellSize; + cvf::ref sourceInfo = new RivEclipseWellSourceInfo(m_rimWell); + for (size_t brIdx = 0; brIdx < pipeBranchesCellIds.size(); ++brIdx) { m_wellBranches.push_back(RivPipeBranchData()); @@ -145,6 +148,8 @@ void RivWellPipesPartMgr::buildWellPipeParts() cvf::ref eff = surfaceGen.generateCachedEffect(); pbd.m_surfacePart->setEffect(eff.p()); + + pbd.m_surfacePart->setSourceInfo(sourceInfo.p()); } if (pbd.m_centerLineDrawable.notNull()) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 5dff91acd6..567bf582a4 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -23,6 +23,7 @@ #include "RicGeoMechPropertyFilterNewExec.h" #include "RicRangeFilterNewExec.h" +#include "CrossSectionCommands/RicNewSimWellCrossSectionFeature.h" #include "CrossSectionCommands/RicNewWellPathCrossSectionFeature.h" #include "WellLogCommands/RicNewWellLogCurveExtractionFeature.h" #include "WellLogCommands/RicNewWellLogFileCurveFeature.h" @@ -40,6 +41,7 @@ #include "RimEclipsePropertyFilter.h" #include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseView.h" +#include "RimEclipseWell.h" #include "RimFaultCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" @@ -63,11 +65,13 @@ #include "RivFemPickSourceInfo.h" #include "RivSourceInfo.h" #include "RivWellPathSourceInfo.h" +#include "RivWellPipeSourceInfo.h" #include "cafCmdExecCommandManager.h" #include "cafCmdFeature.h" #include "cafCmdFeatureManager.h" #include "cafPdmUiTreeView.h" +#include "cafSelectionManager.h" #include "cvfDrawableGeo.h" #include "cvfHitItemCollection.h" @@ -221,13 +225,14 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) // Well log curve creation commands if (firstHitPart && firstHitPart->sourceInfo()) { + caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); + const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (wellPathSourceInfo) { RimWellPath* wellPath = wellPathSourceInfo->wellPath(); if (wellPath) { - caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); RicNewWellLogFileCurveFeature* newWellLogFileCurveFeature = dynamic_cast(commandManager->getCommandFeature("RicNewWellLogFileCurveFeature")); if (newWellLogFileCurveFeature && newWellLogFileCurveFeature->canFeatureBeExecuted()) @@ -250,6 +255,22 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) } } } + + const RivEclipseWellSourceInfo* eclipseWellSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + if (eclipseWellSourceInfo) + { + RimEclipseWell* well = eclipseWellSourceInfo->well(); + if (well) + { + caf::SelectionManager::instance()->setSelectedItem(well); + + RicNewSimWellCrossSectionFeature* newSimWellCrossSectionFeature = dynamic_cast(commandManager->getCommandFeature("RicNewSimWellCrossSectionFeature")); + if (newSimWellCrossSectionFeature && newSimWellCrossSectionFeature->canFeatureBeExecuted()) + { + menu.addAction(newSimWellCrossSectionFeature->action()); + } + } + } } // View Link commands From 3f250ab0ff1a47de204a3886042df471afff230e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 18 Nov 2015 21:02:20 +0100 Subject: [PATCH 083/290] (#166) Final mesh lines fixes for cross section --- .../ModelVisualization/RivCrossSectionGeometryGenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 948553b167..9624082fd2 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -369,7 +369,7 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(triangleVxes[newVx1OnP2.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); continue; @@ -462,7 +462,7 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(newVx1OnP2); clippedTriangleVxes->push_back(newVx1OnP1); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); From bb8475b0e17f8a004c49de257a37c12a7cba1596 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 07:38:31 +0100 Subject: [PATCH 084/290] [System] Reduced scope of variables --- .../ProjectDataModel/RimEclipseView.cpp | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 355970f3f3..b0d6faf613 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1035,14 +1035,14 @@ void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, R { RimReservoirCellResultsStorage* gridCellResults = resultColors->currentGridCellResults(); { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SOIL"); if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); cellResultsData->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); @@ -1051,14 +1051,14 @@ void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, R } { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SGAS"); if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); cellResultsData->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); @@ -1067,14 +1067,14 @@ void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, R } { - double globalMin = 0.0; - double globalMax = 1.0; - double localMin = 0.0; - double localMax = 1.0; - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RimDefines::DYNAMIC_NATIVE, "SWAT"); if (scalarSetIndex != cvf::UNDEFINED_SIZE_T) { + double globalMin = 0.0; + double globalMax = 1.0; + double localMin = 0.0; + double localMax = 1.0; + cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); cellResultsData->minMaxCellScalarValues(scalarSetIndex, m_currentTimeStep, localMin, localMax); From 5ac3dea46deb6bce2032db693ab13a8758691ce3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 07:57:39 +0100 Subject: [PATCH 085/290] [System] Cleaned up unused variables and functions --- .../RicAddWellLogToPlotFeature.cpp | 2 -- .../RicNewWellLogCurveExtractionFeature.cpp | 3 -- .../RicNewWellLogFileCurveFeature.cpp | 2 -- .../RivFemElmVisibilityCalculator.cpp | 2 -- .../RivFemPartGeometryGenerator.cpp | 4 --- .../ProjectDataModel/RimEclipseCase.cpp | 17 ----------- .../ProjectDataModel/RimEclipseCase.h | 1 - .../ProjectDataModel/RimEclipseInputCase.cpp | 30 ------------------- .../ProjectDataModel/RimEclipseInputCase.h | 2 -- .../UserInterface/RiuMainWindow.cpp | 2 +- .../RiuMultiCaseImportDialog.cpp | 3 -- .../RiuSelectionChangedHandler.cpp | 2 -- 12 files changed, 1 insertion(+), 69 deletions(-) diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index 2ae4694c36..19cf118734 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -87,8 +87,6 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) wellLog->firstAnchestorOrThisOfType(wellLogFile); if (wellLogFile) { - size_t curveIdx = plotTrack->curveCount(); - RimWellLogFileCurve* curve = new RimWellLogFileCurve; plotTrack->addCurve(curve); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index 4241d7f526..0da0aeeaf9 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -118,9 +118,6 @@ bool RicNewWellLogCurveExtractionFeature::caseAvailable() const RimWellLogExtractionCurve* RicNewWellLogCurveExtractionFeature::addCurve(RimWellLogTrack* plotTrack, RimView* view, RimWellPath* wellPath) { CVF_ASSERT(plotTrack); - - size_t curveIndex = plotTrack->curveCount(); - RimWellLogExtractionCurve* curve = new RimWellLogExtractionCurve(); cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp index 96855dfde5..95300e49e9 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp @@ -144,8 +144,6 @@ RimWellLogFileCurve* RicNewWellLogFileCurveFeature::addCurve(RimWellLogTrack* pl { CVF_ASSERT(plotTrack); - size_t curveIndex = plotTrack->curveCount(); - RimWellLogFileCurve* curve = new RimWellLogFileCurve(); plotTrack->addCurve(curve); diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp index ba76a26724..d9f7fbe2c1 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp @@ -119,8 +119,6 @@ void RivFemElmVisibilityCalculator::computePropertyVisibility(cvf::UByteArray* c // Do a "Hack" to use elm nodal and not nodal POR results if (resVarAddress.resultPosType == RIG_NODAL && resVarAddress.fieldName == "POR-Bar") resVarAddress.resultPosType = RIG_ELEMENT_NODAL; - size_t adjustedTimeStepIndex = timeStepIndex; - const RimCellFilter::FilterModeType filterType = propertyFilter->filterMode(); RigGeoMechCaseData* caseData = propFilterColl->reservoirView()->geoMechCase()->geoMechData(); diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp index e655ddf137..cce048fb24 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp @@ -177,7 +177,6 @@ void RivFemPartGeometryGenerator::computeArrays() { RigElementType eType = m_part->elementType(elmIdx); int faceCount = RigFemTypes::elmentFaceCount(eType); - int elmQuadCount = 0; const int* elmNodeIndices = m_part->connectivities(elmIdx); @@ -277,14 +276,11 @@ cvf::ref RivFemPartGeometryGenerator::createMeshDrawableFromSi RigElementType eType = part->elementType(elmIdx); int faceCount = RigFemTypes::elmentFaceCount(eType); - int elmQuadCount = 0; const int* elmNodeIndices = part->connectivities(elmIdx); for (int lfIdx = 0; lfIdx < faceCount; ++lfIdx) { - int elmNeighbor = part->elementNeighbor(static_cast(elmIdx), lfIdx); - int faceNodeCount = 0; const int* localElmNodeIndicesForFace = RigFemTypes::localElmNodeIndicesForFace(eType, lfIdx, &faceNodeCount); if (faceNodeCount == 4) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp index 3f6ae1084a..511b5f09f8 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp @@ -317,23 +317,6 @@ RimCaseCollection* RimEclipseCase::parentCaseCollection() return dynamic_cast(this->parentField()->ownerObject()); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimIdenticalGridCaseGroup* RimEclipseCase::parentGridCaseGroup() -{ - RimCaseCollection* caseColl = parentCaseCollection(); - if (caseColl) - { - return caseColl->parentCaseGroup(); - } - else - { - return NULL; - } -} - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.h b/ApplicationCode/ProjectDataModel/RimEclipseCase.h index 47521175c2..72bb06ef0e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.h @@ -82,7 +82,6 @@ class RimEclipseCase : public RimCase RimCaseCollection* parentCaseCollection(); - RimIdenticalGridCaseGroup* parentGridCaseGroup(); virtual std::vector views(); virtual QStringList timeStepStrings(); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp index 3994ceecf7..ae5fef1650 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp @@ -329,36 +329,6 @@ void RimEclipseInputCase::loadAndSyncronizeInputProperties() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseInputCase::removeProperty(RimEclipseInputProperty* inputProperty) -{ - bool isPropertyFileReferencedByOthers = false; - - m_inputPropertyCollection->removeInputProperty(inputProperty, isPropertyFileReferencedByOthers); - if (!isPropertyFileReferencedByOthers) - { - std::vector newList; - size_t i; - for (i = 0; i < m_additionalFileNames().size(); i++) - { - if (m_additionalFileNames()[i] != inputProperty->fileName) - { - newList.push_back(m_additionalFileNames()[i]); - } - } - - m_additionalFileNames.v() = newList; - } - - // Remove the results pointed to by this input property - RigCaseCellResultsData* results = reservoirData()->results(RifReaderInterface::MATRIX_RESULTS); - results->removeResult(inputProperty->resultName); - - this->removeResult(inputProperty->resultName); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.h b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.h index 70346a5994..36974a91f6 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.h @@ -51,8 +51,6 @@ class RimEclipseInputCase : public RimEclipseCase void openDataFileSet(const QStringList& fileNames); void loadAndSyncronizeInputProperties(); - void removeProperty(RimEclipseInputProperty* inputProperty); - // RimCase overrides virtual bool openEclipseGridFile(); // Find grid file among file set. Read, Find read and validate property date. Syncronize child property sets. diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 457b983934..a2d81f6e74 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1024,7 +1024,7 @@ void RiuMainWindow::slotInputMockModel() //-------------------------------------------------------------------------------------------------- bool RiuMainWindow::checkForDocumentModifications() { - RiaApplication* app = RiaApplication::instance(); +// RiaApplication* app = RiaApplication::instance(); // RISceneManager* project = app->sceneManager(); // if (project && project->isModified()) // { diff --git a/ApplicationCode/UserInterface/RiuMultiCaseImportDialog.cpp b/ApplicationCode/UserInterface/RiuMultiCaseImportDialog.cpp index 8a3466df5a..396280a672 100644 --- a/ApplicationCode/UserInterface/RiuMultiCaseImportDialog.cpp +++ b/ApplicationCode/UserInterface/RiuMultiCaseImportDialog.cpp @@ -148,14 +148,11 @@ void RiuMultiCaseImportDialog::on_m_removeSearchFolderButton_clicked() //-------------------------------------------------------------------------------------------------- void RiuMultiCaseImportDialog::updateGridFileList() { - QStringList folderNames = m_searchFolders->stringList(); QStringList gridFileNames; - // Filter the search folders to remove subfolders of existing roots' - bool okToAdd = true; QStringList searchFoldersToRemove; for (int i = 0; i < folderNames.size(); ++i) diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index 6a0dcaab39..8357071d76 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -192,8 +192,6 @@ void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuSelectionIte //-------------------------------------------------------------------------------------------------- void RiuSelectionChangedHandler::scheduleUpdateForAllVisibleViews() const { - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - RimProject* proj = RiaApplication::instance()->project(); if (proj) { From 9c2b1b44a632b60cfc4673aed3293a3fea143b23 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 11:41:16 +0100 Subject: [PATCH 086/290] (#657) Wired up UI to viz model generation for cross sections --- .../RivCrossSectionPartMgr.cpp | 90 +++++++++++++++---- .../RivCrossSectionPartMgr.h | 24 ++--- .../ProjectDataModel/RimCrossSection.cpp | 20 ++++- .../ProjectDataModel/RimCrossSection.h | 8 +- .../RimCrossSectionCollection.cpp | 41 +++++++++ .../RimCrossSectionCollection.h | 11 +++ .../ProjectDataModel/RimEclipseView.cpp | 31 +++---- .../ProjectDataModel/RimEclipseView.h | 1 - ApplicationCode/ProjectDataModel/RimView.cpp | 33 ++++--- ApplicationCode/ProjectDataModel/RimView.h | 7 +- .../RiuSelectionChangedHandler.cpp | 2 +- 11 files changed, 205 insertions(+), 63 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 2f621123b9..ef7de1941a 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -19,21 +19,17 @@ #include "RivCrossSectionPartMgr.h" -//#include "RiaApplication.h" -//#include "RiaPreferences.h" - #include "RigCaseCellResultsData.h" #include "RigCaseData.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" +#include "RimCrossSection.h" #include "RimEclipseCase.h" -#include "RimEclipseView.h" #include "RimEclipseCellColors.h" +#include "RimEclipseView.h" #include "RimTernaryLegendConfig.h" -//#include "RimCrossSectionCollection.h" - #include "RivResultToTextureMapper.h" #include "RivScalarMapperUtils.h" #include "RivTernaryScalarMapper.h" @@ -47,19 +43,16 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivCrossSectionPartMgr::RivCrossSectionPartMgr( const RigMainGrid* grid, - const RimCrossSectionCollection* rimCrossSectionCollection, - const RimCrossSection* rimCrossSection, - const std::vector& polyLine) - : m_grid(grid), - m_rimCrossSectionCollection(rimCrossSectionCollection), - m_rimCrossSection(rimCrossSection), - m_defaultColor(cvf::Color3::WHITE) +RivCrossSectionPartMgr::RivCrossSectionPartMgr(const RimCrossSection* rimCrossSection) + : m_rimCrossSection(rimCrossSection), + m_grid(NULL), + m_defaultColor(cvf::Color3::WHITE) { - - m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine, cvf::Vec3d(0.0,0,1.0), grid ); + CVF_ASSERT(m_rimCrossSection); m_nativeCrossSectionFacesTextureCoords = new cvf::Vec2fArray; + + computeData(); } //-------------------------------------------------------------------------------------------------- @@ -67,6 +60,8 @@ RivCrossSectionPartMgr::RivCrossSectionPartMgr( const RigMainGrid* grid, //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::applySingleColorEffect() { + if (m_nativeCrossSectionGenerator.isNull()) return; + m_defaultColor = cvf::Color3f::OLIVE;//m_rimCrossSection->CrossSectionColor(); this->updatePartEffect(); } @@ -76,6 +71,8 @@ void RivCrossSectionPartMgr::applySingleColorEffect() //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) { + if (m_nativeCrossSectionGenerator.isNull()) return; + CVF_ASSERT(cellResultColors); RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); @@ -106,6 +103,8 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEcli } else { + CVF_ASSERT(m_nativeCrossSectionGenerator.notNull()); + const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), @@ -137,6 +136,7 @@ const int priMesh = 3; //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::generatePartGeometry() { + if (m_nativeCrossSectionGenerator.isNull()) return; bool useBufferObjects = true; // Surface geometry @@ -199,6 +199,8 @@ void RivCrossSectionPartMgr::generatePartGeometry() //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::updatePartEffect() { + if (m_nativeCrossSectionGenerator.isNull()) return; + // Set deCrossSection effect caf::SurfaceEffectGenerator geometryEffgen(m_defaultColor, caf::PO_1); @@ -258,3 +260,59 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::computeData() +{ + m_grid = mainGrid(); + CVF_ASSERT(m_grid.notNull()); + + std::vector< std::vector > polyLine = m_rimCrossSection->polyLines(); + if (polyLine.size() > 0) + { + cvf::Vec3d direction = extrusionDirection(polyLine[0]); + m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, m_grid.p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigMainGrid* RivCrossSectionPartMgr::mainGrid() +{ + RigMainGrid* grid = NULL; + + RimEclipseView* eclipseView = NULL; + m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); + if (eclipseView) + { + grid = eclipseView->eclipseCase()->reservoirData()->mainGrid(); + } + + return grid; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivCrossSectionPartMgr::extrusionDirection(const std::vector& polyline) const +{ + CVF_ASSERT(m_rimCrossSection); + + cvf::Vec3d dir = cvf::Vec3d::Z_AXIS; + + if (m_rimCrossSection->direction == RimCrossSection::CS_VERTICAL && + polyline.size() > 1) + { + // Use first and last point of polyline to approximate orientation of polyline + // Then cross with Z axis to find extrusion direction + + cvf::Vec3d polyLineDir = polyline[polyline.size() - 1] - polyline[0]; + cvf::Vec3d up = cvf::Vec3d::Z_AXIS; + dir = polyLineDir ^ up; + } + + return dir; +} + diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 091dccb98b..736b1b13be 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -18,12 +18,14 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once -#include "cvfBase.h" -#include "cvfObject.h" -//#include "RimCrossSection.h" #include "RivCrossSectionGeometryGenerator.h" + +#include "cvfBase.h" +#include "cvfObject.h" #include "cvfColor4.h" +#include "cvfVector3.h" + namespace cvf { @@ -32,9 +34,9 @@ namespace cvf class Part; } +class RigMainGrid; class RimEclipseCellColors; class RimCellEdgeColors; -class RimCrossSectionCollection; class RimCrossSection; //================================================================================================== @@ -45,10 +47,7 @@ class RimCrossSection; class RivCrossSectionPartMgr : public cvf::Object { public: - RivCrossSectionPartMgr(const RigMainGrid* grid, - const RimCrossSectionCollection* rimCrossSectionCollection, - const RimCrossSection* rimCrossSection, - const std::vector& polyLine); + RivCrossSectionPartMgr(const RimCrossSection* rimCrossSection); void applySingleColorEffect(); void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); @@ -59,10 +58,15 @@ class RivCrossSectionPartMgr : public cvf::Object private: void updatePartEffect(); void generatePartGeometry(); + void computeData(); + + RigMainGrid* mainGrid(); + cvf::Vec3d extrusionDirection(const std::vector& polyline) const; + +private: cvf::cref m_grid; - const RimCrossSection* m_rimCrossSection; - const RimCrossSectionCollection* m_rimCrossSectionCollection; + const RimCrossSection* m_rimCrossSection; cvf::Color3f m_defaultColor; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 43d84d1324..8b04b98e96 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -28,6 +28,7 @@ #include "RimProject.h" #include "RimWellPath.h" +#include "RivCrossSectionPartMgr.h" namespace caf { @@ -78,7 +79,14 @@ RimCrossSection::RimCrossSection() //-------------------------------------------------------------------------------------------------- void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { - + m_crossSectionPartMgr = NULL; + + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + if (rimView) + { + rimView->scheduleCreateDisplayModelAndRedraw(); + } } //-------------------------------------------------------------------------------------------------- @@ -213,3 +221,13 @@ std::vector< std::vector > RimCrossSection::polyLines() const return line; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionPartMgr* RimCrossSection::crossSectionPartMgr() +{ + if (m_crossSectionPartMgr.isNull()) m_crossSectionPartMgr = new RivCrossSectionPartMgr(this); + + return m_crossSectionPartMgr.p(); +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index d47d4a5f95..3589e00fa2 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -25,12 +25,13 @@ #include "cafPdmPtrField.h" #include "cvfBase.h" +#include "cvfObject.h" #include "cvfVector3.h" class RimEclipseWell; class RimEclipseWellCollection; class RimWellPath; - +class RivCrossSectionPartMgr; //================================================================================================== // @@ -72,6 +73,8 @@ class RimCrossSection : public caf::PdmObject virtual caf::PdmFieldHandle* userDescriptionField(); virtual caf::PdmFieldHandle* objectToggleField(); + RivCrossSectionPartMgr* crossSectionPartMgr(); + protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); @@ -80,4 +83,7 @@ class RimCrossSection : public caf::PdmObject private: RimEclipseWellCollection* simulationWellCollection(); + +private: + cvf::ref m_crossSectionPartMgr; }; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 09a899275e..767b3fcae7 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -20,6 +20,7 @@ #include "RimCrossSectionCollection.h" #include "RimCrossSection.h" +#include "RivCrossSectionPartMgr.h" CAF_PDM_SOURCE_INIT(RimCrossSectionCollection, "CrossSectionCollection"); @@ -45,3 +46,43 @@ caf::PdmFieldHandle* RimCrossSectionCollection::objectToggleField() { return &isActive; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSectionCollection::applySingleColorEffect() +{ + for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + { + RimCrossSection* cs = crossSections[csIdx]; + cs->crossSectionPartMgr()->applySingleColorEffect(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +{ + for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + { + RimCrossSection* cs = crossSections[csIdx]; + cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex, cellResultColors); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSectionCollection::appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) +{ + for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + { + RimCrossSection* cs = crossSections[csIdx]; + if (cs->isActive) + { + cs->crossSectionPartMgr()->appendNativeCrossSectionFacesToModel(model, scaleTransform); + cs->crossSectionPartMgr()->appendMeshLinePartsToModel(model, scaleTransform); + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h index 892d586c09..13baa1efe1 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -24,6 +24,12 @@ #include "cafPdmField.h" class RimCrossSection; +class RimEclipseCellColors; + +namespace cvf { + class ModelBasicList; + class Transform; +} //================================================================================================== // @@ -40,6 +46,11 @@ class RimCrossSectionCollection : public caf::PdmObject caf::PdmField isActive; caf::PdmChildArrayField crossSections; + void applySingleColorEffect(); + void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); + + void appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); + protected: //virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); //virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index b0d6faf613..60b71f160d 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -31,6 +31,7 @@ #include "Rim3dOverlayInfoConfig.h" #include "RimCellEdgeColors.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSection.h" #include "RimCrossSectionCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" @@ -71,7 +72,6 @@ #include #include -#include "RivCrossSectionPartMgr.h" @@ -418,21 +418,13 @@ void RimEclipseView::createDisplayModel() } - // Hack to do testing of cross section - { -#if 0 - cvf::ref tempMod = new cvf::ModelBasicList; - m_pipesPartManager->appendDynamicGeometryPartsToModel(tempMod.p(), 3); - if (m_csPartmgr.isNull()) m_csPartmgr = new RivCrossSectionPartMgr(m_reservoir->reservoirData()->mainGrid(), NULL, NULL, - (*m_pipesPartManager->centerLineOfWellBranches(0))[0]); - for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx) - { - m_csPartmgr->appendNativeCrossSectionFacesToModel(frameModels[frameIdx].p(), m_reservoirGridPartManager->scaleTransform()); - m_csPartmgr->appendMeshLinePartsToModel(frameModels[frameIdx].p(), m_reservoirGridPartManager->scaleTransform()); - } -#endif - } + // Cross sections + + m_crossSectionModel->removeAllParts(); + crossSectionCollection->appendPartsToModel(m_crossSectionModel.p(), m_reservoirGridPartManager->scaleTransform()); + m_viewer->addStaticModel(m_crossSectionModel.p()); + // Compute triangle count, Debug only /* @@ -660,9 +652,14 @@ void RimEclipseView::updateCurrentTimeStep() this->updateFaultColors(); - // Hack to do testing of cross section + + if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || this->cellResult()->isTernarySaturationSelected()) + { + crossSectionCollection->updateCellResultColor(m_currentTimeStep, this->cellResult()); + } + else { - // this->m_csPartmgr->updateCellResultColor(m_currentTimeStep, this->cellResult()); + crossSectionCollection->applySingleColorEffect(); } // Well pipes diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index e69fea4038..7dbaa0c89c 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -182,7 +182,6 @@ class RimEclipseView : public RimView cvf::ref m_reservoirGridPartManager; cvf::ref m_pipesPartManager; - cvf::ref m_csPartmgr; std::vector m_visibleGridParts; }; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 608515a850..38faad881b 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -122,6 +122,13 @@ RimView::RimView(void) crossSectionCollection = new RimCrossSectionCollection(); m_previousGridModeMeshLinesWasFaults = false; + + + m_crossSectionModel = new cvf::ModelBasicList; + m_crossSectionModel->setName("CrossSectionModel"); + + m_highlightModelBasicList = new cvf::ModelBasicList; + m_highlightModelBasicList->setName("HighlightModel"); } //-------------------------------------------------------------------------------------------------- @@ -276,7 +283,7 @@ void RimView::createDisplayModelAndRedraw() this->clampCurrentTimestep(); createDisplayModel(); - createOverlayDisplayModel(); + createHighlightAndGridBoxDisplayModel(); updateDisplayModelVisibility(); if (cameraPosition().isIdentity()) @@ -518,7 +525,7 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV } else if (changedField == &showGridBox) { - createOverlayDisplayModelAndRedraw(); + createHighlightAndGridBoxDisplayModelWithRedraw(); } else if (changedField == &m_disableLighting) { @@ -801,9 +808,9 @@ void RimView::updateGridBoxData() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimView::createOverlayDisplayModelAndRedraw() +void RimView::createHighlightAndGridBoxDisplayModelWithRedraw() { - createOverlayDisplayModel(); + createHighlightAndGridBoxDisplayModel(); if (m_viewer) { @@ -814,26 +821,24 @@ void RimView::createOverlayDisplayModelAndRedraw() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimView::createOverlayDisplayModel() +void RimView::createHighlightAndGridBoxDisplayModel() { - m_viewer->removeAllStaticModels(); + m_viewer->removeStaticModel(m_highlightModelBasicList.p()); + m_viewer->removeStaticModel(m_viewer->gridBoxModel()); + + m_highlightModelBasicList->removeAllParts(); cvf::Collection parts; createPartCollectionFromSelection(&parts); if (parts.size() > 0) { - cvf::String highlightModelName = "HighLightModel"; - - cvf::ref highlightModelBasicList = new cvf::ModelBasicList; - highlightModelBasicList->setName(highlightModelName); - for (size_t i = 0; i < parts.size(); i++) { - highlightModelBasicList->addPart(parts[i].p()); + m_highlightModelBasicList->addPart(parts[i].p()); } - highlightModelBasicList->updateBoundingBoxesRecursive(); - m_viewer->addStaticModel(highlightModelBasicList.p()); + m_highlightModelBasicList->updateBoundingBoxesRecursive(); + m_viewer->addStaticModel(m_highlightModelBasicList.p()); } if (showGridBox) diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 03d2e2aa1b..39e83ea0d0 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -135,7 +135,7 @@ class RimView : public caf::PdmObject virtual void scheduleGeometryRegen(RivCellSetEnum geometryType) = 0; void scheduleCreateDisplayModelAndRedraw(); void createDisplayModelAndRedraw(); - void createOverlayDisplayModelAndRedraw(); + void createHighlightAndGridBoxDisplayModelWithRedraw(); RimViewController* viewController() const; bool isMasterView() const; @@ -165,7 +165,7 @@ class RimView : public caf::PdmObject virtual void createDisplayModel() = 0; - void createOverlayDisplayModel(); + void createHighlightAndGridBoxDisplayModel(); void updateGridBoxData(); virtual void createPartCollectionFromSelection(cvf::Collection* parts) = 0; @@ -200,6 +200,9 @@ class RimView : public caf::PdmObject cvf::ref m_currentReservoirCellVisibility; + cvf::ref m_crossSectionModel; + cvf::ref m_highlightModelBasicList; + private: RimViewLinker* viewLinkerIfMasterView() const; diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index 8357071d76..0d0b8a0bc8 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -200,7 +200,7 @@ void RiuSelectionChangedHandler::scheduleUpdateForAllVisibleViews() const for (size_t i = 0; i < visibleViews.size(); i++) { - visibleViews[i]->createOverlayDisplayModelAndRedraw(); + visibleViews[i]->createHighlightAndGridBoxDisplayModelWithRedraw(); } } } From 74f0251ee965b65acc0e518f52ba590919eeafda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 19 Nov 2015 10:59:05 +0100 Subject: [PATCH 087/290] (#166) WIP: Preparing for interpolation --- .../RivCrossSectionGeometryGenerator.cpp | 113 ++++++++++-------- 1 file changed, 66 insertions(+), 47 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 9624082fd2..47d1cefa07 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -85,11 +85,15 @@ bool planeLineIntersect(const cvf::Plane& plane, const cvf::Vec3d& a, const cvf: struct ClipVx { - ClipVx() : vx(cvf::Vec3d::ZERO), normDistFromEdgeVx1(HUGE_VAL), clippedEdgeVx1Id(-1), clippedEdgeVx2Id(-1) {} - cvf::Vec3d vx; - double normDistFromEdgeVx1; - int clippedEdgeVx1Id; - int clippedEdgeVx2Id; + ClipVx() : vx(cvf::Vec3d::ZERO), normDistFromEdgeVx1(HUGE_VAL), clippedEdgeVx1Id(-1), clippedEdgeVx2Id(-1), isVxIdsNative(true) {} + + cvf::Vec3d vx; + + double normDistFromEdgeVx1; + int clippedEdgeVx1Id; + int clippedEdgeVx2Id; + + bool isVxIdsNative; }; //-------------------------------------------------------------------------------------------------- @@ -238,10 +242,13 @@ bool planeTriangleIntersection(const cvf::Plane& plane, // All Quad Top None // // +// Clips the supplied triangles into new triangles returned in clippedTriangleVxes. +// New vertices have set isVxIdsNative = false and their vxIds is indices into triangleVxes +// The isTriangleEdgeCellContour bits refer to the edge after the corresponding triangle vertex. //-------------------------------------------------------------------------------------------------- void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVxes, - const std::vector &isTriangleEdgeInternal, + const std::vector &isTriangleEdgeCellContour, const cvf::Plane& p1Plane, const cvf::Plane& p2Plane, std::vector *clippedTriangleVxes, std::vector *isClippedTriEdgeCellContour) @@ -254,7 +261,10 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx int triVxIdx = tIdx*3; ClipVx newVx1OnP1; + newVx1OnP1.isVxIdsNative = false; ClipVx newVx2OnP1; + newVx2OnP1.isVxIdsNative = false; + bool isMostVxesOnPositiveSideOfP1 = false; bool isIntersectingP1 = planeTriangleIntersection(p1Plane, triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, @@ -269,7 +279,9 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx ClipVx newVx1OnP2; + newVx1OnP2.isVxIdsNative = false; ClipVx newVx2OnP2; + newVx2OnP2.isVxIdsNative = false; bool isMostVxesOnPositiveSideOfP2 = false; bool isIntersectingP2 = planeTriangleIntersection(p2Plane, triangleVxes[triVxIdx + 0].vx, triVxIdx + 0, @@ -296,9 +308,9 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(triangleVxes[triVxIdx + 1]); clippedTriangleVxes->push_back(triangleVxes[triVxIdx + 2]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 0]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 1]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[triVxIdx + 2]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[triVxIdx + 0]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[triVxIdx + 1]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[triVxIdx + 2]); continue; } @@ -315,11 +327,11 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(newVx2OnP1); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx2Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP1.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); continue; @@ -338,10 +350,10 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP2.clippedEdgeVx2Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); continue; @@ -355,8 +367,8 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(triangleVxes[newVx1OnP1.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx1Id]); continue; } @@ -369,8 +381,8 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(triangleVxes[newVx1OnP2.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx1Id]); continue; } @@ -395,7 +407,7 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(triangleVxes[newVx2OnP1.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); @@ -403,8 +415,8 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP1.clippedEdgeVx2Id]); } else { @@ -418,12 +430,12 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP2.clippedEdgeVx2Id]); } continue; @@ -440,12 +452,12 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(newVx2OnP2); clippedTriangleVxes->push_back(newVx2OnP1); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP1.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP1.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP2.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP2.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); continue; @@ -462,12 +474,12 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx clippedTriangleVxes->push_back(newVx1OnP2); clippedTriangleVxes->push_back(newVx1OnP1); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx2OnP1.clippedEdgeVx2Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx2OnP1.clippedEdgeVx2Id]); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); isClippedTriEdgeCellContour->push_back(false); - isClippedTriEdgeCellContour->push_back(isTriangleEdgeInternal[newVx1OnP2.clippedEdgeVx1Id]); + isClippedTriEdgeCellContour->push_back(isTriangleEdgeCellContour[newVx1OnP2.clippedEdgeVx1Id]); isClippedTriEdgeCellContour->push_back(false); continue; @@ -1100,38 +1112,45 @@ void RivCrossSectionGeometryGenerator::calculateArrays() clipTrianglesBetweenTwoParallelPlanes(triangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); - triangleCount = static_cast(clippedTriangleVxes.size())/3; - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + int clippedTriangleCount = static_cast(clippedTriangleVxes.size())/3; + + // Accumulate triangle vertices + for (int tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) { - // Accumulate to geometry int triVxIdx = tIdx*3; - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); - m_triangleToCellIdxMap.push_back(globalCellIdx); - } + cvf::Vec3f p0(clippedTriangleVxes[triVxIdx+0].vx - displayOffset); + cvf::Vec3f p1(clippedTriangleVxes[triVxIdx+1].vx - displayOffset); + cvf::Vec3f p2(clippedTriangleVxes[triVxIdx+2].vx - displayOffset); + + triangleVertices.push_back(p0); + triangleVertices.push_back(p1); + triangleVertices.push_back(p2); + + + // Accumulate mesh lines - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) - { - // Accumulate to geometry - int triVxIdx = tIdx*3; if (isClippedTriEdgeCellContour[triVxIdx]) { - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); + cellBorderLineVxes.push_back(p0); + cellBorderLineVxes.push_back(p1); } if (isClippedTriEdgeCellContour[triVxIdx+1]) { - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+1].vx - displayOffset)); - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); + cellBorderLineVxes.push_back(p1); + cellBorderLineVxes.push_back(p2); } if (isClippedTriEdgeCellContour[triVxIdx+2]) { - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+2].vx - displayOffset)); - cellBorderLineVxes.push_back(cvf::Vec3f(clippedTriangleVxes[triVxIdx+0].vx - displayOffset)); + cellBorderLineVxes.push_back(p2); + cellBorderLineVxes.push_back(p0); } + // Mapping to data + + m_triangleToCellIdxMap.push_back(globalCellIdx); + + } #endif From 227eba03253227b51fe28dfad6a4f6245c515007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 19 Nov 2015 13:33:50 +0100 Subject: [PATCH 088/290] (#166) Added storage of interpolation metadata --- .../RivCrossSectionGeometryGenerator.cpp | 33 ++++++++++++++--- .../RivCrossSectionGeometryGenerator.h | 37 +++++++++++++++++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 47d1cefa07..7abbea18b5 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1060,8 +1060,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 - plane.normal() ); - std::vector triangleVxes; - triangleVxes.reserve(5*3); + std::vector triangleClipVxes; + triangleClipVxes.reserve(5*3); std::vector isTriangleEdgeCellContour; isTriangleEdgeCellContour.reserve(5*3); @@ -1071,7 +1071,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (m_mainGrid->cells()[globalCellIdx].isInvalid()) continue; - triangleVxes.clear(); + triangleClipVxes.clear(); cvf::Vec3d cellCorners[8]; m_mainGrid->cellCornerVertices(globalCellIdx, cellCorners); @@ -1089,7 +1089,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() int triangleCount = planeHexIntersectionMC(plane, cellCorners, hexCornersIds, - &triangleVxes, + &triangleClipVxes, &isTriangleEdgeCellContour); @@ -1110,7 +1110,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() std::vector clippedTriangleVxes; std::vector isClippedTriEdgeCellContour; - clipTrianglesBetweenTwoParallelPlanes(triangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); + clipTrianglesBetweenTwoParallelPlanes(triangleClipVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); int clippedTriangleCount = static_cast(clippedTriangleVxes.size())/3; @@ -1150,7 +1150,28 @@ void RivCrossSectionGeometryGenerator::calculateArrays() m_triangleToCellIdxMap.push_back(globalCellIdx); - + for (int i = 0; i < 3; ++i) + { + ClipVx cvx = clippedTriangleVxes[triVxIdx+i]; + if (cvx.isVxIdsNative) + { + m_triangleVxInterPolationData.push_back( + VxInterPolData(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1, + -1, -1, 0.0, + 0.0)); + } + else + { + ClipVx cvx1 = triangleClipVxes[cvx.clippedEdgeVx1Id]; + ClipVx cvx2 = triangleClipVxes[cvx.clippedEdgeVx2Id]; + + m_triangleVxInterPolationData.push_back( + VxInterPolData(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, + cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, + cvx.normDistFromEdgeVx1)); + + } + } } #endif diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 270387fb27..f3e1dc08c1 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -62,14 +62,43 @@ class RivCrossSectionGeometryGenerator : public cvf::Object void adjustPolyline(); - cvf::ref m_triangleVxes; - cvf::ref m_cellBorderLineVxes; - - std::vector m_triangleToCellIdxMap; cvf::cref m_mainGrid; std::vector m_polyLine; cvf::Vec3d m_extrusionDirection; std::vector m_adjustedPolyline; + + // Output arrays + cvf::ref m_triangleVxes; + cvf::ref m_cellBorderLineVxes; + std::vector m_triangleToCellIdxMap; + + struct VxInterPolData + { + explicit VxInterPolData(int vx1, int vx2, double normDistFrom1, + int vx3, int vx4, double normDistFrom3, + double normDistFrom12) + : vx1Id(vx1), + weight1((float)(1.0 - normDistFrom1 - normDistFrom12 + normDistFrom1*normDistFrom12)), + vx2Id(vx2), + weight2((float)(normDistFrom1 - normDistFrom1*normDistFrom12)), + vx3Id(vx3), + weight3((float)(normDistFrom12 - normDistFrom3*normDistFrom12)), + vx4Id(vx4), + weight4((float)(normDistFrom3*normDistFrom12)) + {} + + int vx1Id; + float weight1; + int vx2Id; + float weight2; + + int vx3Id; + float weight3; + int vx4Id; + float weight4; + }; + + std::vector m_triangleVxInterPolationData; }; From 29973bbcf68944dadece4d08772601d60a63755f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 13:38:36 +0100 Subject: [PATCH 089/290] (#657) Fixed inverted horizontal / vertical mapping --- ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index ef7de1941a..cb4574d0a7 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -302,7 +302,7 @@ cvf::Vec3d RivCrossSectionPartMgr::extrusionDirection(const std::vectordirection == RimCrossSection::CS_VERTICAL && + if (m_rimCrossSection->direction == RimCrossSection::CS_HORIZONTAL && polyline.size() > 1) { // Use first and last point of polyline to approximate orientation of polyline From 089c9d47dab70e5de5dd84bdd9600fa90daeb624 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 13:40:45 +0100 Subject: [PATCH 090/290] (#657) Create new display model when adding / deleting a cross section --- .../RicAppendCrossSectionFeature.cpp | 9 ++--- .../RicNewSimWellCrossSectionFeature.cpp | 7 +--- .../RicNewWellPathCrossSectionFeature.cpp | 7 +--- .../Commands/RicDeleteItemExec.cpp | 8 +++++ .../RimCrossSectionCollection.cpp | 36 ++++++++++++++----- .../RimCrossSectionCollection.h | 10 ++++-- 6 files changed, 48 insertions(+), 29 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp index 77c6b0a448..8c44ccce51 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp @@ -22,8 +22,6 @@ #include "RimCrossSection.h" #include "RimCrossSectionCollection.h" -#include "RiuMainWindow.h" - #include "cafCmdExecCommandManager.h" #include "cafSelectionManager.h" @@ -96,11 +94,8 @@ void RicAppendCrossSectionFeatureCmd::redo() CVF_ASSERT(m_crossSectionCollection); RimCrossSection* crossSection = new RimCrossSection(); - crossSection->name = QString("Cross Section (%1)").arg(m_crossSectionCollection->crossSections.size() + 1); - m_crossSectionCollection->crossSections.push_back(crossSection); - - m_crossSectionCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + crossSection->name = QString("Cross Section"); + m_crossSectionCollection->appendCrossSection(crossSection); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp index f5d89e6154..22ed07350b 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp @@ -24,8 +24,6 @@ #include "RimEclipseView.h" #include "RimEclipseWell.h" -#include "RiuMainWindow.h" - #include "cafCmdExecCommandManager.h" #include "cafSelectionManager.h" @@ -109,10 +107,7 @@ void RicNewSimWellCrossSectionCmd::redo() crossSection->type = RimCrossSection::CS_SIMULATION_WELL; crossSection->simulationWell = m_wellPath; - m_crossSectionCollection->crossSections.push_back(crossSection); - - m_crossSectionCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + m_crossSectionCollection->appendCrossSection(crossSection); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index 90764d6501..96f2b68794 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -23,8 +23,6 @@ #include "RimCrossSectionCollection.h" #include "RimWellPath.h" -#include "RiuMainWindow.h" - #include "cafCmdExecCommandManager.h" #include "cafSelectionManager.h" @@ -123,10 +121,7 @@ void RicNewWellPathCrossSectionFeatureCmd::redo() crossSection->type = RimCrossSection::CS_WELL_PATH; crossSection->wellPath = m_wellPath; - m_crossSectionCollection->crossSections.push_back(crossSection); - - m_crossSectionCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + m_crossSectionCollection->appendCrossSection(crossSection); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 6b335c716c..30db7a11a3 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -22,6 +22,7 @@ #include "RicDeleteItemExecData.h" #include "RimCellRangeFilterCollection.h" +#include "RimCrossSectionCollection.h" #include "RimEclipsePropertyFilterCollection.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimProject.h" @@ -102,6 +103,13 @@ void RicDeleteItemExec::redo() view->scheduleCreateDisplayModelAndRedraw(); } + RimCrossSectionCollection* crossSectionColl; + parentObj->firstAnchestorOrThisOfType(crossSectionColl); + if (view && crossSectionColl) + { + view->scheduleCreateDisplayModelAndRedraw(); + } + RimWellPathCollection* wellPathColl; parentObj->firstAnchestorOrThisOfType(wellPathColl); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 767b3fcae7..0fcf8dd352 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -21,6 +21,8 @@ #include "RimCrossSection.h" #include "RivCrossSectionPartMgr.h" +#include "RiuMainWindow.h" +#include "RimView.h" CAF_PDM_SOURCE_INIT(RimCrossSectionCollection, "CrossSectionCollection"); @@ -32,8 +34,8 @@ RimCrossSectionCollection::RimCrossSectionCollection() { CAF_PDM_InitObject("Cross Sections", ":/undefined_image.png", "", ""); - CAF_PDM_InitFieldNoDefault(&crossSections, "CrossSections", "Cross Sections", "", "", ""); - crossSections.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_crossSections, "CrossSections", "Cross Sections", "", "", ""); + m_crossSections.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); @@ -52,9 +54,9 @@ caf::PdmFieldHandle* RimCrossSectionCollection::objectToggleField() //-------------------------------------------------------------------------------------------------- void RimCrossSectionCollection::applySingleColorEffect() { - for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { - RimCrossSection* cs = crossSections[csIdx]; + RimCrossSection* cs = m_crossSections[csIdx]; cs->crossSectionPartMgr()->applySingleColorEffect(); } } @@ -64,9 +66,9 @@ void RimCrossSectionCollection::applySingleColorEffect() //-------------------------------------------------------------------------------------------------- void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) { - for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { - RimCrossSection* cs = crossSections[csIdx]; + RimCrossSection* cs = m_crossSections[csIdx]; cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex, cellResultColors); } } @@ -76,9 +78,9 @@ void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex, RimE //-------------------------------------------------------------------------------------------------- void RimCrossSectionCollection::appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { - for (size_t csIdx = 0; csIdx < crossSections.size(); ++csIdx) + for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { - RimCrossSection* cs = crossSections[csIdx]; + RimCrossSection* cs = m_crossSections[csIdx]; if (cs->isActive) { cs->crossSectionPartMgr()->appendNativeCrossSectionFacesToModel(model, scaleTransform); @@ -86,3 +88,21 @@ void RimCrossSectionCollection::appendPartsToModel(cvf::ModelBasicList* model, c } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSectionCollection::appendCrossSection(RimCrossSection* crossSection) +{ + m_crossSections.push_back(crossSection); + + updateConnectedEditors(); + RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + + RimView* rimView = NULL; + firstAnchestorOrThisOfType(rimView); + if (rimView) + { + rimView->scheduleCreateDisplayModelAndRedraw(); + } +} diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h index 13baa1efe1..9bd17cba19 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -44,15 +44,21 @@ class RimCrossSectionCollection : public caf::PdmObject RimCrossSectionCollection(); caf::PdmField isActive; - caf::PdmChildArrayField crossSections; + + void appendCrossSection(RimCrossSection* crossSection); + + + // Visualization interface void applySingleColorEffect(); void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); - void appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); protected: //virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); //virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); virtual caf::PdmFieldHandle* objectToggleField(); + +private: + caf::PdmChildArrayField m_crossSections; }; From f3a1f21e874ae514bb2425d62baf43de7a4344e8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 18:56:23 +0100 Subject: [PATCH 091/290] (#657) Hide unused enums and handle isActive for cross section collection --- .../ProjectDataModel/RimCrossSection.cpp | 27 ++++++++++++------- .../RimCrossSectionCollection.cpp | 18 +++++++++++++ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 8b04b98e96..ff067ea898 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -37,8 +37,8 @@ template<> void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() { addItem(RimCrossSection::CS_WELL_PATH, "CS_WELL_PATH", "Well Path"); - addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); - addItem(RimCrossSection::CS_USER_DEFINED, "CS_USER_DEFINED", "User defined"); +// addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); +// addItem(RimCrossSection::CS_USER_DEFINED, "CS_USER_DEFINED", "User defined"); setDefault(RimCrossSection::CS_WELL_PATH); } @@ -79,13 +79,20 @@ RimCrossSection::RimCrossSection() //-------------------------------------------------------------------------------------------------- void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { - m_crossSectionPartMgr = NULL; - - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - if (rimView) + if (changedField == &isActive || + changedField == &type || + changedField == &direction || + changedField == &wellPath || + changedField == &simulationWell) { - rimView->scheduleCreateDisplayModelAndRedraw(); + m_crossSectionPartMgr = NULL; + + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + if (rimView) + { + rimView->scheduleCreateDisplayModelAndRedraw(); + } } } @@ -104,11 +111,11 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& } else if (type == CS_SIMULATION_WELL) { - uiOrdering.add(&simulationWell); + //uiOrdering.add(&simulationWell); } else { - + // User defined poly line } uiOrdering.setForgetRemainingFields(true); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 0fcf8dd352..0aca5842d5 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -78,6 +78,8 @@ void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex, RimE //-------------------------------------------------------------------------------------------------- void RimCrossSectionCollection::appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { + if (!isActive) return; + for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { RimCrossSection* cs = m_crossSections[csIdx]; @@ -106,3 +108,19 @@ void RimCrossSectionCollection::appendCrossSection(RimCrossSection* crossSection rimView->scheduleCreateDisplayModelAndRedraw(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSectionCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &isActive) + { + RimView* rimView = NULL; + firstAnchestorOrThisOfType(rimView); + if (rimView) + { + rimView->scheduleCreateDisplayModelAndRedraw(); + } + } +} From 115e0cb660b78e8c55fddfe254eb972bf72f3402 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 18:57:32 +0100 Subject: [PATCH 092/290] (#657) Improved 3D view commands and context menu creation --- .../RicNewWellPathCrossSectionFeature.cpp | 17 ++---- .../RicNewWellPathCrossSectionFeature.h | 7 --- .../RimContextCommandBuilder.cpp | 30 +++++++++ .../RimContextCommandBuilder.h | 5 +- .../RimCrossSectionCollection.h | 3 +- .../UserInterface/RiuViewerCommands.cpp | 61 +++---------------- 6 files changed, 51 insertions(+), 72 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index 96f2b68794..a16e1dd513 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -19,9 +19,12 @@ #include "RicNewWellPathCrossSectionFeature.h" +#include "RiaApplication.h" + #include "RimCrossSection.h" #include "RimCrossSectionCollection.h" #include "RimWellPath.h" +#include "RimView.h" #include "cafCmdExecCommandManager.h" #include "cafSelectionManager.h" @@ -36,7 +39,6 @@ CAF_CMD_SOURCE_INIT(RicNewWellPathCrossSectionFeature, "RicNewWellPathCrossSecti /// //-------------------------------------------------------------------------------------------------- RicNewWellPathCrossSectionFeature::RicNewWellPathCrossSectionFeature() - : m_view(NULL) { } @@ -54,7 +56,8 @@ bool RicNewWellPathCrossSectionFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) { - if (!m_view) return; + RimView* activeView = RiaApplication::instance()->activeReservoirView(); + if (!activeView) return; std::vector collection; caf::SelectionManager::instance()->objectsByType(&collection); @@ -62,7 +65,7 @@ void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) RimWellPath* wellPath = collection[0]; - RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(m_view->crossSectionCollection, wellPath); + RicNewWellPathCrossSectionFeatureCmd* cmd = new RicNewWellPathCrossSectionFeatureCmd(activeView->crossSectionCollection, wellPath); caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); } @@ -75,14 +78,6 @@ void RicNewWellPathCrossSectionFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setText("New Cross Section"); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicNewWellPathCrossSectionFeature::setView(RimView* view) -{ - m_view = view; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h index 063ab0c9dd..39ffa243b5 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.h @@ -19,8 +19,6 @@ #pragma once -#include "RimView.h" - #include "cafCmdFeature.h" #include "cafCmdExecuteCommand.h" #include "cafPdmPointer.h" @@ -59,16 +57,11 @@ class RicNewWellPathCrossSectionFeature : public caf::CmdFeature public: RicNewWellPathCrossSectionFeature(); - void setView(RimView* view); - protected: // Overrides virtual bool isCommandEnabled(); virtual void onActionTriggered( bool isChecked ); virtual void setupActionLook( QAction* actionToSetup ); - -private: - caf::PdmPointer m_view; }; diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index 60f6f5c3b2..5ceea5fe05 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -57,8 +57,13 @@ #include "cafSelectionManager.h" #include "cvfAssert.h" +#include "cafCmdFeatureManager.h" +#include "cafCmdFeature.h" + #include +#include + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -207,6 +212,7 @@ QStringList RimContextCommandBuilder::commandsFromSelection() { commandIds << "RicNewWellLogFileCurveFeature"; commandIds << "RicNewWellLogCurveExtractionFeature"; + commandIds << "RicNewWellPathCrossSectionFeature"; commandIds << "RicWellPathDeleteFeature"; } else if (dynamic_cast(uiItem)) @@ -291,3 +297,27 @@ QStringList RimContextCommandBuilder::commandsFromSelection() return commandIds; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContextCommandBuilder::appendCommandsToMenu(const QStringList& commandIds, QMenu* menu) +{ + CVF_ASSERT(menu); + + caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); + for (int i = 0; i < commandIds.size(); i++) + { + caf::CmdFeature* feature = commandManager->getCommandFeature(commandIds[i].toStdString()); + CVF_ASSERT(feature); + + if (feature->canFeatureBeExecuted()) + { + QAction* act = commandManager->action(commandIds[i]); + CVF_ASSERT(act); + + menu->addAction(act); + } + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h index be9a221762..abe8fd2947 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h @@ -21,6 +21,8 @@ #include +class QMenu; + //================================================================================================== /// /// @@ -28,5 +30,6 @@ class RimContextCommandBuilder { public: - static QStringList commandsFromSelection(); + static QStringList commandsFromSelection(); + static void appendCommandsToMenu(const QStringList& commandIds, QMenu* menu); }; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h index 9bd17cba19..72a10ed33e 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -55,8 +55,7 @@ class RimCrossSectionCollection : public caf::PdmObject void appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); protected: - //virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - //virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName); + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual caf::PdmFieldHandle* objectToggleField(); private: diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 567bf582a4..7888484c72 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -36,6 +36,7 @@ #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" +#include "RimContextCommandBuilder.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipsePropertyFilter.h" @@ -136,7 +137,6 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) if (m_viewer->rayPick(winPosX, winPosY, &hitItems)) { extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &faceIndex, &nncFirstHitPart, NULL); - updateSelectionFromPickedPart(firstHitPart); } if (firstHitPart && faceIndex != cvf::UNDEFINED_UINT) @@ -222,6 +222,8 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) } } + QStringList commandIds; + // Well log curve creation commands if (firstHitPart && firstHitPart->sourceInfo()) { @@ -233,26 +235,11 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) RimWellPath* wellPath = wellPathSourceInfo->wellPath(); if (wellPath) { + caf::SelectionManager::instance()->setSelectedItem(wellPath); - RicNewWellLogFileCurveFeature* newWellLogFileCurveFeature = dynamic_cast(commandManager->getCommandFeature("RicNewWellLogFileCurveFeature")); - if (newWellLogFileCurveFeature && newWellLogFileCurveFeature->canFeatureBeExecuted()) - { - menu.addAction(newWellLogFileCurveFeature->action()); - } - - RicNewWellLogCurveExtractionFeature* newExtractionCurveFeature = dynamic_cast(commandManager->getCommandFeature("RicNewWellLogCurveExtractionFeature")); - if (newExtractionCurveFeature && newExtractionCurveFeature->canFeatureBeExecuted()) - { - menu.addAction(newExtractionCurveFeature->action()); - } - - RicNewWellPathCrossSectionFeature* newWellPathCrossSectionFeature = dynamic_cast(commandManager->getCommandFeature("RicNewWellPathCrossSectionFeature")); - if (newWellPathCrossSectionFeature) - { - newWellPathCrossSectionFeature->setView(m_reservoirView); - - menu.addAction(newWellPathCrossSectionFeature->action()); - } + commandIds << "RicNewWellLogFileCurveFeature"; + commandIds << "RicNewWellLogCurveExtractionFeature"; + commandIds << "RicNewWellPathCrossSectionFeature"; } } @@ -264,11 +251,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) { caf::SelectionManager::instance()->setSelectedItem(well); - RicNewSimWellCrossSectionFeature* newSimWellCrossSectionFeature = dynamic_cast(commandManager->getCommandFeature("RicNewSimWellCrossSectionFeature")); - if (newSimWellCrossSectionFeature && newSimWellCrossSectionFeature->canFeatureBeExecuted()) - { - menu.addAction(newSimWellCrossSectionFeature->action()); - } + commandIds << "RicNewSimWellCrossSectionFeature"; } } } @@ -276,38 +259,14 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) // View Link commands if (!firstHitPart) { - QStringList commandIds; - commandIds << "RicLinkViewFeature"; commandIds << "RicUnLinkViewFeature"; commandIds << "RicShowLinkOptionsFeature"; commandIds << "RicSetMasterViewFeature"; - - bool firstLinkAction = true; - - caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); - for (int i = 0; i < commandIds.size(); i++) - { - caf::CmdFeature* feature = commandManager->getCommandFeature(commandIds[i].toStdString()); - if (feature->canFeatureBeExecuted()) - { - QAction* act = commandManager->action(commandIds[i]); - CVF_ASSERT(act); - - if (firstLinkAction) - { - if (menu.actions().size() > 0) - { - menu.addSeparator(); - } - firstLinkAction = false; - } - - menu.addAction(act); - } - } } + RimContextCommandBuilder::appendCommandsToMenu(commandIds, &menu); + if (menu.actions().size() > 0) { menu.exec(event->globalPos()); From ca5dc6e80a39decb6e1d3f122d4e5c0fd1fc7dd6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 19:04:28 +0100 Subject: [PATCH 093/290] Removed unused function --- ApplicationCode/UserInterface/RiuViewerCommands.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 7888484c72..b634f366d7 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -69,8 +69,6 @@ #include "RivWellPipeSourceInfo.h" #include "cafCmdExecCommandManager.h" -#include "cafCmdFeature.h" -#include "cafCmdFeatureManager.h" #include "cafPdmUiTreeView.h" #include "cafSelectionManager.h" @@ -227,8 +225,6 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) // Well log curve creation commands if (firstHitPart && firstHitPart->sourceInfo()) { - caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); - const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (wellPathSourceInfo) { From b356be946479627dfcfff4a8a7d743fa0d7fb6e6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 19 Nov 2015 19:50:06 +0100 Subject: [PATCH 094/290] (#629) Fixed crash when opening an Odb-file in no-odb version of ResInsight --- ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index a58f74bd0a..366c2d1e82 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -97,10 +97,8 @@ RimGeoMechView* RimGeoMechCase::createAndAddReservoirView() bool RimGeoMechCase::openGeoMechCase(std::string* errorMessage) { // If read already, return - if (this->m_geoMechCaseData.notNull()) return true; - if (!QFile::exists(m_caseFileName())) { return false; @@ -108,7 +106,15 @@ bool RimGeoMechCase::openGeoMechCase(std::string* errorMessage) m_geoMechCaseData = new RigGeoMechCaseData(m_caseFileName().toStdString()); - return m_geoMechCaseData->openAndReadFemParts(errorMessage); + bool fileOpenSuccess = m_geoMechCaseData->openAndReadFemParts(errorMessage); + if (!fileOpenSuccess) + { + // If opening failed, release all data + // Also, several places is checked for this data to validate availability of data + m_geoMechCaseData = NULL; + } + + return fileOpenSuccess; } //-------------------------------------------------------------------------------------------------- From b26d199815109b9fc49f9df36349ebf0db32022c Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 20 Nov 2015 09:12:07 +0100 Subject: [PATCH 095/290] (#639) Show E (x,1) on axis label As the space is limited, the text is compressed to "E-x1", "N-y2", "Z-3" --- .../ProjectDataModel/RimGeoMechView.cpp | 16 ++++++++++ .../ProjectDataModel/RimGeoMechView.h | 2 ++ ApplicationCode/UserInterface/RiuViewer.cpp | 32 ++++++++++++++++--- ApplicationCode/UserInterface/RiuViewer.h | 4 +++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 4fd8e0c4e7..9794c1dd0c 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -155,6 +155,8 @@ void RimGeoMechView::loadDataAndUpdate() progress.setProgressDescription("Create Display model"); updateViewerWidget(); + setCustomAxisCrossLabels(); + this->geoMechPropertyFilterCollection()->loadAndInitializePropertyFilters(); this->scheduleCreateDisplayModelAndRedraw(); @@ -481,6 +483,8 @@ void RimGeoMechView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { bool generateDisplayModel = (viewer() == NULL); updateViewerWidget(); + setCustomAxisCrossLabels(); + if (generateDisplayModel) { scheduleCreateDisplayModelAndRedraw(); @@ -512,6 +516,18 @@ void RimGeoMechView::initAfterRead() this->updateUiIconFromToggleField(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechView::setCustomAxisCrossLabels() +{ + // Minimalistic - size of axis cross does not have to be adjusted + if (m_viewer) m_viewer->setAxisLabels("E-x1", "N-y2", "Z-3"); + + // A bit larger - size of axis cross is slightly larger + //if (m_viewer) m_viewer->setAxisLabels("E(x,1)", "N(y,2)", "Z(3)"); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index 823e173b3d..4fe6dceea7 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -101,6 +101,8 @@ class RimGeoMechView : public RimView virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void initAfterRead(); + void setCustomAxisCrossLabels(); + virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index cf76402a35..4bdc8831e2 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -77,10 +77,10 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) : caf::Viewer(format, parent) { cvf::Font* standardFont = RiaApplication::instance()->standardFont(); - cvf::OverlayAxisCross* axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); - axisCross->setAxisLabels("E", "N", "Z"); - axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); - m_mainRendering->addOverlayItem(axisCross); + m_axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); + m_axisCross->setAxisLabels("E", "N", "Z"); + m_axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); + m_mainRendering->addOverlayItem(m_axisCross.p()); this->enableOverlyPainting(true); this->setReleaseOGLResourcesEachFrame(true); @@ -571,3 +571,27 @@ cvf::Model* RiuViewer::gridBoxModel() const { return m_gridBoxGenerator->model(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel) +{ + m_axisCross->setAxisLabels(xLabel, yLabel, zLabel); + + size_t maxAxisLabelLength = xLabel.size(); + if (yLabel.size() > maxAxisLabelLength) maxAxisLabelLength = yLabel.size(); + if (zLabel.size() > maxAxisLabelLength) maxAxisLabelLength = zLabel.size(); + + if (maxAxisLabelLength > 4) + { + if (maxAxisLabelLength < 6) + { + m_axisCross->setSize(cvf::Vec2ui(140, 140)); + } + else if (maxAxisLabelLength < 8) + { + m_axisCross->setSize(cvf::Vec2ui(160, 160)); + } + } +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 04b5c89376..3a52f93e66 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -42,6 +42,7 @@ namespace cvf class Model; class OverlayItem; class Part; + class OverlayAxisCross; } //================================================================================================== @@ -84,6 +85,8 @@ class RiuViewer : public caf::Viewer void setCurrentFrame(int frameIndex); + void setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel); + public slots: virtual void slotSetCurrentFrame(int frameIndex); virtual void slotEndAnimation(); @@ -109,6 +112,7 @@ public slots: QCDEStyle* m_progressBarStyle; + cvf::ref m_axisCross; cvf::Collection m_visibleLegends; caf::PdmPointer m_rimView; From 1f91405c501ae1bf083f290b480d66b4800e27e3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 20 Nov 2015 10:49:23 +0100 Subject: [PATCH 096/290] [Fwk] Propagate return value from QFile::open in writeFile() to caller --- Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.cpp | 6 ++++-- Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.cpp index baa4fff955..606c07c773 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.cpp @@ -98,13 +98,15 @@ void PdmDocument::readFile(QIODevice* xmlFile) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void PdmDocument::writeFile() +bool PdmDocument::writeFile() { QFile xmlFile(fileName); if (!xmlFile.open(QIODevice::WriteOnly )) - return; + return false; writeFile(&xmlFile); + + return true; } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.h index 17dafdab4b..1acfeb042a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmDocument.h @@ -56,7 +56,7 @@ class PdmDocument: public PdmObject PdmField fileName; void readFile(); - void writeFile(); + bool writeFile(); void readFile(QIODevice* device); void writeFile(QIODevice* device); From ac714ca2eac7257b71a794bbb4f6fa5affac5068 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 20 Nov 2015 10:50:23 +0100 Subject: [PATCH 097/290] (#630) Give warning if user tries to save project to a read only file Add saved file to recent file list --- ApplicationCode/Application/RiaApplication.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 855b10e198..cbcf2c327a 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -569,11 +569,20 @@ bool RiaApplication::saveProjectPromptForFileName() bool RiaApplication::saveProjectAs(const QString& fileName) { m_project->fileName = fileName; - m_project->writeFile(); + + if (!m_project->writeFile()) + { + QMessageBox::warning(NULL, "Error when saving project file", QString("Not possible to save project file. Make sure you have sufficient access rights.\n\nProject file location : %1").arg(fileName)); + + return false; + } m_preferences->lastUsedProjectFileName = fileName; caf::PdmSettings::writeFieldsToApplicationStore(m_preferences); + RiuMainWindow* mainWnd = RiuMainWindow::instance(); + mainWnd->addRecentFiles(fileName); + return true; } From 94b713d3bfb222c6f3d50d25d6b24563889cb491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 20 Nov 2015 08:45:23 +0100 Subject: [PATCH 098/290] Removed unused code --- .../RivCrossSectionGeometryGenerator.cpp | 89 +++---------------- 1 file changed, 10 insertions(+), 79 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 7abbea18b5..2ce3224d0d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -489,60 +489,6 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx } } - -#if 0 -static void planeHexCellIntersectionOnTriangles(const cvf::Plane& plane, - const cvf::Vec3d hexCorners[8], - const int hexCornersIds[8], - std::vector* polygon) -{ - CVF_ASSERT(polygon != NULL); - - int intersectionCount = 0; - - std::vector > polygonEdges; - for (int face = 0; face < 6 ; ++face) - { - cvf::ubyte faceVertexIndices[4]; - cvf::StructGridInterface::cellFaceVertexIndices(static_cast(face), faceVertexIndices); - - ClipVx newVx1; - ClipVx newVx2; - - bool isClipped = planeTriangleIntersection(plane, - hexCorners[faceVertexIndices[0]], hexCornersIds[faceVertexIndices[0]], - hexCorners[faceVertexIndices[1]], hexCornersIds[faceVertexIndices[1]], - hexCorners[faceVertexIndices[2]], hexCornersIds[faceVertexIndices[2]], - &newVx1, &newVx2); - if (isClipped) - { - polygonEdges.push_back(std::make_pair(newVx1, newVx2)); - } - - isClipped = planeTriangleIntersection(plane, - hexCorners[faceVertexIndices[0]], hexCornersIds[faceVertexIndices[0]], - hexCorners[faceVertexIndices[2]], hexCornersIds[faceVertexIndices[2]], - hexCorners[faceVertexIndices[3]], hexCornersIds[faceVertexIndices[3]], - &newVx1, &newVx2); - if (isClipped) - { - polygonEdges.push_back(std::make_pair(newVx1, newVx2)); - } - - } - - if (polygonEdges.size >= 3) - { - // Sort polygon edges in polygon order. - // Do this by finding polygon vxes cutting the same edge. - // And grow from the first edge - (*polygon).push_back(polygonEdges[0].first); - (*polygon).push_back(polygonEdges[0].second); - //for () - } -} -#endif - //-------------------------------------------------------------------------------------------------- /// Will return the intersection point. If the plane is outside the line, it returns the closest line endpoint //-------------------------------------------------------------------------------------------------- @@ -1091,34 +1037,21 @@ void RivCrossSectionGeometryGenerator::calculateArrays() hexCornersIds, &triangleClipVxes, &isTriangleEdgeCellContour); - - -#if 0 - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) - { - // Accumulate to geometry - int triVxIdx = tIdx*3; - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+0].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+1].vx - displayOffset)); - triangleVertices.push_back(cvf::Vec3f(triangleVxes[triVxIdx+2].vx - displayOffset)); - - m_triangleToCellIdxMap.push_back(globalCellIdx); - } -#else - std::vector clippedTriangleVxes; std::vector isClippedTriEdgeCellContour; - clipTrianglesBetweenTwoParallelPlanes(triangleClipVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); + clipTrianglesBetweenTwoParallelPlanes(triangleClipVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, + &clippedTriangleVxes, &isClippedTriEdgeCellContour); int clippedTriangleCount = static_cast(clippedTriangleVxes.size())/3; - // Accumulate triangle vertices for (int tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) { int triVxIdx = tIdx*3; + // Accumulate triangle vertices + cvf::Vec3f p0(clippedTriangleVxes[triVxIdx+0].vx - displayOffset); cvf::Vec3f p1(clippedTriangleVxes[triVxIdx+1].vx - displayOffset); cvf::Vec3f p2(clippedTriangleVxes[triVxIdx+2].vx - displayOffset); @@ -1146,10 +1079,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() cellBorderLineVxes.push_back(p0); } - // Mapping to data + // Mapping to cell index m_triangleToCellIdxMap.push_back(globalCellIdx); + // Interpolation from nodes for (int i = 0; i < 3; ++i) { ClipVx cvx = clippedTriangleVxes[triVxIdx+i]; @@ -1157,8 +1091,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() { m_triangleVxInterPolationData.push_back( VxInterPolData(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1, - -1, -1, 0.0, - 0.0)); + -1, -1, 0.0, + 0.0)); } else { @@ -1167,16 +1101,13 @@ void RivCrossSectionGeometryGenerator::calculateArrays() m_triangleVxInterPolationData.push_back( VxInterPolData(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, - cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, - cvx.normDistFromEdgeVx1)); + cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, + cvx.normDistFromEdgeVx1)); } } } -#endif - } - } m_triangleVxes->assign(triangleVertices); From 919ba80bc663fb4335ec30a99445eee1ad086006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 20 Nov 2015 09:26:27 +0100 Subject: [PATCH 099/290] Improved comments and some renaming --- .../RivCrossSectionGeometryGenerator.cpp | 46 +++++++++---------- .../RivCrossSectionGeometryGenerator.h | 22 ++++----- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 2ce3224d0d..eec9c04b32 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -56,7 +56,8 @@ RivCrossSectionGeometryGenerator::~RivCrossSectionGeometryGenerator() /// \param b End of line segment /// \param intersection Returns intersection point along the infinite line defined by a-b /// \param normalizedDistFromA Returns the normalized (0..1) position from a to b of the intersection point. -/// Will return values along the complete line, and HUGE_VAL if plane and line are parallel. +/// Will return values along the infinite line defined by the a-b direcion, +/// and HUGE_VAL if plane and line are parallel. /// /// \return True if line segment intersects the plane //-------------------------------------------------------------------------------------------------- @@ -97,33 +98,30 @@ struct ClipVx }; //-------------------------------------------------------------------------------------------------- -/// Returns whether the triangle was hit by the plane -/// isMostVxesOnPositiveSide returns true if all or two of the vxes is on the positive side of the plane -/// newVx1/2.vx1ClippedEdge returns the index of the single vx that is alone on one side +/// Returns whether the triangle was hit by the plane. +/// isMostVxesOnPositiveSide returns true if all or two of the vxes is on the positive side of the plane. +/// newVx1/2.vx1ClippedEdge returns the index of the single vx that is alone on one side of the plane. /// Going newVx1 to newVx2 will make the top triangle same winding as the original triangle, -/// and thus the quad opposite winding +/// and the quad opposite winding -// Except for the trivial cases where all vertices are in front -// or behind plane, these are the permutations +// The permutations except for the trivial cases where all vertices are in front or behind plane: // -// Single vertex on positive side of plane -// => return a triangle +// Single vertex on positive side of plane => isMostVxesOnPositiveSide = false // -// +\ /\c /\c /+ /\c . +// +\ /\3 /\3 /+ /\3 . // \ / \ / \ / + / \ + . -// \ \ / \/ ---/----\--- . +// \2 \ / \/1 __1/____\2__ . // / \ \ / /\ / \ . -// a/___\____\b a/_____/__\b a/________\b . +// 1/___\1___\2 1/____2/__\2 1/________\2 . // +\ /+ // -// Two vertices vertex on positive side of plane -// => return a quad +// Two vertices vertex on positive side of plane => isMostVxesOnPositiveSide = true // -// \+ /\c /\c +/ /\c . +// \+ /\3 /\3 +/ /\3 . // \ / \ / \ / / \ . -// \ \ / \/ ___/____\___ . +// \2 \ / \/1 __1/____\2__ . // / \ \ / /\ + / \ + . -// a/___\____\b a/_____/__\b a/________\b . +// 1/___\1___\2 1/____2/__\2 1/________\2 . // \+ +/ //-------------------------------------------------------------------------------------------------- @@ -1006,8 +1004,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 - plane.normal() ); - std::vector triangleClipVxes; - triangleClipVxes.reserve(5*3); + std::vector hexPlaneCutTriangleVxes; + hexPlaneCutTriangleVxes.reserve(5*3); std::vector isTriangleEdgeCellContour; isTriangleEdgeCellContour.reserve(5*3); @@ -1017,7 +1015,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (m_mainGrid->cells()[globalCellIdx].isInvalid()) continue; - triangleClipVxes.clear(); + hexPlaneCutTriangleVxes.clear(); cvf::Vec3d cellCorners[8]; m_mainGrid->cellCornerVertices(globalCellIdx, cellCorners); @@ -1035,13 +1033,13 @@ void RivCrossSectionGeometryGenerator::calculateArrays() int triangleCount = planeHexIntersectionMC(plane, cellCorners, hexCornersIds, - &triangleClipVxes, + &hexPlaneCutTriangleVxes, &isTriangleEdgeCellContour); std::vector clippedTriangleVxes; std::vector isClippedTriEdgeCellContour; - clipTrianglesBetweenTwoParallelPlanes(triangleClipVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, + clipTrianglesBetweenTwoParallelPlanes(hexPlaneCutTriangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); int clippedTriangleCount = static_cast(clippedTriangleVxes.size())/3; @@ -1096,8 +1094,8 @@ void RivCrossSectionGeometryGenerator::calculateArrays() } else { - ClipVx cvx1 = triangleClipVxes[cvx.clippedEdgeVx1Id]; - ClipVx cvx2 = triangleClipVxes[cvx.clippedEdgeVx2Id]; + ClipVx cvx1 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx1Id]; + ClipVx cvx2 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx2Id]; m_triangleVxInterPolationData.push_back( VxInterPolData(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index f3e1dc08c1..8c963bda90 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -75,17 +75,17 @@ class RivCrossSectionGeometryGenerator : public cvf::Object struct VxInterPolData { - explicit VxInterPolData(int vx1, int vx2, double normDistFrom1, - int vx3, int vx4, double normDistFrom3, - double normDistFrom12) - : vx1Id(vx1), - weight1((float)(1.0 - normDistFrom1 - normDistFrom12 + normDistFrom1*normDistFrom12)), - vx2Id(vx2), - weight2((float)(normDistFrom1 - normDistFrom1*normDistFrom12)), - vx3Id(vx3), - weight3((float)(normDistFrom12 - normDistFrom3*normDistFrom12)), - vx4Id(vx4), - weight4((float)(normDistFrom3*normDistFrom12)) + explicit VxInterPolData(int edge1Vx1, int edge1Vx2, double normDistFromE1V1, + int edge2Vx1, int edge2Vx2, double normDistFromE2V1, + double normDistFromE1Cut) + : vx1Id(edge1Vx1), + weight1((float)(1.0 - normDistFromE1V1 - normDistFromE1Cut + normDistFromE1V1*normDistFromE1Cut)), + vx2Id(edge1Vx2), + weight2((float)(normDistFromE1V1 - normDistFromE1V1*normDistFromE1Cut)), + vx3Id(edge2Vx1), + weight3((float)(normDistFromE1Cut - normDistFromE2V1*normDistFromE1Cut)), + vx4Id(edge2Vx2), + weight4((float)(normDistFromE2V1*normDistFromE1Cut)) {} int vx1Id; From e593361b917edb983dfc1b966d0102e6305fa584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 20 Nov 2015 12:02:43 +0100 Subject: [PATCH 100/290] (#166) Refactoring to make way for geomech cross sections --- .../RivCrossSectionGeometryGenerator.cpp | 132 +++++++++++++----- .../RivCrossSectionGeometryGenerator.h | 98 +++++++++---- 2 files changed, 165 insertions(+), 65 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index eec9c04b32..5f243c4972 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -91,8 +91,8 @@ struct ClipVx cvf::Vec3d vx; double normDistFromEdgeVx1; - int clippedEdgeVx1Id; - int clippedEdgeVx2Id; + size_t clippedEdgeVx1Id; + size_t clippedEdgeVx2Id; bool isVxIdsNative; }; @@ -126,9 +126,9 @@ struct ClipVx //-------------------------------------------------------------------------------------------------- bool planeTriangleIntersection(const cvf::Plane& plane, - const cvf::Vec3d& p1, int p1Id, - const cvf::Vec3d& p2, int p2Id, - const cvf::Vec3d& p3, int p3Id, + const cvf::Vec3d& p1, size_t p1Id, + const cvf::Vec3d& p2, size_t p2Id, + const cvf::Vec3d& p3, size_t p3Id, ClipVx* newVx1, ClipVx* newVx2, bool * isMostVxesOnPositiveSide) { @@ -251,12 +251,12 @@ void clipTrianglesBetweenTwoParallelPlanes(const std::vector &triangleVx std::vector *clippedTriangleVxes, std::vector *isClippedTriEdgeCellContour) { - int triangleCount = static_cast(triangleVxes.size())/3; + size_t triangleCount = triangleVxes.size()/3; - for (int tIdx = 0; tIdx < triangleCount; ++tIdx) + for (size_t tIdx = 0; tIdx < triangleCount; ++tIdx) { - int triVxIdx = tIdx*3; + size_t triVxIdx = tIdx*3; ClipVx newVx1OnP1; newVx1OnP1.isVxIdsNative = false; @@ -540,7 +540,7 @@ cvf::Vec3d planeLineIntersectionForMC(const cvf::Plane& plane, const cvf::Vec3d& //-------------------------------------------------------------------------------------------------- int planeHexIntersectionMC(const cvf::Plane& plane, const cvf::Vec3d cell[8], - const int hexCornersIds[8], + const size_t hexCornersIds[8], std::vector* triangleVxes, std::vector* isTriEdgeCellContour) { @@ -936,7 +936,7 @@ int planeHexIntersectionMC(const cvf::Plane& plane, for (uint tIdx = 0; tIdx < triangleCount; ++tIdx) { - int triVxIdx = 3*tIdx; + uint triVxIdx = 3*tIdx; int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx]; int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1]; int cubeEdgeIdx3 = triangleIndicesToCubeEdges[triVxIdx + 2 ]; @@ -948,7 +948,7 @@ int planeHexIntersectionMC(const cvf::Plane& plane, for (uint tIdx = 0; tIdx < triangleCount; ++tIdx) { - int triVxIdx = 3*tIdx; + uint triVxIdx = 3*tIdx; int cubeEdgeIdx1 = triangleIndicesToCubeEdges[triVxIdx]; int cubeEdgeIdx2 = triangleIndicesToCubeEdges[triVxIdx + 1]; @@ -974,8 +974,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() std::vector triangleVertices; std::vector cellBorderLineVxes; - cvf::Vec3d displayOffset = m_mainGrid->displayModelOffset(); - cvf::BoundingBox gridBBox = m_mainGrid->boundingBox(); + EclipseCrossSectionGrid eclHexGrid(m_mainGrid.p()); + cvf::CrossSectionHexGridIntf* hexGrid = &eclHexGrid; + + cvf::Vec3d displayOffset = hexGrid->displayOffset(); + cvf::BoundingBox gridBBox = hexGrid->boundingBox(); size_t lineCount = m_adjustedPolyline.size(); for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) @@ -993,7 +996,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() sectionBBox.add(p2 - m_extrusionDirection*maxSectionHeight); std::vector columnCellCandidates; - m_mainGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); + hexGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); cvf::Plane plane; plane.setFromPoints(p1, p2, p2 + m_extrusionDirection*maxSectionHeight); @@ -1008,31 +1011,22 @@ void RivCrossSectionGeometryGenerator::calculateArrays() hexPlaneCutTriangleVxes.reserve(5*3); std::vector isTriangleEdgeCellContour; isTriangleEdgeCellContour.reserve(5*3); + cvf::Vec3d cellCorners[8]; + size_t cornerIndices[8]; for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) { size_t globalCellIdx = columnCellCandidates[cccIdx]; - if (m_mainGrid->cells()[globalCellIdx].isInvalid()) continue; + if (!hexGrid->useCell(globalCellIdx)) continue; hexPlaneCutTriangleVxes.clear(); - cvf::Vec3d cellCorners[8]; - m_mainGrid->cellCornerVertices(globalCellIdx, cellCorners); - - const caf::SizeTArray8& cornerIndices = m_mainGrid->cells()[globalCellIdx].cornerIndices(); - int hexCornersIds[8]; - hexCornersIds[0] = static_cast(cornerIndices[0]); - hexCornersIds[1] = static_cast(cornerIndices[1]); - hexCornersIds[2] = static_cast(cornerIndices[2]); - hexCornersIds[3] = static_cast(cornerIndices[3]); - hexCornersIds[4] = static_cast(cornerIndices[4]); - hexCornersIds[5] = static_cast(cornerIndices[5]); - hexCornersIds[6] = static_cast(cornerIndices[6]); - hexCornersIds[7] = static_cast(cornerIndices[7]); + hexGrid->cellCornerVertices(globalCellIdx, cellCorners); + hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); int triangleCount = planeHexIntersectionMC(plane, cellCorners, - hexCornersIds, + cornerIndices, &hexPlaneCutTriangleVxes, &isTriangleEdgeCellContour); @@ -1042,11 +1036,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() clipTrianglesBetweenTwoParallelPlanes(hexPlaneCutTriangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, &clippedTriangleVxes, &isClippedTriEdgeCellContour); - int clippedTriangleCount = static_cast(clippedTriangleVxes.size())/3; + size_t clippedTriangleCount = clippedTriangleVxes.size()/3; - for (int tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) + for (uint tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) { - int triVxIdx = tIdx*3; + uint triVxIdx = tIdx*3; // Accumulate triangle vertices @@ -1087,18 +1081,16 @@ void RivCrossSectionGeometryGenerator::calculateArrays() ClipVx cvx = clippedTriangleVxes[triVxIdx+i]; if (cvx.isVxIdsNative) { - m_triangleVxInterPolationData.push_back( - VxInterPolData(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1, - -1, -1, 0.0, - 0.0)); + m_triVxToCellCornerWeights.push_back( + RivVertexWeights(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1)); } else { ClipVx cvx1 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx1Id]; ClipVx cvx2 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx2Id]; - m_triangleVxInterPolationData.push_back( - VxInterPolData(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, + m_triVxToCellCornerWeights.push_back( + RivVertexWeights(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, cvx.normDistFromEdgeVx1)); @@ -1212,3 +1204,67 @@ void RivCrossSectionGeometryGenerator::adjustPolyline() } } } + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +EclipseCrossSectionGrid::EclipseCrossSectionGrid(const RigMainGrid * mainGrid) : m_mainGrid(mainGrid) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d EclipseCrossSectionGrid::displayOffset() const +{ + return m_mainGrid->displayModelOffset(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox EclipseCrossSectionGrid::boundingBox() const +{ + return m_mainGrid->boundingBox(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void EclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const +{ + m_mainGrid->findIntersectingCells(intersectingBB, intersectedCells); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool EclipseCrossSectionGrid::useCell(size_t cellIndex) const +{ + const RigCell& cell = m_mainGrid->cells()[cellIndex]; + + return !(cell.isInvalid() || (cell.subGrid() != NULL)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void EclipseCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const +{ + m_mainGrid->cellCornerVertices(cellIndex, cellCorners); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void EclipseCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const +{ + const caf::SizeTArray8& cornerIndicesSource = m_mainGrid->cells()[cellIndex].cornerIndices(); + memcpy(cornerIndices, cornerIndicesSource.data(), 8); +} diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 8c963bda90..c36685c30f 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -34,6 +34,75 @@ namespace cvf class DrawableGeo; } +#include "cvfBoundingBox.h" +namespace cvf { + +class CrossSectionHexGridIntf : public Object +{ +public: + virtual Vec3d displayOffset() const = 0; + virtual BoundingBox boundingBox() const = 0; + virtual void findIntersectingCells(const BoundingBox& intersectingBB, std::vector* intersectedCells) const = 0; + virtual bool useCell(size_t cellIndex) const = 0; + virtual void cellCornerVertices(size_t cellIndex, Vec3d cellCorners[8]) const = 0; + virtual void cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const = 0; +}; + +} + +class EclipseCrossSectionGrid : public cvf::CrossSectionHexGridIntf +{ +public: + EclipseCrossSectionGrid(const RigMainGrid * mainGrid); + + virtual cvf::Vec3d displayOffset() const; + virtual cvf::BoundingBox boundingBox() const; + virtual void findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const; + virtual bool useCell(size_t cellIndex) const; + virtual void cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const; + virtual void cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const; + +private: + cvf::cref m_mainGrid; +}; + +class RivVertexWeights +{ +public: + explicit RivVertexWeights(size_t edge1Vx1, size_t edge1Vx2, double normDistFromE1V1, + size_t edge2Vx1, size_t edge2Vx2, double normDistFromE2V1, + double normDistFromE1Cut) : m_count(4) + { + m_vxIds[0] = (edge1Vx1); + m_vxIds[1] = (edge1Vx2); + m_vxIds[2] = (edge2Vx1); + m_vxIds[3] = (edge2Vx2); + + m_weights[0] = ((float)(1.0 - normDistFromE1V1 - normDistFromE1Cut + normDistFromE1V1*normDistFromE1Cut)); + m_weights[1] = ((float)(normDistFromE1V1 - normDistFromE1V1*normDistFromE1Cut)); + m_weights[2] = ((float)(normDistFromE1Cut - normDistFromE2V1*normDistFromE1Cut)); + m_weights[3] = ((float)(normDistFromE2V1*normDistFromE1Cut)); + } + + explicit RivVertexWeights(size_t edge1Vx1, size_t edge1Vx2, double normDistFromE1V1) : m_count(2) + { + m_vxIds[0] = (edge1Vx1); + m_vxIds[1] = (edge1Vx2); + + m_weights[0] = ((float)(1.0 - normDistFromE1V1)); + m_weights[1] = ((float)(normDistFromE1V1)); + } + + int size() const { return m_count;} + size_t vxId(int idx) const { return m_vxIds[idx];} + float weight(int idx)const { return m_weights[idx];} + +private: + + size_t m_vxIds[4]; + float m_weights[4]; + int m_count; +}; class RivCrossSectionGeometryGenerator : public cvf::Object { @@ -51,6 +120,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object // Mapping between cells and geometry const std::vector& triangleToCellIndex() const; + const std::vector& triangleVxToCellCornerInterpolationWeights() const; // Generated geometry cvf::ref generateSurface(); @@ -73,32 +143,6 @@ class RivCrossSectionGeometryGenerator : public cvf::Object cvf::ref m_cellBorderLineVxes; std::vector m_triangleToCellIdxMap; - struct VxInterPolData - { - explicit VxInterPolData(int edge1Vx1, int edge1Vx2, double normDistFromE1V1, - int edge2Vx1, int edge2Vx2, double normDistFromE2V1, - double normDistFromE1Cut) - : vx1Id(edge1Vx1), - weight1((float)(1.0 - normDistFromE1V1 - normDistFromE1Cut + normDistFromE1V1*normDistFromE1Cut)), - vx2Id(edge1Vx2), - weight2((float)(normDistFromE1V1 - normDistFromE1V1*normDistFromE1Cut)), - vx3Id(edge2Vx1), - weight3((float)(normDistFromE1Cut - normDistFromE2V1*normDistFromE1Cut)), - vx4Id(edge2Vx2), - weight4((float)(normDistFromE2V1*normDistFromE1Cut)) - {} - - int vx1Id; - float weight1; - int vx2Id; - float weight2; - - int vx3Id; - float weight3; - int vx4Id; - float weight4; - }; - - std::vector m_triangleVxInterPolationData; + std::vector m_triVxToCellCornerWeights; }; From fbfd6fd21230843712361e65c1b41d1620a22006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 20 Nov 2015 13:26:41 +0100 Subject: [PATCH 101/290] (#166) More refactoring to support geomech cross sections --- .../RivCrossSectionGeometryGenerator.cpp | 107 +++++++----------- .../RivCrossSectionGeometryGenerator.h | 45 +++----- .../RivCrossSectionPartMgr.cpp | 52 ++++++++- .../RivCrossSectionPartMgr.h | 3 +- 4 files changed, 109 insertions(+), 98 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 5f243c4972..67070da78e 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -31,10 +31,10 @@ //-------------------------------------------------------------------------------------------------- RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector &polyline, const cvf::Vec3d& extrusionDirection, - const RigMainGrid* grid) + const RivCrossSectionHexGridIntf* grid) : m_polyLine(polyline), m_extrusionDirection(extrusionDirection), - m_mainGrid(grid) + m_hexGrid(grid) { m_triangleVxes = new cvf::Vec3fArray; m_cellBorderLineVxes = new cvf::Vec3fArray; @@ -968,17 +968,15 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (m_triangleVxes->size()) return; m_extrusionDirection.normalize(); + std::vector m_adjustedPolyline; - adjustPolyline(); + adjustPolyline(m_polyLine, m_extrusionDirection, &m_adjustedPolyline); std::vector triangleVertices; std::vector cellBorderLineVxes; - EclipseCrossSectionGrid eclHexGrid(m_mainGrid.p()); - cvf::CrossSectionHexGridIntf* hexGrid = &eclHexGrid; - - cvf::Vec3d displayOffset = hexGrid->displayOffset(); - cvf::BoundingBox gridBBox = hexGrid->boundingBox(); + cvf::Vec3d displayOffset = m_hexGrid->displayOffset(); + cvf::BoundingBox gridBBox = m_hexGrid->boundingBox(); size_t lineCount = m_adjustedPolyline.size(); for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) @@ -996,7 +994,7 @@ void RivCrossSectionGeometryGenerator::calculateArrays() sectionBBox.add(p2 - m_extrusionDirection*maxSectionHeight); std::vector columnCellCandidates; - hexGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); + m_hexGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); cvf::Plane plane; plane.setFromPoints(p1, p2, p2 + m_extrusionDirection*maxSectionHeight); @@ -1018,11 +1016,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() { size_t globalCellIdx = columnCellCandidates[cccIdx]; - if (!hexGrid->useCell(globalCellIdx)) continue; + if (!m_hexGrid->useCell(globalCellIdx)) continue; hexPlaneCutTriangleVxes.clear(); - hexGrid->cellCornerVertices(globalCellIdx, cellCorners); - hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); + m_hexGrid->cellCornerVertices(globalCellIdx, cellCorners); + m_hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); int triangleCount = planeHexIntersectionMC(plane, cellCorners, @@ -1142,41 +1140,28 @@ cvf::ref RivCrossSectionGeometryGenerator::createMeshDrawable( return geo; } - //-------------------------------------------------------------------------------------------------- -/// Calculates the texture coordinates in a "nearly" one dimentional texture. -/// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5 +/// Remove the lines from the polyline that is nearly parallel to the extrusion direction //-------------------------------------------------------------------------------------------------- -void RivCrossSectionGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, - const RigResultAccessor* resultAccessor, - const cvf::ScalarMapper* mapper) const +void RivCrossSectionGeometryGenerator::adjustPolyline(const std::vector& polyLine, + const cvf::Vec3d extrDir, + std::vector* adjustedPolyline) { - if (!resultAccessor) return; + size_t lineCount = polyLine.size(); + if (!polyLine.size()) return; - size_t numVertices = m_triangleVxes->size(); + adjustedPolyline->push_back(polyLine[0]); + cvf::Vec3d p1 = polyLine[0]; - textureCoords->resize(numVertices); - cvf::Vec2f* rawPtr = textureCoords->ptr(); - - double cellScalarValue; - cvf::Vec2f texCoord; - - int triangleCount = static_cast(m_triangleToCellIdxMap.size()); - -#pragma omp parallel for private(texCoord, cellScalarValue) - for (int tIdx = 0; tIdx < triangleCount; tIdx++) + for (size_t lIdx = 1; lIdx < lineCount; ++lIdx) { - cellScalarValue = resultAccessor->cellScalarGlobIdx(m_triangleToCellIdxMap[tIdx]); - texCoord = mapper->mapToTextureCoord(cellScalarValue); - if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's - { - texCoord[1] = 1.0f; - } + cvf::Vec3d p2 = polyLine[lIdx]; + cvf::Vec3d p1p2 = p2 - p1; - size_t j; - for (j = 0; j < 3; j++) - { - rawPtr[tIdx*3 + j] = texCoord; + if ((p1p2 - (p1p2 * extrDir)*extrDir).length() > 0.1 ) + { + adjustedPolyline->push_back(p2); + p1 = p2; } } } @@ -1184,25 +1169,19 @@ void RivCrossSectionGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textu //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivCrossSectionGeometryGenerator::adjustPolyline() +const std::vector& RivCrossSectionGeometryGenerator::triangleToCellIndex() const { - size_t lineCount = m_polyLine.size(); - if (!m_polyLine.size()) return; - - m_adjustedPolyline.push_back(m_polyLine[0]); - cvf::Vec3d p1 = m_polyLine[0]; - - for (size_t lIdx = 1; lIdx < lineCount; ++lIdx) - { - cvf::Vec3d p2 = m_polyLine[lIdx]; - cvf::Vec3d p1p2 = p2 - p1; + CVF_ASSERT(m_triangleVxes->size()); + return m_triangleToCellIdxMap; +} - if ((p1p2 - (p1p2 * m_extrusionDirection)*m_extrusionDirection).length() > 0.1 ) - { - m_adjustedPolyline.push_back(p2); - p1 = p2; - } - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RivCrossSectionGeometryGenerator::triangleVxToCellCornerInterpolationWeights() const +{ + CVF_ASSERT(m_triangleVxes->size()); + return m_triVxToCellCornerWeights; } @@ -1213,7 +1192,7 @@ void RivCrossSectionGeometryGenerator::adjustPolyline() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -EclipseCrossSectionGrid::EclipseCrossSectionGrid(const RigMainGrid * mainGrid) : m_mainGrid(mainGrid) +RivEclipseCrossSectionGrid::RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid) : m_mainGrid(mainGrid) { } @@ -1221,7 +1200,7 @@ EclipseCrossSectionGrid::EclipseCrossSectionGrid(const RigMainGrid * mainGrid) : //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::Vec3d EclipseCrossSectionGrid::displayOffset() const +cvf::Vec3d RivEclipseCrossSectionGrid::displayOffset() const { return m_mainGrid->displayModelOffset(); } @@ -1229,7 +1208,7 @@ cvf::Vec3d EclipseCrossSectionGrid::displayOffset() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::BoundingBox EclipseCrossSectionGrid::boundingBox() const +cvf::BoundingBox RivEclipseCrossSectionGrid::boundingBox() const { return m_mainGrid->boundingBox(); } @@ -1237,7 +1216,7 @@ cvf::BoundingBox EclipseCrossSectionGrid::boundingBox() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void EclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const +void RivEclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const { m_mainGrid->findIntersectingCells(intersectingBB, intersectedCells); } @@ -1245,7 +1224,7 @@ void EclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& inte //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool EclipseCrossSectionGrid::useCell(size_t cellIndex) const +bool RivEclipseCrossSectionGrid::useCell(size_t cellIndex) const { const RigCell& cell = m_mainGrid->cells()[cellIndex]; @@ -1255,7 +1234,7 @@ bool EclipseCrossSectionGrid::useCell(size_t cellIndex) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void EclipseCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const +void RivEclipseCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const { m_mainGrid->cellCornerVertices(cellIndex, cellCorners); } @@ -1263,7 +1242,7 @@ void EclipseCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d ce //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void EclipseCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const +void RivEclipseCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const { const caf::SizeTArray8& cornerIndicesSource = m_mainGrid->cells()[cellIndex].cornerIndices(); memcpy(cornerIndices, cornerIndicesSource.data(), 8); diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index c36685c30f..0c3416e3b1 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -35,25 +35,24 @@ namespace cvf } #include "cvfBoundingBox.h" -namespace cvf { -class CrossSectionHexGridIntf : public Object + +class RivCrossSectionHexGridIntf : public cvf::Object { public: - virtual Vec3d displayOffset() const = 0; - virtual BoundingBox boundingBox() const = 0; - virtual void findIntersectingCells(const BoundingBox& intersectingBB, std::vector* intersectedCells) const = 0; + virtual cvf::Vec3d displayOffset() const = 0; + virtual cvf::BoundingBox boundingBox() const = 0; + virtual void findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const = 0; virtual bool useCell(size_t cellIndex) const = 0; - virtual void cellCornerVertices(size_t cellIndex, Vec3d cellCorners[8]) const = 0; + virtual void cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const = 0; virtual void cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const = 0; }; -} -class EclipseCrossSectionGrid : public cvf::CrossSectionHexGridIntf +class RivEclipseCrossSectionGrid : public RivCrossSectionHexGridIntf { public: - EclipseCrossSectionGrid(const RigMainGrid * mainGrid); + RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid); virtual cvf::Vec3d displayOffset() const; virtual cvf::BoundingBox boundingBox() const; @@ -109,40 +108,32 @@ class RivCrossSectionGeometryGenerator : public cvf::Object public: RivCrossSectionGeometryGenerator(const std::vector &polyline, const cvf::Vec3d& extrusionDirection, - const RigMainGrid* grid ); + const RivCrossSectionHexGridIntf* grid ); ~RivCrossSectionGeometryGenerator(); - - - void textureCoordinates(cvf::Vec2fArray* textureCoords, - const RigResultAccessor* resultAccessor, - const cvf::ScalarMapper* mapper) const; + + // Generate geometry + cvf::ref generateSurface(); + cvf::ref createMeshDrawable(); // Mapping between cells and geometry - const std::vector& triangleToCellIndex() const; + const std::vector& triangleToCellIndex() const; const std::vector& triangleVxToCellCornerInterpolationWeights() const; - // Generated geometry - cvf::ref generateSurface(); - cvf::ref createMeshDrawable(); - private: void calculateArrays(); + static void adjustPolyline(const std::vector& polyLine, + const cvf::Vec3d extrDir, + std::vector* adjustedPolyline); - - - void adjustPolyline(); - - cvf::cref m_mainGrid; + cvf::cref m_hexGrid; std::vector m_polyLine; cvf::Vec3d m_extrusionDirection; - std::vector m_adjustedPolyline; // Output arrays cvf::ref m_triangleVxes; cvf::ref m_cellBorderLineVxes; std::vector m_triangleToCellIdxMap; - std::vector m_triVxToCellCornerWeights; }; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index cb4574d0a7..c15d856dd9 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -45,7 +45,6 @@ //-------------------------------------------------------------------------------------------------- RivCrossSectionPartMgr::RivCrossSectionPartMgr(const RimCrossSection* rimCrossSection) : m_rimCrossSection(rimCrossSection), - m_grid(NULL), m_defaultColor(cvf::Color3::WHITE) { CVF_ASSERT(m_rimCrossSection); @@ -113,7 +112,10 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEcli timeStepIndex, cellResultColors->resultVariable()); - m_nativeCrossSectionGenerator->textureCoordinates(m_nativeCrossSectionFacesTextureCoords.p(), resultAccessor.p() ,mapper); + calculateEclipseTextureCoordinates(m_nativeCrossSectionFacesTextureCoords.p(), + m_nativeCrossSectionGenerator->triangleToCellIndex(), + resultAccessor.p(), + mapper); RivScalarMapperUtils::applyTextureResultsToPart(m_nativeCrossSectionFaces.p(), @@ -127,6 +129,45 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEcli } +//-------------------------------------------------------------------------------------------------- +/// Calculates the texture coordinates in a "nearly" one dimentional texture. +/// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5 +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, + const std::vector& triangleToCellIdxMap, + const RigResultAccessor* resultAccessor, + const cvf::ScalarMapper* mapper) const +{ + if (!resultAccessor) return; + + size_t numVertices = triangleToCellIdxMap.size()*3; + + textureCoords->resize(numVertices); + cvf::Vec2f* rawPtr = textureCoords->ptr(); + + double cellScalarValue; + cvf::Vec2f texCoord; + + int triangleCount = static_cast(triangleToCellIdxMap.size()); + +#pragma omp parallel for private(texCoord, cellScalarValue) + for (int tIdx = 0; tIdx < triangleCount; tIdx++) + { + cellScalarValue = resultAccessor->cellScalarGlobIdx(triangleToCellIdxMap[tIdx]); + texCoord = mapper->mapToTextureCoord(cellScalarValue); + if (cellScalarValue == HUGE_VAL || cellScalarValue != cellScalarValue) // a != a is true for NAN's + { + texCoord[1] = 1.0f; + } + + size_t j; + for (j = 0; j < 3; j++) + { + rawPtr[tIdx*3 + j] = texCoord; + } + } +} + const int priCrossSectionGeo = 1; const int priNncGeo = 2; const int priMesh = 3; @@ -265,14 +306,15 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::computeData() { - m_grid = mainGrid(); - CVF_ASSERT(m_grid.notNull()); + RigMainGrid* m_grid = mainGrid(); + CVF_ASSERT(m_grid); std::vector< std::vector > polyLine = m_rimCrossSection->polyLines(); if (polyLine.size() > 0) { cvf::Vec3d direction = extrusionDirection(polyLine[0]); - m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, m_grid.p()); + cvf::ref eclHexGrid = new RivEclipseCrossSectionGrid(m_grid); + m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, eclHexGrid.p()); } } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 736b1b13be..96c1dd4fcc 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -62,10 +62,9 @@ class RivCrossSectionPartMgr : public cvf::Object RigMainGrid* mainGrid(); cvf::Vec3d extrusionDirection(const std::vector& polyline) const; - + void calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, const std::vector& triangleToCellIdxMap, const RigResultAccessor* resultAccessor, const cvf::ScalarMapper* mapper) const; private: - cvf::cref m_grid; const RimCrossSection* m_rimCrossSection; cvf::Color3f m_defaultColor; From f8fa6787e900ee8e187a6c84ef6e0a43c6a0cf4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 20 Nov 2015 15:54:22 +0100 Subject: [PATCH 102/290] (#166) WIP: Starting to get geomech cross sections in place --- .../RivFemPartPartMgr.cpp | 9 +- .../RivCrossSectionGeometryGenerator.cpp | 88 +++++++ .../RivCrossSectionGeometryGenerator.h | 18 ++ .../RivCrossSectionPartMgr.cpp | 237 ++++++++++++------ .../RivCrossSectionPartMgr.h | 12 +- .../RimCrossSectionCollection.cpp | 4 +- .../RimCrossSectionCollection.h | 2 +- .../ProjectDataModel/RimEclipseView.cpp | 2 +- 8 files changed, 284 insertions(+), 88 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp index cd3a140502..7a8a5fcace 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp @@ -218,8 +218,6 @@ void RivFemPartPartMgr::updateCellResultColor(size_t timeStepIndex, RimGeoMechCe { CVF_ASSERT(cellResultColors); - // RigCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->reservoirData(); - cvf::ref surfaceFacesColorArray; // Outer surface @@ -295,7 +293,12 @@ void RivFemPartPartMgr::updateCellResultColor(size_t timeStepIndex, RimGeoMechCe cellResultColors->firstAnchestorOrThisOfType(view); CVF_ASSERT(view); - RivScalarMapperUtils::applyTextureResultsToPart(m_surfaceFaces.p(), m_surfaceFacesTextureCoords.p(), mapper, m_opacityLevel, caf::FC_NONE, view->isLightingDisabled()); + RivScalarMapperUtils::applyTextureResultsToPart(m_surfaceFaces.p(), + m_surfaceFacesTextureCoords.p(), + mapper, + m_opacityLevel, + caf::FC_NONE, + view->isLightingDisabled()); } } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 67070da78e..e178f42949 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1247,3 +1247,91 @@ void RivEclipseCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t corn const caf::SizeTArray8& cornerIndicesSource = m_mainGrid->cells()[cellIndex].cornerIndices(); memcpy(cornerIndices, cornerIndicesSource.data(), 8); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +#include "RigFemPart.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivFemCrossSectionGrid::RivFemCrossSectionGrid(const RigFemPart * femPart): m_femPart(femPart) +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivFemCrossSectionGrid::displayOffset() const +{ + return cvf::Vec3d::ZERO; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RivFemCrossSectionGrid::boundingBox() const +{ + return m_femPart->boundingBox(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivFemCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const +{ + m_femPart->findIntersectingCells(intersectingBB, intersectedCells); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivFemCrossSectionGrid::useCell(size_t cellIndex) const +{ + RigElementType elmType = m_femPart->elementType(cellIndex); + + if (!(elmType == HEX8 || elmType == HEX8P)) return false; + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivFemCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const +{ + RigElementType elmType = m_femPart->elementType(cellIndex); + if (!(elmType == HEX8 || elmType == HEX8P)) return ; + + const std::vector& nodeCoords = m_femPart->nodes().coordinates; + const int* cornerIndices = m_femPart->connectivities(cellIndex); + + cellCorners[0] = cvf::Vec3d(nodeCoords[cornerIndices[0]]); + cellCorners[1] = cvf::Vec3d(nodeCoords[cornerIndices[1]]); + cellCorners[2] = cvf::Vec3d(nodeCoords[cornerIndices[2]]); + cellCorners[3] = cvf::Vec3d(nodeCoords[cornerIndices[3]]); + cellCorners[4] = cvf::Vec3d(nodeCoords[cornerIndices[4]]); + cellCorners[5] = cvf::Vec3d(nodeCoords[cornerIndices[5]]); + cellCorners[6] = cvf::Vec3d(nodeCoords[cornerIndices[6]]); + cellCorners[7] = cvf::Vec3d(nodeCoords[cornerIndices[7]]); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivFemCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const +{ + RigElementType elmType = m_femPart->elementType(cellIndex); + if (!(elmType == HEX8 || elmType == HEX8P)) return ; + int elmIdx = static_cast(cellIndex); + cornerIndices[0] = m_femPart->elementNodeResultIdx(elmIdx, 0); + cornerIndices[1] = m_femPart->elementNodeResultIdx(elmIdx, 1); + cornerIndices[2] = m_femPart->elementNodeResultIdx(elmIdx, 2); + cornerIndices[3] = m_femPart->elementNodeResultIdx(elmIdx, 3); + cornerIndices[4] = m_femPart->elementNodeResultIdx(elmIdx, 4); + cornerIndices[5] = m_femPart->elementNodeResultIdx(elmIdx, 5); + cornerIndices[6] = m_femPart->elementNodeResultIdx(elmIdx, 6); + cornerIndices[7] = m_femPart->elementNodeResultIdx(elmIdx, 7); +} + diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 0c3416e3b1..e20ade141c 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -65,6 +65,24 @@ class RivEclipseCrossSectionGrid : public RivCrossSectionHexGridIntf cvf::cref m_mainGrid; }; +class RigFemPart; + +class RivFemCrossSectionGrid : public RivCrossSectionHexGridIntf +{ +public: + RivFemCrossSectionGrid(const RigFemPart * femPart); + + virtual cvf::Vec3d displayOffset() const; + virtual cvf::BoundingBox boundingBox() const; + virtual void findIntersectingCells(const cvf::BoundingBox& intersectingBB, std::vector* intersectedCells) const; + virtual bool useCell(size_t cellIndex) const; + virtual void cellCornerVertices(size_t cellIndex, cvf::Vec3d cellCorners[8]) const; + virtual void cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const; + +private: + cvf::cref m_femPart; +}; + class RivVertexWeights { public: diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index c15d856dd9..684f886796 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -38,6 +38,12 @@ #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetDirect.h" +#include "RimGeoMechView.h" +#include "RimGeoMechCase.h" +#include "RigGeomechCaseData.h" +#include "RigFemPartCollection.h" +#include "RimGeoMechCellColors.h" +#include "RigFemPartResultsCollection.h" //-------------------------------------------------------------------------------------------------- @@ -49,7 +55,7 @@ RivCrossSectionPartMgr::RivCrossSectionPartMgr(const RimCrossSection* rimCrossSe { CVF_ASSERT(m_rimCrossSection); - m_nativeCrossSectionFacesTextureCoords = new cvf::Vec2fArray; + m_crossSectionFacesTextureCoords = new cvf::Vec2fArray; computeData(); } @@ -59,7 +65,7 @@ RivCrossSectionPartMgr::RivCrossSectionPartMgr(const RimCrossSection* rimCrossSe //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::applySingleColorEffect() { - if (m_nativeCrossSectionGenerator.isNull()) return; + if (m_crossSectionGenerator.isNull()) return; m_defaultColor = cvf::Color3f::OLIVE;//m_rimCrossSection->CrossSectionColor(); this->updatePartEffect(); @@ -68,65 +74,140 @@ void RivCrossSectionPartMgr::applySingleColorEffect() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) { - if (m_nativeCrossSectionGenerator.isNull()) return; + RimEclipseView* eclipseView; + m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); + if (eclipseView) + { + RimEclipseCellColors* cellResultColors = eclipseView->cellResult(); - CVF_ASSERT(cellResultColors); + if (m_crossSectionGenerator.isNull()) return; - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); - RimEclipseView* eclipseView = cellResultColors->reservoirView(); - RigCaseData* eclipseCase = eclipseView->eclipseCase()->reservoirData(); + CVF_ASSERT(cellResultColors); - // CrossSections - if (m_nativeCrossSectionFaces.notNull()) - { - if (cellResultColors->isTernarySaturationSelected()) - { - //RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), - // timeStepIndex, - // m_grid->gridIndex(), - // m_nativeCrossSectionGenerator->quadToCellFaceMapper()); - // - //texturer.createTextureCoords(m_nativeCrossSectionFacesTextureCoords.p()); - - CVF_ASSERT(false); // Todo - - const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); - RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_nativeCrossSectionFaces.p(), - m_nativeCrossSectionFacesTextureCoords.p(), - mapper, - 1.0, - caf::FC_NONE, - eclipseView->isLightingDisabled()); - } - else + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); + RigCaseData* eclipseCase = eclipseView->eclipseCase()->reservoirData(); + + // CrossSections + if (m_crossSectionFaces.notNull()) { - CVF_ASSERT(m_nativeCrossSectionGenerator.notNull()); + if (cellResultColors->isTernarySaturationSelected()) + { + //RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), + // timeStepIndex, + // m_grid->gridIndex(), + // m_nativeCrossSectionGenerator->quadToCellFaceMapper()); + // + //texturer.createTextureCoords(m_nativeCrossSectionFacesTextureCoords.p()); + + CVF_ASSERT(false); // Todo + + const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); + RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_crossSectionFaces.p(), + m_crossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + eclipseView->isLightingDisabled()); + } + else + { + CVF_ASSERT(m_crossSectionGenerator.notNull()); - const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); + const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); - cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), - 0, - RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), - timeStepIndex, - cellResultColors->resultVariable()); + cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), + 0, + RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), + timeStepIndex, + cellResultColors->resultVariable()); - calculateEclipseTextureCoordinates(m_nativeCrossSectionFacesTextureCoords.p(), - m_nativeCrossSectionGenerator->triangleToCellIndex(), - resultAccessor.p(), - mapper); + calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), + m_crossSectionGenerator->triangleToCellIndex(), + resultAccessor.p(), + mapper); - RivScalarMapperUtils::applyTextureResultsToPart(m_nativeCrossSectionFaces.p(), - m_nativeCrossSectionFacesTextureCoords.p(), - mapper, - 1.0, - caf::FC_NONE, - eclipseView->isLightingDisabled()); + RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), + m_crossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + eclipseView->isLightingDisabled()); + } } } + RimGeoMechView* geoView; + m_rimCrossSection->firstAnchestorOrThisOfType(geoView); + + if (geoView) + { + RimGeoMechCellColors* cellResultColors = geoView->cellResult(); + RigGeoMechCaseData* caseData = cellResultColors->ownerCaseData(); + + if (!caseData) return; + + const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); + RigFemResultAddress resVarAddress = cellResultColors->resultAddress(); + + // Do a "Hack" to show elm nodal and not nodal POR results + if (resVarAddress.resultPosType == RIG_NODAL && resVarAddress.fieldName == "POR-Bar") resVarAddress.resultPosType = RIG_ELEMENT_NODAL; + + const std::vector& resultValues = caseData->femPartResults()->resultValues(resVarAddress, 0, (int)timeStepIndex); + + const std::vector &vertexWeights = m_crossSectionGenerator->triangleVxToCellCornerInterpolationWeights(); + + bool isNodalResult = false; + RigFemPart* femPart = NULL; + if (resVarAddress.resultPosType == RIG_NODAL) + { + isNodalResult = true; + femPart = caseData->femParts()->part(0); + } + + m_crossSectionFacesTextureCoords->resize(vertexWeights.size()); + + if (resultValues.size() == 0) + { + m_crossSectionFacesTextureCoords->setAll(cvf::Vec2f(0.0, 1.0f)); + } + else + { + cvf::Vec2f* rawPtr = m_crossSectionFacesTextureCoords->ptr(); + + int vxCount = static_cast(vertexWeights.size()); + + #pragma omp parallel for schedule(dynamic) + for (int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx) + { + float resValue = 0; + int weightCount = vertexWeights[triangleVxIdx].size(); + for (int wIdx = 0; wIdx < weightCount; ++wIdx) + { + size_t resIdx = isNodalResult ? vertexWeights[triangleVxIdx].vxId(wIdx): femPart->nodeIdxFromElementNodeResultIdx(vertexWeights[triangleVxIdx].vxId(wIdx)); + resValue += resultValues[vertexWeights[triangleVxIdx].vxId(wIdx)] * vertexWeights[triangleVxIdx].weight(wIdx); + } + + if (resValue == HUGE_VAL || resValue != resValue) // a != a is true for NAN's + { + rawPtr[triangleVxIdx][1] = 1.0f; + } + else + { + rawPtr[triangleVxIdx] = mapper->mapToTextureCoord(resValue); + } + } + } + + RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), + m_crossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + geoView->isLightingDisabled()); + } } //-------------------------------------------------------------------------------------------------- @@ -177,12 +258,12 @@ const int priMesh = 3; //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::generatePartGeometry() { - if (m_nativeCrossSectionGenerator.isNull()) return; + if (m_crossSectionGenerator.isNull()) return; bool useBufferObjects = true; // Surface geometry { - cvf::ref geo = m_nativeCrossSectionGenerator->generateSurface(); + cvf::ref geo = m_crossSectionGenerator->generateSurface(); if (geo.notNull()) { geo->computeNormals(); @@ -205,13 +286,13 @@ void RivCrossSectionPartMgr::generatePartGeometry() part->setEnableMask(surfaceBit); part->setPriority(priCrossSectionGeo); - m_nativeCrossSectionFaces = part; + m_crossSectionFaces = part; } } // Mesh geometry { - cvf::ref geoMesh = m_nativeCrossSectionGenerator->createMeshDrawable(); + cvf::ref geoMesh = m_crossSectionGenerator->createMeshDrawable(); if (geoMesh.notNull()) { if (useBufferObjects) @@ -227,7 +308,7 @@ void RivCrossSectionPartMgr::generatePartGeometry() part->setEnableMask(meshSurfaceBit); part->setPriority(priMesh); - m_nativeCrossSectionGridLines = part; + m_crossSectionGridLines = part; } } @@ -240,16 +321,16 @@ void RivCrossSectionPartMgr::generatePartGeometry() //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::updatePartEffect() { - if (m_nativeCrossSectionGenerator.isNull()) return; + if (m_crossSectionGenerator.isNull()) return; // Set deCrossSection effect caf::SurfaceEffectGenerator geometryEffgen(m_defaultColor, caf::PO_1); cvf::ref geometryOnlyEffect = geometryEffgen.generateCachedEffect(); - if (m_nativeCrossSectionFaces.notNull()) + if (m_crossSectionFaces.notNull()) { - m_nativeCrossSectionFaces->setEffect(geometryOnlyEffect.p()); + m_crossSectionFaces->setEffect(geometryOnlyEffect.p()); } // Update mesh colors as well, in case of change @@ -259,9 +340,9 @@ void RivCrossSectionPartMgr::updatePartEffect() caf::MeshEffectGenerator CrossSectionEffGen(cvf::Color3::WHITE);//prefs->defaultCrossSectionGridLineColors()); eff = CrossSectionEffGen.generateCachedEffect(); - if (m_nativeCrossSectionGridLines.notNull()) + if (m_crossSectionGridLines.notNull()) { - m_nativeCrossSectionGridLines->setEffect(eff.p()); + m_crossSectionGridLines->setEffect(eff.p()); } } @@ -271,15 +352,15 @@ void RivCrossSectionPartMgr::updatePartEffect() //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { - if (m_nativeCrossSectionFaces.isNull()) + if (m_crossSectionFaces.isNull()) { generatePartGeometry(); } - if (m_nativeCrossSectionFaces.notNull()) + if (m_crossSectionFaces.notNull()) { - m_nativeCrossSectionFaces->setTransform(scaleTransform); - model->addPart(m_nativeCrossSectionFaces.p()); + m_crossSectionFaces->setTransform(scaleTransform); + model->addPart(m_crossSectionFaces.p()); } } @@ -289,15 +370,15 @@ void RivCrossSectionPartMgr::appendNativeCrossSectionFacesToModel(cvf::ModelBasi //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) { - if (m_nativeCrossSectionGridLines.isNull()) + if (m_crossSectionGridLines.isNull()) { generatePartGeometry(); } - if (m_nativeCrossSectionGridLines.notNull()) + if (m_crossSectionGridLines.notNull()) { - m_nativeCrossSectionGridLines->setTransform(scaleTransform); - model->addPart(m_nativeCrossSectionGridLines.p()); + m_crossSectionGridLines->setTransform(scaleTransform); + model->addPart(m_crossSectionGridLines.p()); } } @@ -306,33 +387,39 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::computeData() { - RigMainGrid* m_grid = mainGrid(); - CVF_ASSERT(m_grid); - std::vector< std::vector > polyLine = m_rimCrossSection->polyLines(); if (polyLine.size() > 0) { cvf::Vec3d direction = extrusionDirection(polyLine[0]); - cvf::ref eclHexGrid = new RivEclipseCrossSectionGrid(m_grid); - m_nativeCrossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, eclHexGrid.p()); + cvf::ref hexGrid = createHexGridInterface(); + m_crossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, hexGrid.p()); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigMainGrid* RivCrossSectionPartMgr::mainGrid() +cvf::ref RivCrossSectionPartMgr::createHexGridInterface() { - RigMainGrid* grid = NULL; - RimEclipseView* eclipseView = NULL; + RimEclipseView* eclipseView; m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); if (eclipseView) { + RigMainGrid* grid = NULL; grid = eclipseView->eclipseCase()->reservoirData()->mainGrid(); + return new RivEclipseCrossSectionGrid(grid); + } + + RimGeoMechView* geoView; + m_rimCrossSection->firstAnchestorOrThisOfType(geoView); + if (geoView) + { + RigFemPart* femPart = geoView->geoMechCase()->geoMechData()->femParts()->part(0); + return new RivFemCrossSectionGrid(femPart); } - return grid; + return NULL; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 96c1dd4fcc..62c084756d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -50,7 +50,7 @@ class RivCrossSectionPartMgr : public cvf::Object RivCrossSectionPartMgr(const RimCrossSection* rimCrossSection); void applySingleColorEffect(); - void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); + void updateCellResultColor(size_t timeStepIndex); void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); void appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); @@ -60,18 +60,18 @@ class RivCrossSectionPartMgr : public cvf::Object void generatePartGeometry(); void computeData(); - RigMainGrid* mainGrid(); cvf::Vec3d extrusionDirection(const std::vector& polyline) const; void calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, const std::vector& triangleToCellIdxMap, const RigResultAccessor* resultAccessor, const cvf::ScalarMapper* mapper) const; + cvf::ref createHexGridInterface(); private: const RimCrossSection* m_rimCrossSection; cvf::Color3f m_defaultColor; - cvf::ref m_nativeCrossSectionGenerator; - cvf::ref m_nativeCrossSectionFaces; - cvf::ref m_nativeCrossSectionGridLines; - cvf::ref m_nativeCrossSectionFacesTextureCoords; + cvf::ref m_crossSectionGenerator; + cvf::ref m_crossSectionFaces; + cvf::ref m_crossSectionGridLines; + cvf::ref m_crossSectionFacesTextureCoords; }; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 0aca5842d5..c603058bf0 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -64,12 +64,12 @@ void RimCrossSectionCollection::applySingleColorEffect() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex) { for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { RimCrossSection* cs = m_crossSections[csIdx]; - cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex, cellResultColors); + cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex); } } diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h index 72a10ed33e..c539d1d7ac 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -51,7 +51,7 @@ class RimCrossSectionCollection : public caf::PdmObject // Visualization interface void applySingleColorEffect(); - void updateCellResultColor(size_t timeStepIndex, RimEclipseCellColors* cellResultColors); + void updateCellResultColor(size_t timeStepIndex); void appendPartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); protected: diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 60b71f160d..1eed0aa39a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -655,7 +655,7 @@ void RimEclipseView::updateCurrentTimeStep() if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || this->cellResult()->isTernarySaturationSelected()) { - crossSectionCollection->updateCellResultColor(m_currentTimeStep, this->cellResult()); + crossSectionCollection->updateCellResultColor(m_currentTimeStep); } else { From b77d91b5e16eddcfcd7f6c46ba88eec17ae49785 Mon Sep 17 00:00:00 2001 From: Jacob Storen Date: Sat, 21 Nov 2015 00:06:20 -0800 Subject: [PATCH 103/290] Linux compile fix --- ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 684f886796..2710973b52 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -40,7 +40,7 @@ #include "cvfPrimitiveSetDirect.h" #include "RimGeoMechView.h" #include "RimGeoMechCase.h" -#include "RigGeomechCaseData.h" +#include "RigGeoMechCaseData.h" #include "RigFemPartCollection.h" #include "RimGeoMechCellColors.h" #include "RigFemPartResultsCollection.h" From 0b097ec2eb2ceaaf687beb0ff386a338d515cff1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Sat, 21 Nov 2015 15:36:01 +0100 Subject: [PATCH 104/290] Hide cross section command from context menu of simulation well --- ApplicationCode/UserInterface/RiuViewerCommands.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index b634f366d7..c4eafb763e 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -239,6 +239,8 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) } } +// TODO: Include when cross section from simulation wells are ready +/* const RivEclipseWellSourceInfo* eclipseWellSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (eclipseWellSourceInfo) { @@ -250,6 +252,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) commandIds << "RicNewSimWellCrossSectionFeature"; } } +*/ } // View Link commands From 95e22b581c1017749f655febe7ef7fe681344a08 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 07:24:50 +0100 Subject: [PATCH 105/290] (#639) Updated axis cross texts --- .../ProjectDataModel/RimEclipseView.cpp | 14 ++++++- .../ProjectDataModel/RimEclipseView.h | 3 +- .../ProjectDataModel/RimGeoMechView.cpp | 26 ++++++------- .../ProjectDataModel/RimGeoMechView.h | 5 +-- ApplicationCode/ProjectDataModel/RimView.h | 1 + ApplicationCode/UserInterface/RiuViewer.cpp | 39 ++++++++++++------- 6 files changed, 55 insertions(+), 33 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 1eed0aa39a..31e20b5cb9 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -186,7 +186,6 @@ void RimEclipseView::clampCurrentTimestep() if (m_currentTimeStep < 0 ) m_currentTimeStep = 0; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -200,6 +199,7 @@ void RimEclipseView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { bool generateDisplayModel = (viewer() == NULL); updateViewerWidget(); + if (generateDisplayModel) { updateDisplayModelForWellResults(); @@ -1718,6 +1718,18 @@ void RimEclipseView::updateIconStateForFilterCollections() m_propertyFilterCollection()->uiCapability()->updateConnectedEditors(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel) +{ + CVF_ASSERT(xLabel && yLabel && zLabel); + + *xLabel = "E(X)"; + *yLabel = "N(Y)"; + *zLabel = "Z"; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 7dbaa0c89c..5849e04366 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -134,6 +134,8 @@ class RimEclipseView : public RimView virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); void updateIconStateForFilterCollections(); + virtual void axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel); + protected: virtual void initAfterRead(); virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); @@ -171,7 +173,6 @@ class RimEclipseView : public RimView void clampCurrentTimestep(); - virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 9794c1dd0c..f99d89ffb9 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -155,7 +155,6 @@ void RimGeoMechView::loadDataAndUpdate() progress.setProgressDescription("Create Display model"); updateViewerWidget(); - setCustomAxisCrossLabels(); this->geoMechPropertyFilterCollection()->loadAndInitializePropertyFilters(); @@ -483,7 +482,6 @@ void RimGeoMechView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { bool generateDisplayModel = (viewer() == NULL); updateViewerWidget(); - setCustomAxisCrossLabels(); if (generateDisplayModel) { @@ -516,18 +514,6 @@ void RimGeoMechView::initAfterRead() this->updateUiIconFromToggleField(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGeoMechView::setCustomAxisCrossLabels() -{ - // Minimalistic - size of axis cross does not have to be adjusted - if (m_viewer) m_viewer->setAxisLabels("E-x1", "N-y2", "Z-3"); - - // A bit larger - size of axis cross is slightly larger - //if (m_viewer) m_viewer->setAxisLabels("E(x,1)", "N(y,2)", "Z(3)"); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -642,6 +628,18 @@ void RimGeoMechView::updateIconStateForFilterCollections() m_propertyFilterCollection()->uiCapability()->updateConnectedEditors(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechView::axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel) +{ + CVF_ASSERT(xLabel && yLabel && zLabel); + + *xLabel = "E(X,1)"; + *yLabel = "N(Y,2)"; + *zLabel = "Z(3)"; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index 4fe6dceea7..bcf20262f5 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -78,6 +78,8 @@ class RimGeoMechView : public RimView virtual void scheduleGeometryRegen(RivCellSetEnum geometryType); void updateIconStateForFilterCollections(); + virtual void axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel); + protected: virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); @@ -101,9 +103,6 @@ class RimGeoMechView : public RimView virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void initAfterRead(); - void setCustomAxisCrossLabels(); - - virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 39e83ea0d0..5200f119e1 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -144,6 +144,7 @@ class RimView : public caf::PdmObject cvf::ref currentTotalCellVisibility(); virtual bool showActiveCellsOnly(); + virtual void axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel) = 0; public: virtual void loadDataAndUpdate() = 0; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 4bdc8831e2..16d1a1baa5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -53,7 +53,6 @@ #include #include #include -#include "RimCase.h" using cvf::ManipulatorTrackball; @@ -78,7 +77,7 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) { cvf::Font* standardFont = RiaApplication::instance()->standardFont(); m_axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); - m_axisCross->setAxisLabels("E", "N", "Z"); + m_axisCross->setAxisLabels("X", "Y", "Z"); m_axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); m_mainRendering->addOverlayItem(m_axisCross.p()); @@ -300,6 +299,13 @@ void RiuViewer::setOwnerReservoirView(RimView * owner) { m_rimView = owner; m_viewerCommands->setOwnerView(owner); + + cvf::String xLabel; + cvf::String yLabel; + cvf::String zLabel; + + m_rimView->axisLabels(&xLabel, &yLabel, &zLabel); + setAxisLabels(xLabel, yLabel, zLabel); } //-------------------------------------------------------------------------------------------------- @@ -579,19 +585,24 @@ void RiuViewer::setAxisLabels(const cvf::String& xLabel, const cvf::String& yLab { m_axisCross->setAxisLabels(xLabel, yLabel, zLabel); - size_t maxAxisLabelLength = xLabel.size(); - if (yLabel.size() > maxAxisLabelLength) maxAxisLabelLength = yLabel.size(); - if (zLabel.size() > maxAxisLabelLength) maxAxisLabelLength = zLabel.size(); + // The axis cross is designed for short labels, longer labels causes clipping of text + // The commented out code adjust the size of the axis cross, and this makes the axis cross labels visible + // Side effect is also that the axis cross is zoomed (will be larger) + /* + size_t maxAxisLabelLength = xLabel.size(); + if (yLabel.size() > maxAxisLabelLength) maxAxisLabelLength = yLabel.size(); + if (zLabel.size() > maxAxisLabelLength) maxAxisLabelLength = zLabel.size(); - if (maxAxisLabelLength > 4) - { - if (maxAxisLabelLength < 6) + if (maxAxisLabelLength > 4) { - m_axisCross->setSize(cvf::Vec2ui(140, 140)); + if (maxAxisLabelLength < 6) + { + m_axisCross->setSize(cvf::Vec2ui(140, 140)); + } + else if (maxAxisLabelLength < 8) + { + m_axisCross->setSize(cvf::Vec2ui(160, 160)); + } } - else if (maxAxisLabelLength < 8) - { - m_axisCross->setSize(cvf::Vec2ui(160, 160)); - } - } + */ } From 4971304bf9d5b39a5532dd3a8314661a59c2e7fa Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 08:37:45 +0100 Subject: [PATCH 106/290] (#597) Fixed how fraction of day is used to adjust time step date --- .../RifEclipseOutputFileTools.cpp | 104 +++++------------- .../FileInterface/RifEclipseOutputFileTools.h | 3 +- 2 files changed, 26 insertions(+), 81 deletions(-) diff --git a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp index 500efe7c86..aa5fb95a17 100644 --- a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp @@ -58,11 +58,10 @@ void getDayMonthYear(const ecl_kw_type* intehead_kw, int* day, int* month, int* *year = ecl_kw_iget_int(intehead_kw, INTEHEAD_YEAR_INDEX); } - //-------------------------------------------------------------------------------------------------- /// Get list of time step texts (dates) //-------------------------------------------------------------------------------------------------- -void RifEclipseOutputFileTools::timeSteps(ecl_file_type* ecl_file, std::vector* timeSteps, bool* detectedFractionOfDay ) +void RifEclipseOutputFileTools::timeSteps(ecl_file_type* ecl_file, std::vector* timeSteps) { CVF_ASSERT(timeSteps); CVF_ASSERT(ecl_file); @@ -73,38 +72,30 @@ void RifEclipseOutputFileTools::timeSteps(ecl_file_type* ecl_file, std::vector dayFractions(numINTEHEAD, 0.0); // Init fraction to zero - // Find all days, and stop when the double value is lower than the previous - QList days; - for (int i = 0; i < numDOUBHEAD; i++) + // Read out fraction of day if number of keywords are identical + if (numINTEHEAD == numDOUBHEAD) { - if (foundAllDayValues) continue;; - - ecl_kw_type* kwDOUBHEAD = ecl_file_iget_named_kw(ecl_file, DOUBHEAD_KW, i); - if (kwDOUBHEAD) + for (int i = 0; i < numDOUBHEAD; i++) { - double dayValue = ecl_kw_iget_double(kwDOUBHEAD, DOUBHEAD_DAYS_INDEX); - double floorDayValue = cvf::Math::floor(dayValue); - - if (dayValue - floorDayValue > delta) + ecl_kw_type* kwDOUBHEAD = ecl_file_iget_named_kw(ecl_file, DOUBHEAD_KW, i); + if (kwDOUBHEAD) { - hasFractionOfDay = true; - } + double dayValue = ecl_kw_iget_double(kwDOUBHEAD, DOUBHEAD_DAYS_INDEX); + double floorDayValue = cvf::Math::floor(dayValue); + + double dayDelta = dayValue - floorDayValue; - days.push_back(dayValue); + dayFractions[i] = dayDelta; + } } } - std::vector timeStepsFound; - - if (hasFractionOfDay) + for (int i = 0; i < numINTEHEAD; i++) { - ecl_kw_type* kwINTEHEAD = ecl_file_iget_named_kw(ecl_file, INTEHEAD_KW, 0); + ecl_kw_type* kwINTEHEAD = ecl_file_iget_named_kw(ecl_file, INTEHEAD_KW, i); + CVF_ASSERT(kwINTEHEAD); if (kwINTEHEAD) { int day = 0; @@ -112,66 +103,24 @@ void RifEclipseOutputFileTools::timeSteps(ecl_file_type* ecl_file, std::vector(floorDayValue)); + double dayFraction = dayFractions[i]; + int seconds = static_cast(dayFraction * 24.0 * 60.0 * 60.0); + QTime time(0, 0); + time = time.addSecs(seconds); - double dayFraction = dayValue - floorDayValue; - int seconds = static_cast(dayFraction * 24.0 * 60.0 * 60.0); - QTime time(0, 0); - time = time.addSecs(seconds); + reportDateTime.setTime(time); - reportDateTime.setTime(time); - - if (std::find(timeStepsFound.begin(), timeStepsFound.end(), reportDateTime) == timeStepsFound.end()) - { - timeStepsFound.push_back(reportDateTime); - } - } - } - } - else - { - for (int i = 0; i < numINTEHEAD; i++) - { - ecl_kw_type* kwINTEHEAD = ecl_file_iget_named_kw(ecl_file, INTEHEAD_KW, i); - if (kwINTEHEAD) + if (std::find(timeSteps->begin(), timeSteps->end(), reportDateTime) == timeSteps->end()) { - int day = 0; - int month = 0; - int year = 0; - getDayMonthYear(kwINTEHEAD, &day, &month, &year); - - QDateTime reportDateTime(QDate(year, month, day)); - QTime time(0, 0); - reportDateTime.setTime(time); - - CVF_ASSERT(reportDateTime.isValid()); - - if (std::find(timeStepsFound.begin(), timeStepsFound.end(), reportDateTime) == timeStepsFound.end()) - { - timeStepsFound.push_back(reportDateTime); - } + timeSteps->push_back(reportDateTime); } } } - - // Return time step info to caller - *timeSteps = timeStepsFound; - - if (detectedFractionOfDay) - { - *detectedFractionOfDay = hasFractionOfDay; - } } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -216,7 +165,6 @@ bool RifEclipseOutputFileTools::keywordData(ecl_file_type* ecl_file, const QStri return false; } - //-------------------------------------------------------------------------------------------------- /// Get first occurrence of file of given type in given list of filenames, as filename or NULL if not found //-------------------------------------------------------------------------------------------------- @@ -236,7 +184,6 @@ QString RifEclipseOutputFileTools::firstFileNameOfType(const QStringList& fileSe return QString::null; } - //-------------------------------------------------------------------------------------------------- /// Get all files of the given type from the provided list of filenames //-------------------------------------------------------------------------------------------------- @@ -285,7 +232,6 @@ bool RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName(const QString& return baseNameFiles->count() > 0; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h index 8b6abcde5a..02bff0b477 100644 --- a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h +++ b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h @@ -49,8 +49,7 @@ class RifEclipseOutputFileTools static bool keywordData(ecl_file_type* ecl_file, const QString& keyword, size_t fileKeywordOccurrence, std::vector* values); static bool keywordData(ecl_file_type* ecl_file, const QString& keyword, size_t fileKeywordOccurrence, std::vector* values); -// static void timeStepsText(ecl_file_type* ecl_file, QStringList* timeSteps); - static void timeSteps(ecl_file_type* ecl_file, std::vector* timeSteps, bool* detectedFractionOfDay = NULL); + static void timeSteps(ecl_file_type* ecl_file, std::vector* timeSteps); static bool findSiblingFilesWithSameBaseName(const QString& fileName, QStringList* fileSet); From dc1a66d2cc7d08c044e96286ad1e16b727644918 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 09:07:35 +0100 Subject: [PATCH 107/290] (#660) Use Intersection to be aligned with concept naming in other tools --- .../CrossSectionCommands/RicAppendCrossSectionFeature.cpp | 6 +++--- .../RicNewSimWellCrossSectionFeature.cpp | 4 ++-- .../RicNewWellPathCrossSectionFeature.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimCrossSection.cpp | 4 ++-- .../ProjectDataModel/RimCrossSectionCollection.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimView.cpp | 3 +-- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp index 8c44ccce51..618e21092f 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp @@ -59,7 +59,7 @@ void RicAppendCrossSectionFeature::onActionTriggered(bool isChecked) void RicAppendCrossSectionFeature::setupActionLook(QAction* actionToSetup) { // actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); - actionToSetup->setText("New Cross Section"); + actionToSetup->setText("New Intersection"); } //-------------------------------------------------------------------------------------------------- @@ -83,7 +83,7 @@ RicAppendCrossSectionFeatureCmd::~RicAppendCrossSectionFeatureCmd() //-------------------------------------------------------------------------------------------------- QString RicAppendCrossSectionFeatureCmd::name() { - return "New Cross Section"; + return "New Intersection"; } //-------------------------------------------------------------------------------------------------- @@ -94,7 +94,7 @@ void RicAppendCrossSectionFeatureCmd::redo() CVF_ASSERT(m_crossSectionCollection); RimCrossSection* crossSection = new RimCrossSection(); - crossSection->name = QString("Cross Section"); + crossSection->name = QString("Intersection"); m_crossSectionCollection->appendCrossSection(crossSection); } diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp index 22ed07350b..4b8be2785e 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp @@ -66,7 +66,7 @@ void RicNewSimWellCrossSectionFeature::onActionTriggered(bool isChecked) void RicNewSimWellCrossSectionFeature::setupActionLook(QAction* actionToSetup) { // actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); - actionToSetup->setText("New Cross Section"); + actionToSetup->setText("New Intersection"); } //-------------------------------------------------------------------------------------------------- @@ -91,7 +91,7 @@ RicNewSimWellCrossSectionCmd::~RicNewSimWellCrossSectionCmd() //-------------------------------------------------------------------------------------------------- QString RicNewSimWellCrossSectionCmd::name() { - return "Create Cross Section From Well"; + return "Create Intersection From Well"; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index a16e1dd513..662d55969b 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -75,7 +75,7 @@ void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) void RicNewWellPathCrossSectionFeature::setupActionLook(QAction* actionToSetup) { // actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); - actionToSetup->setText("New Cross Section"); + actionToSetup->setText("New Intersection"); } //-------------------------------------------------------------------------------------------------- @@ -100,7 +100,7 @@ RicNewWellPathCrossSectionFeatureCmd::~RicNewWellPathCrossSectionFeatureCmd() //-------------------------------------------------------------------------------------------------- QString RicNewWellPathCrossSectionFeatureCmd::name() { - return "Create Cross Section From Well Path"; + return "Create Intersection From Well Path"; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index ff067ea898..5687944c07 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -60,9 +60,9 @@ CAF_PDM_SOURCE_INIT(RimCrossSection, "CrossSection"); //-------------------------------------------------------------------------------------------------- RimCrossSection::RimCrossSection() { - CAF_PDM_InitObject("Cross Section", "", "", ""); + CAF_PDM_InitObject("Intersection", "", "", ""); - CAF_PDM_InitField(&name, "UserDescription", QString("Cross Section Name"), "Name", "", "", ""); + CAF_PDM_InitField(&name, "UserDescription", QString("Intersection Name"), "Name", "", "", ""); CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index c603058bf0..98a97ce7b9 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -32,9 +32,9 @@ CAF_PDM_SOURCE_INIT(RimCrossSectionCollection, "CrossSectionCollection"); //-------------------------------------------------------------------------------------------------- RimCrossSectionCollection::RimCrossSectionCollection() { - CAF_PDM_InitObject("Cross Sections", ":/undefined_image.png", "", ""); + CAF_PDM_InitObject("Intersections", ":/undefined_image.png", "", ""); - CAF_PDM_InitFieldNoDefault(&m_crossSections, "CrossSections", "Cross Sections", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_crossSections, "CrossSections", "Intersections", "", "", ""); m_crossSections.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 38faad881b..5331a59f55 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -117,13 +117,12 @@ RimView::RimView(void) m_overrideRangeFilterCollection.xmlCapability()->setIOWritable(false); m_overrideRangeFilterCollection.xmlCapability()->setIOReadable(false); - CAF_PDM_InitFieldNoDefault(&crossSectionCollection, "CrossSections", "Cross Sections", "", "", ""); + CAF_PDM_InitFieldNoDefault(&crossSectionCollection, "CrossSections", "Intersections", "", "", ""); crossSectionCollection.uiCapability()->setUiHidden(true); crossSectionCollection = new RimCrossSectionCollection(); m_previousGridModeMeshLinesWasFaults = false; - m_crossSectionModel = new cvf::ModelBasicList; m_crossSectionModel->setName("CrossSectionModel"); From 9a25a71cdea64d6cab1d2629ab995030e54256bb Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 09:56:48 +0100 Subject: [PATCH 108/290] Fwk : Added support for more characters in axis labels Moved drawing of axis cross slightly closer to left edge of available viewport --- Fwk/VizFwk/LibRender/cvfOverlayAxisCross.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Fwk/VizFwk/LibRender/cvfOverlayAxisCross.cpp b/Fwk/VizFwk/LibRender/cvfOverlayAxisCross.cpp index 9d32e2b866..8949efe212 100644 --- a/Fwk/VizFwk/LibRender/cvfOverlayAxisCross.cpp +++ b/Fwk/VizFwk/LibRender/cvfOverlayAxisCross.cpp @@ -102,7 +102,8 @@ void OverlayAxisCross::setAxisLabels( const String& xLabel, const String& yLabel { // Clipping of axis label text is depends on m_size and // z-part of axisMatrix.setTranslation(Vec3d(0, 0, -4.4)) defined in OverlayAxisCross::render() - CVF_ASSERT (xLabel.size() < 5 && yLabel.size() < 5 && zLabel.size() < 5); + + CVF_ASSERT (xLabel.size() < 7 && yLabel.size() < 7 && zLabel.size() < 7); m_xLabel = xLabel; m_yLabel = yLabel; @@ -174,7 +175,7 @@ void OverlayAxisCross::render(OpenGLContext* oglContext, const Vec2i& position, // Position the camera far enough away to make the axis and the text fit within the viewport Mat4d axisMatrix = viewMatrix; - axisMatrix.setTranslation(Vec3d(0, 0, -4.4)); + axisMatrix.setTranslation(Vec3d(-0.4, 0, -4.4)); // Setup camera Camera cam; From 11b317dd1b4ec2fd646627afe23fedef270f28fa Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 09:57:41 +0100 Subject: [PATCH 109/290] (#639) Use lower case for x and y --- ApplicationCode/ProjectDataModel/RimEclipseView.cpp | 4 ++-- ApplicationCode/ProjectDataModel/RimGeoMechView.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 31e20b5cb9..55f79e9918 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1725,8 +1725,8 @@ void RimEclipseView::axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::S { CVF_ASSERT(xLabel && yLabel && zLabel); - *xLabel = "E(X)"; - *yLabel = "N(Y)"; + *xLabel = "E(x)"; + *yLabel = "N(y)"; *zLabel = "Z"; } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index f99d89ffb9..b0251e5f23 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -635,8 +635,8 @@ void RimGeoMechView::axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::S { CVF_ASSERT(xLabel && yLabel && zLabel); - *xLabel = "E(X,1)"; - *yLabel = "N(Y,2)"; + *xLabel = "E(x,1)"; + *yLabel = "N(y,2)"; *zLabel = "Z(3)"; } From 83387ded1bef82a7e1e92095aaa6073a5050dd1a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 10:34:33 +0100 Subject: [PATCH 110/290] (#658) Fixed missing NNC text in Result Info --- ApplicationCode/UserInterface/RiuResultTextBuilder.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp index 3b837cd870..5dde69324d 100644 --- a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp +++ b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp @@ -90,8 +90,7 @@ QString RiuResultTextBuilder::mainResultText() { text = "NNC : " + nncText; } - - if (m_cellIndex != cvf::UNDEFINED_SIZE_T) + else if (m_cellIndex != cvf::UNDEFINED_SIZE_T) { QString faultText = faultResultText(); From 6c583055655c996d66241b2de89670f50c3663ac Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 11:17:52 +0100 Subject: [PATCH 111/290] (#266) Improved grid color based on background color --- .../GridBox/RivGridBoxGenerator.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index f5a4c28c01..8e3784eab2 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -635,16 +635,30 @@ cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) //-------------------------------------------------------------------------------------------------- void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f backgroundColor) { + double adjustmentFactor = 0.3; + + float gridR = 0.0; + float gridG = 0.0; + float gridB = 0.0; + if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) { - m_gridColor = cvf::Color3f::DARK_GRAY; + gridR = backgroundColor.r() - (backgroundColor.r() * adjustmentFactor); + gridG = backgroundColor.g() - (backgroundColor.g() * adjustmentFactor); + gridB = backgroundColor.b() - (backgroundColor.b() * adjustmentFactor); + m_gridLegendColor = cvf::Color3f::fromByteColor(10, 10, 10); } else { - m_gridColor = cvf::Color3f::LIGHT_GRAY; + gridR = backgroundColor.r() + (1.0 - backgroundColor.r()) * adjustmentFactor; + gridG = backgroundColor.g() + (1.0 - backgroundColor.g()) * adjustmentFactor; + gridB = backgroundColor.b() + (1.0 - backgroundColor.b()) * adjustmentFactor; + m_gridLegendColor = cvf::Color3f::WHITE; } + + m_gridColor.set(gridR, gridG, gridB); } //-------------------------------------------------------------------------------------------------- From 4d0c1d17b40c0183d27af3fc5ded76f70c9b5611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 22 Nov 2015 15:04:09 +0100 Subject: [PATCH 112/290] cafViewer: Add static model(s) to mainScene as well. --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 93b3c78be1..4e624bb288 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -872,6 +872,11 @@ void caf::Viewer::removeModelFromAllFrames(cvf::Model* model) scene->removeModel(model); } + + if (m_mainScene.notNull()) + { + m_mainScene->removeModel(model); + } } //-------------------------------------------------------------------------------------------------- @@ -885,7 +890,12 @@ void caf::Viewer::appendModelToAllFrames(cvf::Model* model) scene->addModel(model); } -} + + if (m_mainScene.notNull()) + { + m_mainScene->addModel(model); + } +} //-------------------------------------------------------------------------------------------------- /// From ed563fdce2ae07f255d256e5208330fb203e3c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 22 Nov 2015 15:05:19 +0100 Subject: [PATCH 113/290] (#166) Added crossSections to geomech view --- ApplicationCode/ProjectDataModel/RimGeoMechView.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index b0251e5f23..3ff21bd6d1 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -239,6 +239,12 @@ void RimGeoMechView::createDisplayModel() mainScene->addModel(wellPathModel.p()); + // Cross sections + + m_crossSectionModel->removeAllParts(); + crossSectionCollection->appendPartsToModel(m_crossSectionModel.p(), scaleTransform()); + m_viewer->addStaticModel(m_crossSectionModel.p()); + // If the animation was active before recreating everything, make viewer view current frame if (isTimeStepDependentDataVisible()) @@ -294,6 +300,11 @@ void RimGeoMechView::updateCurrentTimeStep() else m_vizLogic->updateStaticCellColors(m_currentTimeStep()); + if (this->cellResult()->hasResult()) + crossSectionCollection->updateCellResultColor(m_currentTimeStep); + else + crossSectionCollection->applySingleColorEffect(); + } else { From 5ec200c4fbb28eaab8996041f811e3083550ee91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 22 Nov 2015 15:06:43 +0100 Subject: [PATCH 114/290] (#166) Fixed geomech result addressing when interpolating --- .../ModelVisualization/RivCrossSectionPartMgr.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 2710973b52..0afe4c9391 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -159,11 +159,11 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) const std::vector &vertexWeights = m_crossSectionGenerator->triangleVxToCellCornerInterpolationWeights(); - bool isNodalResult = false; + bool isElementNodalResult = true; RigFemPart* femPart = NULL; if (resVarAddress.resultPosType == RIG_NODAL) { - isNodalResult = true; + isElementNodalResult = false; femPart = caseData->femParts()->part(0); } @@ -186,8 +186,9 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) int weightCount = vertexWeights[triangleVxIdx].size(); for (int wIdx = 0; wIdx < weightCount; ++wIdx) { - size_t resIdx = isNodalResult ? vertexWeights[triangleVxIdx].vxId(wIdx): femPart->nodeIdxFromElementNodeResultIdx(vertexWeights[triangleVxIdx].vxId(wIdx)); - resValue += resultValues[vertexWeights[triangleVxIdx].vxId(wIdx)] * vertexWeights[triangleVxIdx].weight(wIdx); + size_t resIdx = isElementNodalResult ? vertexWeights[triangleVxIdx].vxId(wIdx) : + femPart->nodeIdxFromElementNodeResultIdx(vertexWeights[triangleVxIdx].vxId(wIdx)); + resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight(wIdx); } if (resValue == HUGE_VAL || resValue != resValue) // a != a is true for NAN's From b5c226aac141d84400381015cdefca32d35658e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 22 Nov 2015 15:07:34 +0100 Subject: [PATCH 115/290] Guard against cell results color update on inactive cross sections --- .../ProjectDataModel/RimCrossSectionCollection.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 98a97ce7b9..bb6a17ca2d 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -57,7 +57,10 @@ void RimCrossSectionCollection::applySingleColorEffect() for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { RimCrossSection* cs = m_crossSections[csIdx]; - cs->crossSectionPartMgr()->applySingleColorEffect(); + if (cs->isActive) + { + cs->crossSectionPartMgr()->applySingleColorEffect(); + } } } @@ -69,7 +72,10 @@ void RimCrossSectionCollection::updateCellResultColor(size_t timeStepIndex) for (size_t csIdx = 0; csIdx < m_crossSections.size(); ++csIdx) { RimCrossSection* cs = m_crossSections[csIdx]; - cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex); + if (cs->isActive) + { + cs->crossSectionPartMgr()->updateCellResultColor(timeStepIndex); + } } } From c4aed9c487d97ac28275e763dcc860ed7c289358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 23 Nov 2015 11:21:12 +0100 Subject: [PATCH 116/290] (#166) Geomech cross sections in place. Refactor of frame/scene/model usage on top level. --- .../ProjectDataModel/RimEclipseView.cpp | 123 ++++-------------- .../ProjectDataModel/RimEclipseView.h | 6 - .../ProjectDataModel/RimGeoMechView.cpp | 41 +++--- ApplicationCode/ProjectDataModel/RimView.cpp | 23 ++-- ApplicationCode/ProjectDataModel/RimView.h | 7 +- Fwk/AppFwk/cafViewer/cafViewer.cpp | 2 +- Fwk/AppFwk/cafViewer/cafViewer.h | 2 +- 7 files changed, 64 insertions(+), 140 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 55f79e9918..cb1ffe622c 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -279,9 +279,11 @@ void RimEclipseView::createDisplayModel() { if (m_viewer.isNull()) return; - //static int callCount = 0; - //std::cout << "RimReservoirView::createDisplayModel() " << callCount++ << std::endl; - //RiuMainWindow::instance()->setResultInfo(QString ("RimReservoirView::createDisplayModel() ") + QString::number(callCount++)); +#if 0 // Debug info + static int callCount = 0; + std::cout << "RimReservoirView::createDisplayModel() " << callCount++ << std::endl; + RiuMainWindow::instance()->setResultInfo(QString("RimReservoirView::createDisplayModel() ") + QString::number(callCount++)); +#endif if (!(m_reservoir && m_reservoir->reservoirData())) return; @@ -421,9 +423,9 @@ void RimEclipseView::createDisplayModel() // Cross sections - m_crossSectionModel->removeAllParts(); - crossSectionCollection->appendPartsToModel(m_crossSectionModel.p(), m_reservoirGridPartManager->scaleTransform()); - m_viewer->addStaticModel(m_crossSectionModel.p()); + m_crossSectionVizModel->removeAllParts(); + crossSectionCollection->appendPartsToModel(m_crossSectionVizModel.p(), m_reservoirGridPartManager->scaleTransform()); + m_viewer->addStaticModelOnce(m_crossSectionVizModel.p()); // Compute triangle count, Debug only @@ -450,14 +452,22 @@ void RimEclipseView::createDisplayModel() } } */ + // Well path model + + RigMainGrid* mainGrid = eclipseCase()->reservoirData()->mainGrid(); + + m_wellPathPipeVizModel->removeAllParts(); + addWellPathsToModel(m_wellPathPipeVizModel.p(), + mainGrid->displayModelOffset(), + mainGrid->characteristicIJCellSize(), + currentActiveCellInfo()->geometryBoundingBox(), + m_reservoirGridPartManager->scaleTransform()); + + m_viewer->addStaticModelOnce(m_wellPathPipeVizModel.p()); // Create Scenes from the frameModels // Animation frames for results display, starts from frame 1 - RimEclipseCase* eclCase = eclipseCase(); - RigCaseData* caseData = eclCase ? eclCase->reservoirData() : NULL; - RigMainGrid* mainGrid = caseData ? caseData->mainGrid() : NULL; - CVF_ASSERT(mainGrid); size_t frameIndex; for (frameIndex = 0; frameIndex < frameModels.size(); frameIndex++) @@ -468,12 +478,6 @@ void RimEclipseView::createDisplayModel() cvf::ref scene = new cvf::Scene; scene->addModel(model); - // Add well paths, if any - addWellPathsToScene(scene.p(), mainGrid->displayModelOffset(), - mainGrid->characteristicIJCellSize(), - currentActiveCellInfo()->geometryBoundingBox(), - m_reservoirGridPartManager->scaleTransform()); - if (frameIndex == 0) m_viewer->setMainScene(scene.p()); else @@ -506,38 +510,11 @@ void RimEclipseView::updateCurrentTimeStep() if (this->viewController() && this->viewController()->isVisibleCellsOveridden()) { geometriesToRecolor.push_back(OVERRIDDEN_CELL_VISIBILITY); -#if 0 // Experimental - cvf::ref frameParts = new cvf::ModelBasicList; - std::vector gridIndices; - this->indicesToVisibleGrids(&gridIndices); - - - m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameParts.p(), OVERRIDDEN_CELL_VISIBILITY, gridIndices); - std::vector faultGeometryTypesToAppend = visibleFaultGeometryTypes(); - - for (size_t i = 0; i < faultGeometryTypesToAppend.size(); i++) - { - m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameParts.p(), faultGeometryTypesToAppend[i]); - } - - RivCellSetEnum faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels(faultGeometryTypesToAppend); - m_reservoirGridPartManager->appendFaultLabelsStaticGeometryPartsToModel(frameParts.p(), faultLabelType); - - if (m_viewer) - { - cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); - if (frameScene) - { - frameScene->removeAllModels(); - frameScene->addModel(frameParts.p()); - frameParts->updateBoundingBoxesRecursive(); - } - } -#endif } else if (this->eclipsePropertyFilterCollection()->hasActiveFilters()) { cvf::ref frameParts = new cvf::ModelBasicList; + frameParts->setName("GridModel"); std::vector gridIndices; this->indicesToVisibleGrids(&gridIndices); @@ -603,7 +580,7 @@ void RimEclipseView::updateCurrentTimeStep() cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); if (frameScene) { - frameScene->removeAllModels(); + this->removeModelByName(frameScene, frameParts->name()); frameScene->addModel(frameParts.p()); frameParts->updateBoundingBoxesRecursive(); } @@ -662,40 +639,25 @@ void RimEclipseView::updateCurrentTimeStep() crossSectionCollection->applySingleColorEffect(); } - // Well pipes + // Simulation Well pipes if (m_viewer) { cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); if (frameScene) { - // Well pipes - // ---------- - cvf::String wellPipeModelName = "WellPipeModel"; - - this->removeModelByName(frameScene, wellPipeModelName); + // Simulation Well pipes cvf::ref wellPipeModelBasicList = new cvf::ModelBasicList; - wellPipeModelBasicList->setName(wellPipeModelName); + wellPipeModelBasicList->setName("SimWellPipeMod"); m_pipesPartManager->appendDynamicGeometryPartsToModel(wellPipeModelBasicList.p(), m_currentTimeStep); - m_pipesPartManager->updatePipeResultColor(m_currentTimeStep); wellPipeModelBasicList->updateBoundingBoxesRecursive(); - //printf("updateCurrentTimeStep: Add WellPipeModel to frameScene\n"); - frameScene->addModel(wellPipeModelBasicList.p()); - // Add well paths, if any - RimEclipseCase* eclCase = eclipseCase(); - RigCaseData* caseData = eclCase ? eclCase->reservoirData() : NULL; - RigMainGrid* mainGrid = caseData ? caseData->mainGrid() : NULL; - CVF_ASSERT(mainGrid); - - addWellPathsToScene(frameScene, - mainGrid->displayModelOffset(), - mainGrid->characteristicIJCellSize(), - currentActiveCellInfo()->geometryBoundingBox(), - m_reservoirGridPartManager->scaleTransform()); + this->removeModelByName(frameScene, wellPipeModelBasicList->name()); + frameScene->addModel(wellPipeModelBasicList.p()); + m_pipesPartManager->updatePipeResultColor(m_currentTimeStep); } } @@ -1569,35 +1531,6 @@ RimCase* RimEclipseView::ownerCase() return eclipseCase(); } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseView::addWellPathsToScene(cvf::Scene* scene, - const cvf::Vec3d& displayModelOffset, - double characteristicCellSize, - const cvf::BoundingBox& wellPathClipBoundingBox, - cvf::Transform* scaleTransform) -{ - CVF_ASSERT(scene); - CVF_ASSERT(scaleTransform); - - cvf::String wellPathModelName = "WellPathModel"; - this->removeModelByName(scene, wellPathModelName); - - // Append static Well Paths to model - cvf::ref wellPathModelBasicList = new cvf::ModelBasicList; - wellPathModelBasicList->setName(wellPathModelName); - - addWellPathsToModel(wellPathModelBasicList.p(), - displayModelOffset, - characteristicCellSize, - wellPathClipBoundingBox, - scaleTransform); - - scene->addModel(wellPathModelBasicList.p()); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 5849e04366..559dfb31a5 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -165,17 +165,11 @@ class RimEclipseView : public RimView void updateFaultColors(); void syncronizeWellsWithResults(); - void addWellPathsToScene(cvf::Scene* scene, - const cvf::Vec3d& displayModelOffset, - double characteristicCellSize, - const cvf::BoundingBox& wellPathClipBoundingBox, - cvf::Transform* scaleTransform); void clampCurrentTimestep(); virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility); - caf::PdmChildField m_propertyFilterCollection; caf::PdmPointer m_overridePropertyFilterCollection; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 3ff21bd6d1..6616625e1f 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -221,29 +221,32 @@ void RimGeoMechView::createDisplayModel() m_viewer->setMainScene(mainScene.p()); // Grid model - cvf::ref mainSceneModel = new cvf::ModelBasicList; - m_vizLogic->appendNoAnimPartsToModel(mainSceneModel.p()); - mainSceneModel->updateBoundingBoxesRecursive(); - mainScene->addModel(mainSceneModel.p()); + cvf::ref mainSceneGridVizModel = new cvf::ModelBasicList; + mainSceneGridVizModel->setName("GridModel"); + m_vizLogic->appendNoAnimPartsToModel(mainSceneGridVizModel.p()); + mainSceneGridVizModel->updateBoundingBoxesRecursive(); + mainScene->addModel(mainSceneGridVizModel.p()); // Well path model double characteristicCellSize = geoMechCase()->geoMechData()->femParts()->characteristicElementSize(); cvf::BoundingBox femBBox = geoMechCase()->geoMechData()->femParts()->boundingBox(); - cvf::ref wellPathModel = new cvf::ModelBasicList; - addWellPathsToModel(wellPathModel.p(), + + m_wellPathPipeVizModel->removeAllParts(); + addWellPathsToModel(m_wellPathPipeVizModel.p(), cvf::Vec3d(0, 0, 0), characteristicCellSize, femBBox, scaleTransform()); - mainScene->addModel(wellPathModel.p()); + + m_viewer->addStaticModelOnce(m_wellPathPipeVizModel.p()); - // Cross sections + // Cross sections - m_crossSectionModel->removeAllParts(); - crossSectionCollection->appendPartsToModel(m_crossSectionModel.p(), scaleTransform()); - m_viewer->addStaticModel(m_crossSectionModel.p()); + m_crossSectionVizModel->removeAllParts(); + crossSectionCollection->appendPartsToModel(m_crossSectionVizModel.p(), scaleTransform()); + m_viewer->addStaticModelOnce(m_crossSectionVizModel.p()); // If the animation was active before recreating everything, make viewer view current frame @@ -274,24 +277,14 @@ void RimGeoMechView::updateCurrentTimeStep() cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); if (frameScene) { - frameScene->removeAllModels(); - // Grid model cvf::ref frameParts = new cvf::ModelBasicList; + frameParts->setName("GridModel"); m_vizLogic->appendPartsToModel(m_currentTimeStep, frameParts.p()); frameParts->updateBoundingBoxesRecursive(); + + this->removeModelByName(frameScene, frameParts->name()); frameScene->addModel(frameParts.p()); - - // Well Path model - double characteristicCellSize = geoMechCase()->geoMechData()->femParts()->characteristicElementSize(); - cvf::BoundingBox femBBox = geoMechCase()->geoMechData()->femParts()->boundingBox(); - cvf::ref wellPathModel = new cvf::ModelBasicList; - addWellPathsToModel(wellPathModel.p(), - cvf::Vec3d(0, 0, 0), - characteristicCellSize, - femBBox, - scaleTransform()); - frameScene->addModel(wellPathModel.p()); } } diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 5331a59f55..75fbe324ab 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -123,11 +123,14 @@ RimView::RimView(void) m_previousGridModeMeshLinesWasFaults = false; - m_crossSectionModel = new cvf::ModelBasicList; - m_crossSectionModel->setName("CrossSectionModel"); + m_crossSectionVizModel = new cvf::ModelBasicList; + m_crossSectionVizModel->setName("CrossSectionModel"); - m_highlightModelBasicList = new cvf::ModelBasicList; - m_highlightModelBasicList->setName("HighlightModel"); + m_highlightVizModel = new cvf::ModelBasicList; + m_highlightVizModel->setName("HighlightModel"); + + m_wellPathPipeVizModel = new cvf::ModelBasicList; + m_wellPathPipeVizModel->setName("WellPathPipeModel"); } //-------------------------------------------------------------------------------------------------- @@ -822,10 +825,10 @@ void RimView::createHighlightAndGridBoxDisplayModelWithRedraw() //-------------------------------------------------------------------------------------------------- void RimView::createHighlightAndGridBoxDisplayModel() { - m_viewer->removeStaticModel(m_highlightModelBasicList.p()); + m_viewer->removeStaticModel(m_highlightVizModel.p()); m_viewer->removeStaticModel(m_viewer->gridBoxModel()); - m_highlightModelBasicList->removeAllParts(); + m_highlightVizModel->removeAllParts(); cvf::Collection parts; createPartCollectionFromSelection(&parts); @@ -833,16 +836,16 @@ void RimView::createHighlightAndGridBoxDisplayModel() { for (size_t i = 0; i < parts.size(); i++) { - m_highlightModelBasicList->addPart(parts[i].p()); + m_highlightVizModel->addPart(parts[i].p()); } - m_highlightModelBasicList->updateBoundingBoxesRecursive(); - m_viewer->addStaticModel(m_highlightModelBasicList.p()); + m_highlightVizModel->updateBoundingBoxesRecursive(); + m_viewer->addStaticModelOnce(m_highlightVizModel.p()); } if (showGridBox) { - m_viewer->addStaticModel(m_viewer->gridBoxModel()); + m_viewer->addStaticModelOnce(m_viewer->gridBoxModel()); } } diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 5200f119e1..d82ded7848 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -200,9 +200,10 @@ class RimView : public caf::PdmObject virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); cvf::ref m_currentReservoirCellVisibility; - - cvf::ref m_crossSectionModel; - cvf::ref m_highlightModelBasicList; + + cvf::ref m_wellPathPipeVizModel; + cvf::ref m_crossSectionVizModel; + cvf::ref m_highlightVizModel; private: RimViewLinker* viewLinkerIfMasterView() const; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 4e624bb288..644f8b966f 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -823,7 +823,7 @@ void caf::Viewer::navigationPolicyUpdate() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void caf::Viewer::addStaticModel(cvf::Model* model) +void caf::Viewer::addStaticModelOnce(cvf::Model* model) { if (m_staticModels.contains(model)) return; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index c4c132b6a7..3d760058b4 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -95,7 +95,7 @@ class Viewer : public caf::OpenGLWidget void removeAllFrames(); // Static models to be shown in all frames - void addStaticModel(cvf::Model* model); + void addStaticModelOnce(cvf::Model* model); void removeStaticModel(cvf::Model* model); void removeAllStaticModels(); From 40821a05a680515af9cfb5cdf27419ed1657aaf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 23 Nov 2015 13:23:25 +0100 Subject: [PATCH 117/290] (#166) Refactored to improve readability of geomech Intersection texture generation --- .../RivCrossSectionPartMgr.cpp | 116 ++++++++++-------- .../RivCrossSectionPartMgr.h | 12 +- 2 files changed, 76 insertions(+), 52 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 0afe4c9391..2fbe4c72dc 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -123,10 +123,10 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) timeStepIndex, cellResultColors->resultVariable()); - calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), - m_crossSectionGenerator->triangleToCellIndex(), - resultAccessor.p(), - mapper); + RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), + m_crossSectionGenerator->triangleToCellIndex(), + resultAccessor.p(), + mapper); RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), @@ -149,76 +149,90 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) if (!caseData) return; - const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); RigFemResultAddress resVarAddress = cellResultColors->resultAddress(); // Do a "Hack" to show elm nodal and not nodal POR results if (resVarAddress.resultPosType == RIG_NODAL && resVarAddress.fieldName == "POR-Bar") resVarAddress.resultPosType = RIG_ELEMENT_NODAL; - const std::vector& resultValues = caseData->femPartResults()->resultValues(resVarAddress, 0, (int)timeStepIndex); - const std::vector &vertexWeights = m_crossSectionGenerator->triangleVxToCellCornerInterpolationWeights(); + const std::vector& resultValues = caseData->femPartResults()->resultValues(resVarAddress, 0, (int)timeStepIndex); + bool isElementNodalResult = !(resVarAddress.resultPosType == RIG_NODAL); + RigFemPart* femPart = caseData->femParts()->part(0); + const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); + + RivCrossSectionPartMgr::calculateGeoMechTextureCoords(m_crossSectionFacesTextureCoords.p(), + vertexWeights, + resultValues, + isElementNodalResult, + femPart, + mapper); - bool isElementNodalResult = true; - RigFemPart* femPart = NULL; - if (resVarAddress.resultPosType == RIG_NODAL) - { - isElementNodalResult = false; - femPart = caseData->femParts()->part(0); - } + RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), + m_crossSectionFacesTextureCoords.p(), + mapper, + 1.0, + caf::FC_NONE, + geoView->isLightingDisabled()); + } +} - m_crossSectionFacesTextureCoords->resize(vertexWeights.size()); - if (resultValues.size() == 0) - { - m_crossSectionFacesTextureCoords->setAll(cvf::Vec2f(0.0, 1.0f)); - } - else - { - cvf::Vec2f* rawPtr = m_crossSectionFacesTextureCoords->ptr(); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::calculateGeoMechTextureCoords(cvf::Vec2fArray* textureCoords, + const std::vector &vertexWeights, + const std::vector &resultValues, + bool isElementNodalResult, + const RigFemPart* femPart, + const cvf::ScalarMapper* mapper) +{ + textureCoords->resize(vertexWeights.size()); + + if (resultValues.size() == 0) + { + textureCoords->setAll(cvf::Vec2f(0.0, 1.0f)); + } + else + { + cvf::Vec2f* rawPtr = textureCoords->ptr(); - int vxCount = static_cast(vertexWeights.size()); + int vxCount = static_cast(vertexWeights.size()); - #pragma omp parallel for schedule(dynamic) - for (int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx) +#pragma omp parallel for schedule(dynamic) + for (int triangleVxIdx = 0; triangleVxIdx < vxCount; ++triangleVxIdx) + { + float resValue = 0; + int weightCount = vertexWeights[triangleVxIdx].size(); + for (int wIdx = 0; wIdx < weightCount; ++wIdx) { - float resValue = 0; - int weightCount = vertexWeights[triangleVxIdx].size(); - for (int wIdx = 0; wIdx < weightCount; ++wIdx) - { - size_t resIdx = isElementNodalResult ? vertexWeights[triangleVxIdx].vxId(wIdx) : - femPart->nodeIdxFromElementNodeResultIdx(vertexWeights[triangleVxIdx].vxId(wIdx)); - resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight(wIdx); - } - - if (resValue == HUGE_VAL || resValue != resValue) // a != a is true for NAN's - { - rawPtr[triangleVxIdx][1] = 1.0f; - } - else - { - rawPtr[triangleVxIdx] = mapper->mapToTextureCoord(resValue); - } + size_t resIdx = isElementNodalResult ? vertexWeights[triangleVxIdx].vxId(wIdx) : + femPart->nodeIdxFromElementNodeResultIdx(vertexWeights[triangleVxIdx].vxId(wIdx)); + resValue += resultValues[resIdx] * vertexWeights[triangleVxIdx].weight(wIdx); } - } - RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), - m_crossSectionFacesTextureCoords.p(), - mapper, - 1.0, - caf::FC_NONE, - geoView->isLightingDisabled()); + if (resValue == HUGE_VAL || resValue != resValue) // a != a is true for NAN's + { + rawPtr[triangleVxIdx][1] = 1.0f; + } + else + { + rawPtr[triangleVxIdx] = mapper->mapToTextureCoord(resValue); + } + } } } + + //-------------------------------------------------------------------------------------------------- -/// Calculates the texture coordinates in a "nearly" one dimentional texture. +/// Calculates the texture coordinates in a "nearly" one dimensional texture. /// Undefined values are coded with a y-texturecoordinate value of 1.0 instead of the normal 0.5 //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, const std::vector& triangleToCellIdxMap, const RigResultAccessor* resultAccessor, - const cvf::ScalarMapper* mapper) const + const cvf::ScalarMapper* mapper) { if (!resultAccessor) return; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 62c084756d..28f1332ab7 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -52,6 +52,7 @@ class RivCrossSectionPartMgr : public cvf::Object void applySingleColorEffect(); void updateCellResultColor(size_t timeStepIndex); + void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); void appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); @@ -61,7 +62,16 @@ class RivCrossSectionPartMgr : public cvf::Object void computeData(); cvf::Vec3d extrusionDirection(const std::vector& polyline) const; - void calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, const std::vector& triangleToCellIdxMap, const RigResultAccessor* resultAccessor, const cvf::ScalarMapper* mapper) const; + static void calculateEclipseTextureCoordinates(cvf::Vec2fArray* textureCoords, + const std::vector& triangleToCellIdxMap, + const RigResultAccessor* resultAccessor, + const cvf::ScalarMapper* mapper); + static void calculateGeoMechTextureCoords(cvf::Vec2fArray* textureCoords, + const std::vector &vertexWeights, + const std::vector &resultValues, + bool isElementNodalResult, + const RigFemPart* femPart, + const cvf::ScalarMapper* mapper); cvf::ref createHexGridInterface(); private: From 0907232a7e872b9aa3e77680574821515ba85cee Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 11:44:32 +0100 Subject: [PATCH 118/290] (#266) Do not show tick marks at start and end of legend --- .../GridBox/RivGridBoxGenerator.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 8e3784eab2..bb5c4523f9 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -501,8 +501,19 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection vertices->add(point); tickPoint = point + tickLength*tickMarkDir;; vertices->add(tickPoint); - indices->add(2 * static_cast(i)); - indices->add(2 * static_cast(i) + 1); + + if (i == 0 || i == displayCoordsTickValues->size() - 1) + { + // Do not show tick mark at ends of legend + // Add to list of indices to keep surrounding code unchanged + indices->add(2 * static_cast(i)); + indices->add(2 * static_cast(i)); + } + else + { + indices->add(2 * static_cast(i)); + indices->add(2 * static_cast(i) + 1); + } } // Backbone of legend From 2ae92c6a18819600b456313a730c6229730cf659 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 11:50:37 +0100 Subject: [PATCH 119/290] (#266) Hide tickmarks at first and last tick mark position --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index bb5c4523f9..89b27c10af 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -565,7 +565,12 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection // Do not draw legend labels at first/last tick mark for (size_t idx = 1; idx < domainCoordsTickValues->size() - 1; idx++) { - geo->addText(cvf::String(domainCoordsTickValues->at(idx)), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); + double legendValue = domainCoordsTickValues->at(idx); + if (axis == Z_AXIS) + { + legendValue = -domainCoordsTickValues->at(idx); + } + geo->addText(cvf::String(legendValue), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); } cvf::ref part = new cvf::Part; From 469ffdf920d261a784fecd7ac2908b60a6050a35 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 13:29:11 +0100 Subject: [PATCH 120/290] Fwk : Fixed typo --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 12 ++++++------ Fwk/AppFwk/cafViewer/cafViewer.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 644f8b966f..a0f920b71c 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -83,7 +83,7 @@ caf::Viewer::Viewer(const QGLFormat& format, QWidget* parent) m_releaseOGLResourcesEachFrame(false), m_paintCounter(0), m_navigationPolicyEnabled(true), - m_isOverlyPaintingEnabled(true) + m_isOverlayPaintingEnabled(true) { m_layoutWidget = parentWidget(); @@ -421,7 +421,7 @@ void caf::Viewer::paintEvent(QPaintEvent* event) // If Qt overlay painting is enabled, paint to an QImage, and set it to the cvf::OverlayImage - if (m_isOverlyPaintingEnabled || m_showPerfInfoHud) + if (m_isOverlayPaintingEnabled || m_showPerfInfoHud) { // Set up image to draw to, and painter if (m_overlayPaintingQImage.size() != this->size()) @@ -434,7 +434,7 @@ void caf::Viewer::paintEvent(QPaintEvent* event) // Call virtual method to allow subclasses to paint on the OpenGlCanvas - if (m_isOverlyPaintingEnabled) + if (m_isOverlayPaintingEnabled) { this->paintOverlayItems(&overlyPainter); } @@ -785,7 +785,7 @@ int caf::Viewer::currentFrameIndex() //-------------------------------------------------------------------------------------------------- bool caf::Viewer::isOverlyPaintingEnabled() const { - return m_isOverlyPaintingEnabled; + return m_isOverlayPaintingEnabled; } //-------------------------------------------------------------------------------------------------- @@ -793,7 +793,7 @@ bool caf::Viewer::isOverlyPaintingEnabled() const //-------------------------------------------------------------------------------------------------- void caf::Viewer::enableOverlyPainting(bool val) { - m_isOverlyPaintingEnabled = val; + m_isOverlayPaintingEnabled = val; updateOverlayImagePresence(); } @@ -802,7 +802,7 @@ void caf::Viewer::enableOverlyPainting(bool val) //-------------------------------------------------------------------------------------------------- void caf::Viewer::updateOverlayImagePresence() { - if (m_isOverlyPaintingEnabled || m_showPerfInfoHud) + if (m_isOverlayPaintingEnabled || m_showPerfInfoHud) { m_mainRendering->addOverlayItem(m_overlayImage.p()); } diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 3d760058b4..287c8415a8 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -191,7 +191,7 @@ public slots: bool m_releaseOGLResourcesEachFrame; QPointer m_layoutWidget; - bool m_isOverlyPaintingEnabled; + bool m_isOverlayPaintingEnabled; cvf::ref m_overlayTextureImage; cvf::ref m_overlayImage; QImage m_overlayPaintingQImage; From ca9b1cf6833bde202b2cebf18c00ebc57adb43d6 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 13:31:01 +0100 Subject: [PATCH 121/290] (#51) Use contrast color for overlay item text and grid colors --- .../GridBox/RivGridBoxGenerator.cpp | 2 +- .../GridBox/RivGridBoxGenerator.h | 2 +- ApplicationCode/UserInterface/RiuViewer.cpp | 79 ++++++++++++++----- ApplicationCode/UserInterface/RiuViewer.h | 8 ++ 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 89b27c10af..905f06be32 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -649,7 +649,7 @@ cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f backgroundColor) +void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f& backgroundColor) { double adjustmentFactor = 0.3; diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h index a5268af07f..2cba4cf647 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.h @@ -48,7 +48,7 @@ class RivGridBoxGenerator void setScaleZ(double scaleZ); void setDisplayModelOffset(cvf::Vec3d offset); void setGridBoxDomainCoordBoundingBox(const cvf::BoundingBox& boundingBox); - void updateFromBackgroundColor(const cvf::Color3f backgroundColor); + void updateFromBackgroundColor(const cvf::Color3f& backgroundColor); void createGridBoxParts(); diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 16d1a1baa5..4be74f84ea 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -42,12 +42,13 @@ #include "cvfCamera.h" #include "cvfFont.h" +#include "cvfOpenGLResourceManager.h" #include "cvfOverlayAxisCross.h" +#include "cvfOverlayScalarMapperLegend.h" #include "cvfRenderQueueSorter.h" #include "cvfRenderSequence.h" #include "cvfRendering.h" #include "cvfScene.h" -#include "cvfOpenGLResourceManager.h" #include #include @@ -459,6 +460,8 @@ void RiuViewer::addColorLegendToBottomLeftCorner(cvf::OverlayItem* legend) if (legend) { + updateLegendTextAndTickMarkColor(legend); + legend->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); firstRendering->addOverlayItem(legend); @@ -567,6 +570,8 @@ void RiuViewer::updateGridBoxData() } m_gridBoxGenerator->createGridBoxParts(); + + updateTextAndTickMarkColorForOverlayItems(); } } @@ -584,25 +589,63 @@ cvf::Model* RiuViewer::gridBoxModel() const void RiuViewer::setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel) { m_axisCross->setAxisLabels(xLabel, yLabel, zLabel); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateLegendTextAndTickMarkColor(cvf::OverlayItem* legend) +{ + if (m_rimView.isNull()) return; - // The axis cross is designed for short labels, longer labels causes clipping of text - // The commented out code adjust the size of the axis cross, and this makes the axis cross labels visible - // Side effect is also that the axis cross is zoomed (will be larger) - /* - size_t maxAxisLabelLength = xLabel.size(); - if (yLabel.size() > maxAxisLabelLength) maxAxisLabelLength = yLabel.size(); - if (zLabel.size() > maxAxisLabelLength) maxAxisLabelLength = zLabel.size(); + cvf::Color3f contrastColor = computeContrastColor(); - if (maxAxisLabelLength > 4) + cvf::OverlayScalarMapperLegend* scalarMapperLegend = dynamic_cast(legend); + if (scalarMapperLegend) + { + scalarMapperLegend->setColor(contrastColor); + scalarMapperLegend->setLineColor(contrastColor); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateTextAndTickMarkColorForOverlayItems() +{ + for (size_t i = 0; i < m_visibleLegends.size(); i++) + { + updateLegendTextAndTickMarkColor(m_visibleLegends.at(i)); + } + + updateAxisCrossTextColor(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateAxisCrossTextColor() +{ + cvf::Color3f contrastColor = computeContrastColor(); + + m_axisCross->setAxisLabelsColor(contrastColor); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiuViewer::computeContrastColor() const +{ + cvf::Color3f contrastColor = cvf::Color3f::WHITE; + + if (m_rimView.notNull()) + { + cvf::Color3f backgroundColor = m_rimView->backgroundColor; + if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) { - if (maxAxisLabelLength < 6) - { - m_axisCross->setSize(cvf::Vec2ui(140, 140)); - } - else if (maxAxisLabelLength < 8) - { - m_axisCross->setSize(cvf::Vec2ui(160, 160)); - } + contrastColor = cvf::Color3f::BLACK; } - */ + } + + return contrastColor; } diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 3a52f93e66..9adceb68e5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -39,6 +39,7 @@ class QProgressBar; namespace cvf { + class Color3f; class Model; class OverlayItem; class Part; @@ -95,6 +96,13 @@ public slots: virtual void optimizeClippingPlanes(); private: + void updateTextAndTickMarkColorForOverlayItems(); + void updateLegendTextAndTickMarkColor(cvf::OverlayItem* legend); + + cvf::Color3f computeContrastColor() const; + + void updateAxisCrossTextColor(); + void paintOverlayItems(QPainter* painter); void mouseReleaseEvent(QMouseEvent* event); From 95f500fefd7baad679c8844ea3af9593f7119ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 23 Nov 2015 14:26:45 +0100 Subject: [PATCH 122/290] (#166) Added 10% of the well paths start to end XY lenght as extents. --- .../ProjectDataModel/RimCrossSection.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 5687944c07..d8237bb602 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -208,12 +208,12 @@ RimEclipseWellCollection* RimCrossSection::simulationWellCollection() //-------------------------------------------------------------------------------------------------- std::vector< std::vector > RimCrossSection::polyLines() const { - std::vector< std::vector > line; + std::vector< std::vector > lines; if (type == CS_WELL_PATH) { if (wellPath) { - line.push_back(wellPath->wellPathGeometry()->m_wellPathPoints); + lines.push_back(wellPath->wellPathGeometry()->m_wellPathPoints); } } else if (type == CS_SIMULATION_WELL) @@ -225,7 +225,20 @@ std::vector< std::vector > RimCrossSection::polyLines() const } - return line; + if (type == CS_WELL_PATH || type == CS_SIMULATION_WELL) + { + for (int lIdx = 0; lIdx < lines.size(); ++lIdx) + { + cvf::Vec3d startToEnd = (lines[lIdx].back() - lines[lIdx].front()); + startToEnd[2] = 0.0; + cvf::Vec3d newStart = lines[lIdx].front() - startToEnd * 0.1; + cvf::Vec3d newEnd = lines[lIdx].back() + startToEnd * 0.1; + lines[lIdx].insert(lines[lIdx].begin(), newStart); + lines[lIdx].push_back(newEnd); + } + } + + return lines; } //-------------------------------------------------------------------------------------------------- From 6cd4e8a0b7b3f43a7d620babd342bf6e318feb2b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 23 Nov 2015 15:24:03 +0100 Subject: [PATCH 123/290] (#166) Added support for ternary result mapping Removed obsolete interface RigResultAccessor2d --- .../RivCrossSectionPartMgr.cpp | 24 +++---- .../RivTernaryTextureCoordsCreator.cpp | 71 +++++++++++++++++-- .../RivTernaryTextureCoordsCreator.h | 13 +++- .../ReservoirDataModel/CMakeLists_files.cmake | 1 - .../ReservoirDataModel/RigResultAccessor2d.h | 37 ---------- .../RigTernaryResultAccessor2d.cpp | 49 +++++++++++++ .../RigTernaryResultAccessor2d.h | 11 +-- 7 files changed, 144 insertions(+), 62 deletions(-) delete mode 100644 ApplicationCode/ReservoirDataModel/RigResultAccessor2d.h diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 2fbe4c72dc..9496c14e14 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -21,6 +21,9 @@ #include "RigCaseCellResultsData.h" #include "RigCaseData.h" +#include "RigFemPartCollection.h" +#include "RigFemPartResultsCollection.h" +#include "RigGeoMechCaseData.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" @@ -28,22 +31,20 @@ #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseView.h" +#include "RimGeoMechCase.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechView.h" #include "RimTernaryLegendConfig.h" #include "RivResultToTextureMapper.h" #include "RivScalarMapperUtils.h" #include "RivTernaryScalarMapper.h" +#include "RivTernaryTextureCoordsCreator.h" #include "cvfDrawableGeo.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetDirect.h" -#include "RimGeoMechView.h" -#include "RimGeoMechCase.h" -#include "RigGeoMechCaseData.h" -#include "RigFemPartCollection.h" -#include "RimGeoMechCellColors.h" -#include "RigFemPartResultsCollection.h" //-------------------------------------------------------------------------------------------------- @@ -94,14 +95,9 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) { if (cellResultColors->isTernarySaturationSelected()) { - //RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), - // timeStepIndex, - // m_grid->gridIndex(), - // m_nativeCrossSectionGenerator->quadToCellFaceMapper()); - // - //texturer.createTextureCoords(m_nativeCrossSectionFacesTextureCoords.p()); - - CVF_ASSERT(false); // Todo + RivTernaryTextureCoordsCreator texturer(cellResultColors, cellResultColors->ternaryLegendConfig(), timeStepIndex); + + texturer.createTextureCoords(m_crossSectionFacesTextureCoords.p(), m_crossSectionGenerator->triangleToCellIndex()); const RivTernaryScalarMapper* mapper = cellResultColors->ternaryLegendConfig()->scalarMapper(); RivScalarMapperUtils::applyTernaryTextureResultsToPart(m_crossSectionFaces.p(), diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp index 6b6d3b0846..bbe5cb3db7 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp @@ -44,10 +44,30 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( size_t gridIndex, const cvf::StructGridQuadToCellFaceMapper* quadMapper) { - RigCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->reservoirData(); - + CVF_ASSERT(quadMapper); m_quadMapper = quadMapper; - CVF_ASSERT(quadMapper && eclipseCase ); + + initData(cellResultColors, ternaryLegendConfig, timeStepIndex, gridIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( + RimEclipseCellColors* cellResultColors, + RimTernaryLegendConfig* ternaryLegendConfig, + size_t timeStepIndex) + : m_quadMapper(NULL) +{ + initData(cellResultColors, ternaryLegendConfig, timeStepIndex, 0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernaryTextureCoordsCreator::initData(RimEclipseCellColors* cellResultColors, RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex, size_t gridIndex) +{ + RigCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->reservoirData(); size_t resTimeStepIdx = timeStepIndex; @@ -58,11 +78,11 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( cvf::ref soil = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SOIL"); cvf::ref sgas = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SGAS"); cvf::ref swat = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SWAT"); - + m_resultAccessor = new RigTernaryResultAccessor(); m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); - cvf::ref pipeInCellEval = new RigPipeInCellEvaluator( cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), + cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), eclipseCase->gridCellToWellIndex(gridIndex)); const RivTernaryScalarMapper* mapper = ternaryLegendConfig->scalarMapper(); @@ -76,9 +96,20 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( //-------------------------------------------------------------------------------------------------- void RivTernaryTextureCoordsCreator::createTextureCoords(cvf::Vec2fArray* quadTextureCoords) { + CVF_ASSERT(m_quadMapper.notNull()); createTextureCoords(quadTextureCoords, m_quadMapper.p(), m_resultAccessor.p(), m_texMapper.p()); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernaryTextureCoordsCreator::createTextureCoords(cvf::Vec2fArray* triTextureCoords, const std::vector& triangleToCellIdx) +{ + CVF_ASSERT(m_quadMapper.isNull()); + + createTextureCoords(triTextureCoords, triangleToCellIdx, m_resultAccessor.p(), m_texMapper.p()); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -113,3 +144,33 @@ void RivTernaryTextureCoordsCreator::createTextureCoords( } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTernaryTextureCoordsCreator::createTextureCoords(cvf::Vec2fArray* textureCoords, const std::vector& triangleToCellIdx, const RigTernaryResultAccessor* resultAccessor, const RivTernaryResultToTextureMapper* texMapper) +{ + CVF_ASSERT(textureCoords && resultAccessor && texMapper); + + size_t numVertices = triangleToCellIdx.size() * 3; + textureCoords->resize(numVertices); + cvf::Vec2f* rawPtr = textureCoords->ptr(); + + cvf::Vec2d resultValue; + cvf::Vec2f texCoord; + +#pragma omp parallel for private(texCoord, resultValue) + for (int i = 0; i < static_cast(triangleToCellIdx.size()); i++) + { + size_t cellIdx = triangleToCellIdx[i]; + + resultValue = resultAccessor->cellScalarGlobIdx(cellIdx); + texCoord = texMapper->getTexCoord(resultValue.x(), resultValue.y(), cellIdx); + + size_t j; + for (j = 0; j < 3; j++) + { + rawPtr[i * 3 + j] = texCoord; + } + } +} diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h index c617a34ed2..57b602571e 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h @@ -41,20 +41,31 @@ namespace cvf class RivTernaryTextureCoordsCreator { public: - RivTernaryTextureCoordsCreator( RimEclipseCellColors* cellResultColors, + RivTernaryTextureCoordsCreator( RimEclipseCellColors* cellResultColors, RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex, size_t gridIndex, const cvf::StructGridQuadToCellFaceMapper* quadMapper); + RivTernaryTextureCoordsCreator( RimEclipseCellColors* cellResultColors, + RimTernaryLegendConfig* ternaryLegendConfig, + size_t timeStepIndex); + void createTextureCoords(cvf::Vec2fArray* quadTextureCoords); + void createTextureCoords(cvf::Vec2fArray* triTextureCoords, const std::vector& triangleToCellIdx); private: + void initData(RimEclipseCellColors* cellResultColors, RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex, size_t gridIndex); + static void createTextureCoords(cvf::Vec2fArray* quadTextureCoords, const cvf::StructGridQuadToCellFaceMapper* quadMapper, const RigTernaryResultAccessor* resultAccessor, const RivTernaryResultToTextureMapper* texMapper); + static void createTextureCoords(cvf::Vec2fArray* triTextureCoords, + const std::vector& triangleToCellIdx, + const RigTernaryResultAccessor* resultAccessor, + const RivTernaryResultToTextureMapper* texMapper); private: cvf::cref m_quadMapper; cvf::ref m_resultAccessor; diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 3afd3f2d9c..92c65ad47c 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -32,7 +32,6 @@ ${CEE_CURRENT_LIST_DIR}RigNNCData.h ${CEE_CURRENT_LIST_DIR}cvfGeometryTools.h ${CEE_CURRENT_LIST_DIR}cvfGeometryTools.inl ${CEE_CURRENT_LIST_DIR}RigPipeInCellEvaluator.h -${CEE_CURRENT_LIST_DIR}RigResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigTernaryResultAccessor2d.h ${CEE_CURRENT_LIST_DIR}RigEclipseNativeStatCalc.h ${CEE_CURRENT_LIST_DIR}RigEclipseNativeVisibleCellsStatCalc.h diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessor2d.h b/ApplicationCode/ReservoirDataModel/RigResultAccessor2d.h deleted file mode 100644 index 2e86aa1f78..0000000000 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessor2d.h +++ /dev/null @@ -1,37 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) Statoil ASA -// Copyright (C) Ceetron Solutions AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#pragma once - -#include "cvfBase.h" -#include "cvfObject.h" -#include "cvfVector2.h" -#include "cvfStructGrid.h" - -//================================================================================================== -/// -//================================================================================================== -class RigResultAccessor2d : public cvf::Object -{ -public: - virtual cvf::Vec2d cellScalar(size_t gridLocalCellIndex) const = 0; - virtual cvf::Vec2d cellFaceScalar(size_t gridLocalCellIndex, cvf::StructGridInterface::FaceType faceId) const = 0; -}; diff --git a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp index 570a22f799..8dd56f57dd 100644 --- a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp +++ b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp @@ -96,3 +96,52 @@ cvf::Vec2d RigTernaryResultAccessor::cellFaceScalar(size_t gridLocalCellIndex, c { return cellScalar(gridLocalCellIndex); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2d RigTernaryResultAccessor::cellScalarGlobIdx(size_t globCellIndex) const +{ + double soil = 0.0; + double sgas = 0.0; + + if (m_soilAccessor.notNull()) + { + soil = m_soilAccessor->cellScalarGlobIdx(globCellIndex); + + if (m_sgasAccessor.notNull()) + { + sgas = m_sgasAccessor->cellScalarGlobIdx(globCellIndex); + } + else if (m_swatAccessor.notNull()) + { + sgas = 1.0 - soil - m_swatAccessor->cellScalarGlobIdx(globCellIndex); + } + else + { + sgas = 1.0 - soil; + } + } + else + { + if (m_sgasAccessor.notNull()) + { + sgas = m_sgasAccessor->cellScalarGlobIdx(globCellIndex); + + if (m_swatAccessor.notNull()) + { + soil = 1.0 - sgas - m_swatAccessor->cellScalarGlobIdx(globCellIndex); + } + else + { + soil = 1.0 - sgas; + } + } + else if (m_swatAccessor.notNull()) + { + soil = 1.0 - m_swatAccessor->cellScalarGlobIdx(globCellIndex); + } + } + + return cvf::Vec2d(soil, sgas); +} diff --git a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.h b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.h index a85015e8b7..efe4758f86 100644 --- a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.h +++ b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.h @@ -19,13 +19,15 @@ #pragma once -#include "RigResultAccessor2d.h" #include "RigResultAccessor.h" +#include "cvfVector2.h" + + //================================================================================================== /// //================================================================================================== -class RigTernaryResultAccessor : public RigResultAccessor2d +class RigTernaryResultAccessor : public cvf::Object { public: RigTernaryResultAccessor(); @@ -35,8 +37,9 @@ class RigTernaryResultAccessor : public RigResultAccessor2d /// Returns [SOIL, SGAS] regardless of which one of the three is missing. if Soil or SWat is missing, it is calculated /// based on the two others - virtual cvf::Vec2d cellScalar(size_t gridLocalCellIndex) const; - virtual cvf::Vec2d cellFaceScalar(size_t gridLocalCellIndex, cvf::StructGridInterface::FaceType faceId) const; + cvf::Vec2d cellScalar(size_t gridLocalCellIndex) const; + cvf::Vec2d cellFaceScalar(size_t gridLocalCellIndex, cvf::StructGridInterface::FaceType faceId) const; + cvf::Vec2d cellScalarGlobIdx(size_t globCellIndex) const; private: cvf::ref m_soilAccessor; From 60df95843c23a82df9488a2ffa865731102e136a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 09:59:25 +0100 Subject: [PATCH 124/290] (#166) Improvements to ternary result visualization Show undefined in regions with no results Always use time step zero for static results Allow texture coordinate creation without using RigPipeInCellEvaluator --- .../RivCrossSectionPartMgr.cpp | 34 ++++++++++++----- .../RivTernaryResultToTextureMapper.h | 14 ++++++- .../RivTernaryScalarMapper.cpp | 5 +-- .../RivTernaryTextureCoordsCreator.cpp | 38 ++++++++++++------- .../RivTernaryTextureCoordsCreator.h | 2 - .../RigTernaryResultAccessor2d.cpp | 16 ++++++++ 6 files changed, 79 insertions(+), 30 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 9496c14e14..f5b2407fe1 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -112,17 +112,31 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) CVF_ASSERT(m_crossSectionGenerator.notNull()); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); - - cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), - 0, - RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), - timeStepIndex, - cellResultColors->resultVariable()); + cvf::ref resultAccessor; + + if (RimDefines::isPerCellFaceResult(cellResultColors->resultVariable())) + { + resultAccessor = new RigHugeValResultAccessor; + } + else + { + size_t adjustedTimeStepIndex = timeStepIndex; + if (cellResultColors->hasStaticResult()) + { + adjustedTimeStepIndex = 0; + } + + resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), + 0, + RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), + adjustedTimeStepIndex, + cellResultColors->resultVariable()); + } RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), - m_crossSectionGenerator->triangleToCellIndex(), - resultAccessor.p(), - mapper); + m_crossSectionGenerator->triangleToCellIndex(), + resultAccessor.p(), + mapper); RivScalarMapperUtils::applyTextureResultsToPart(m_crossSectionFaces.p(), @@ -131,7 +145,7 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) 1.0, caf::FC_NONE, eclipseView->isLightingDisabled()); - } + } } } diff --git a/ApplicationCode/ModelVisualization/RivTernaryResultToTextureMapper.h b/ApplicationCode/ModelVisualization/RivTernaryResultToTextureMapper.h index fb43d44094..bf1094672d 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryResultToTextureMapper.h +++ b/ApplicationCode/ModelVisualization/RivTernaryResultToTextureMapper.h @@ -39,7 +39,19 @@ class RivTernaryResultToTextureMapper : public cvf::Object cvf::Vec2f getTexCoord(double soil, double sgas, size_t cellIndex) const { - bool isTransparent = m_pipeInCellEvaluator->isWellPipeInCell(cellIndex); + if (soil == HUGE_VAL || soil != soil || + sgas == HUGE_VAL || sgas != sgas) // a != a is true for NAN's + { + cvf::Vec2f texCoord(1.0, 1.0); + return texCoord; + } + + bool isTransparent = false; + + if (m_pipeInCellEvaluator.notNull()) + { + isTransparent = m_pipeInCellEvaluator->isWellPipeInCell(cellIndex); + } return m_scalarMapper->mapToTextureCoord(soil, sgas, isTransparent); } diff --git a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp index 9975b949f3..1f68af359a 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryScalarMapper.cpp @@ -77,10 +77,7 @@ bool RivTernaryScalarMapper::updateTexture(cvf::TextureImage* image, float opaci CVF_ASSERT(image); image->allocate(m_textureSize.x(), m_textureSize.y()); - // For now fill with white so we can see any errors more easily - image->fill(cvf::Color4ub(cvf::Color3::WHITE)); - - + image->fill(cvf::Color4ub(cvf::Color3ub(m_undefScalarColor))); cvf::uint halfTextureHeight = m_textureSize.y() / 2; diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp index bbe5cb3db7..05774f17ab 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp @@ -47,7 +47,28 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( CVF_ASSERT(quadMapper); m_quadMapper = quadMapper; - initData(cellResultColors, ternaryLegendConfig, timeStepIndex, gridIndex); + RigCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->reservoirData(); + + size_t resTimeStepIdx = timeStepIndex; + + if (cellResultColors->hasStaticResult()) resTimeStepIdx = 0; + + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); + + cvf::ref soil = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SOIL"); + cvf::ref sgas = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SGAS"); + cvf::ref swat = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SWAT"); + + m_resultAccessor = new RigTernaryResultAccessor(); + m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); + + cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), + eclipseCase->gridCellToWellIndex(gridIndex)); + + const RivTernaryScalarMapper* mapper = ternaryLegendConfig->scalarMapper(); + + m_texMapper = new RivTernaryResultToTextureMapper(mapper, pipeInCellEval.p()); + CVF_ASSERT(m_texMapper.notNull()); } //-------------------------------------------------------------------------------------------------- @@ -58,14 +79,6 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex) : m_quadMapper(NULL) -{ - initData(cellResultColors, ternaryLegendConfig, timeStepIndex, 0); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RivTernaryTextureCoordsCreator::initData(RimEclipseCellColors* cellResultColors, RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex, size_t gridIndex) { RigCaseData* eclipseCase = cellResultColors->reservoirView()->eclipseCase()->reservoirData(); @@ -75,6 +88,7 @@ void RivTernaryTextureCoordsCreator::initData(RimEclipseCellColors* cellResultCo RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); + size_t gridIndex = 0; cvf::ref soil = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SOIL"); cvf::ref sgas = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SGAS"); cvf::ref swat = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SWAT"); @@ -82,12 +96,10 @@ void RivTernaryTextureCoordsCreator::initData(RimEclipseCellColors* cellResultCo m_resultAccessor = new RigTernaryResultAccessor(); m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); - cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), - eclipseCase->gridCellToWellIndex(gridIndex)); - const RivTernaryScalarMapper* mapper = ternaryLegendConfig->scalarMapper(); - m_texMapper = new RivTernaryResultToTextureMapper(mapper, pipeInCellEval.p()); + // Create a texture mapper without detecting transparency using RigPipeInCellEvaluator + m_texMapper = new RivTernaryResultToTextureMapper(mapper, NULL); CVF_ASSERT(m_texMapper.notNull()); } diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h index 57b602571e..d9e767ab0c 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.h @@ -55,8 +55,6 @@ class RivTernaryTextureCoordsCreator void createTextureCoords(cvf::Vec2fArray* triTextureCoords, const std::vector& triangleToCellIdx); private: - void initData(RimEclipseCellColors* cellResultColors, RimTernaryLegendConfig* ternaryLegendConfig, size_t timeStepIndex, size_t gridIndex); - static void createTextureCoords(cvf::Vec2fArray* quadTextureCoords, const cvf::StructGridQuadToCellFaceMapper* quadMapper, const RigTernaryResultAccessor* resultAccessor, diff --git a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp index 8dd56f57dd..98ff183e45 100644 --- a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp +++ b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp @@ -109,6 +109,11 @@ cvf::Vec2d RigTernaryResultAccessor::cellScalarGlobIdx(size_t globCellIndex) con { soil = m_soilAccessor->cellScalarGlobIdx(globCellIndex); + if (soil == HUGE_VAL) + { + return cvf::Vec2d(HUGE_VAL, HUGE_VAL); + } + if (m_sgasAccessor.notNull()) { sgas = m_sgasAccessor->cellScalarGlobIdx(globCellIndex); @@ -128,6 +133,11 @@ cvf::Vec2d RigTernaryResultAccessor::cellScalarGlobIdx(size_t globCellIndex) con { sgas = m_sgasAccessor->cellScalarGlobIdx(globCellIndex); + if (sgas == HUGE_VAL) + { + return cvf::Vec2d(HUGE_VAL, HUGE_VAL); + } + if (m_swatAccessor.notNull()) { soil = 1.0 - sgas - m_swatAccessor->cellScalarGlobIdx(globCellIndex); @@ -139,6 +149,12 @@ cvf::Vec2d RigTernaryResultAccessor::cellScalarGlobIdx(size_t globCellIndex) con } else if (m_swatAccessor.notNull()) { + double swat = m_swatAccessor->cellScalarGlobIdx(globCellIndex); + if (swat == HUGE_VAL) + { + return cvf::Vec2d(HUGE_VAL, HUGE_VAL); + } + soil = 1.0 - m_swatAccessor->cellScalarGlobIdx(globCellIndex); } } From 369f3c65d86f0bd5a188b7f9cea40c23095481ed Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 10:04:02 +0100 Subject: [PATCH 125/290] Linux fix --- .../ReservoirDataModel/RigTernaryResultAccessor2d.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp index 98ff183e45..3bb0d18e0a 100644 --- a/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp +++ b/ApplicationCode/ReservoirDataModel/RigTernaryResultAccessor2d.cpp @@ -21,6 +21,7 @@ #include "RigResultAccessor.h" +#include // Needed for HUGE_VAL on Linux //-------------------------------------------------------------------------------------------------- /// From 419fd28b0298dc20ce70dda2ad91e8a8fdb31cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 24 Nov 2015 10:59:49 +0100 Subject: [PATCH 126/290] Upped version number to 1.5.101-dev after Sprint 9. --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 2dcf9847ee..3fa852e2f3 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 100) +set(CMAKE_PATCH_VERSION 101) set(DEV_VERSION "-dev") From c588a1fe699beea182034bcb44d545b3d803e437 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 11:35:04 +0100 Subject: [PATCH 127/290] (#645) Convert step names to dates for plotting in Result Plot --- .../ProjectDataModel/RimGeoMechCase.cpp | 55 +++++++++++++++++++ .../ProjectDataModel/RimGeoMechCase.h | 6 ++ .../RiuSelectionChangedHandler.cpp | 20 +++++-- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index 366c2d1e82..d6f5fbe69b 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -213,3 +213,58 @@ cvf::BoundingBox RimGeoMechCase::allCellsBoundingBox() const return cvf::BoundingBox(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechCase::dateTimeVectorFromTimeStepStrings(const QStringList& timeStepStrings) +{ + std::vector dates; + + QString dateFormat = "ddMMyyyy"; + + for (int i = 0; i < timeStepStrings.size(); i++) + { + QString timeStepString = timeStepStrings[i]; + + QString dateStr = subStringOfDigits(timeStepString, dateFormat.size()); + + QDateTime dateTime = QDateTime::fromString(dateStr, dateFormat); + if (dateTime.isValid()) + { + dates.push_back(dateTime); + } + } + + return dates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechCase::subStringOfDigits(const QString& inputString, int numberOfDigitsToFind) +{ + for (int j = 0; j < inputString.size(); j++) + { + if (inputString.at(j).isDigit()) + { + QString digitString; + + for (int k = 0; k < numberOfDigitsToFind; k++) + { + if (j + k < inputString.size() && inputString.at(j + k).isDigit()) + { + digitString += inputString.at(j + k); + } + } + + if (digitString.size() == numberOfDigitsToFind) + { + return digitString; + } + } + } + + return ""; +} + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h index ff65abe38e..320f3fd37c 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h @@ -28,6 +28,8 @@ #include "cvfObject.h" +#include + class RimGeoMechView; class RigGeoMechCaseData; class RifGeoMechReaderInterface; @@ -65,8 +67,12 @@ class RimGeoMechCase : public RimCase // Fields: caf::PdmChildArrayField geoMechViews; + static std::vector dateTimeVectorFromTimeStepStrings(const QStringList& timeStepStrings); + private: virtual void initAfterRead(); + static QString subStringOfDigits(const QString& timeStepString, int numberOfDigitsToFind); + private: cvf::ref m_geoMechCaseData; caf::PdmField m_caseFileName; diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index 0d0b8a0bc8..97d33a0c75 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -156,15 +156,23 @@ void RiuSelectionChangedHandler::addCurveFromSelectionItem(const RiuGeoMechSelec curveName.append(timeHistResultAccessor.topologyText()); std::vector timeHistoryValues = timeHistResultAccessor.timeHistoryValues(); - std::vector frameTimes; - for (size_t i = 0; i < timeHistoryValues.size(); i++) + + QStringList stepNames = geoMechView->geoMechCase()->timeStepStrings(); + std::vector dates = RimGeoMechCase::dateTimeVectorFromTimeStepStrings(stepNames); + if (dates.size() == timeHistoryValues.size()) { - frameTimes.push_back(i); + RiuMainWindow::instance()->resultPlot()->addCurve(curveName, geomSelectionItem->m_color, dates, timeHistoryValues); } + else + { + std::vector dummyStepTimes; + for (size_t i = 0; i < timeHistoryValues.size(); i++) + { + dummyStepTimes.push_back(i); + } - CVF_ASSERT(frameTimes.size() == timeHistoryValues.size()); - - RiuMainWindow::instance()->resultPlot()->addCurve(curveName, geomSelectionItem->m_color, frameTimes, timeHistoryValues); + RiuMainWindow::instance()->resultPlot()->addCurve(curveName, geomSelectionItem->m_color, dummyStepTimes, timeHistoryValues); + } } } From e0b8f6e06b9598a182a0799dccdf224e2b77b461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 24 Nov 2015 13:26:45 +0100 Subject: [PATCH 128/290] (#665) Icons for cross sections --- .../ProjectDataModel/RimCrossSection.cpp | 2 +- .../RimCrossSectionCollection.cpp | 2 +- ApplicationCode/Resources/CrossSection16x16.png | Bin 0 -> 687 bytes ApplicationCode/Resources/CrossSections16x16.png | Bin 0 -> 848 bytes ApplicationCode/Resources/ResInsight.qrc | 4 +++- 5 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 ApplicationCode/Resources/CrossSection16x16.png create mode 100644 ApplicationCode/Resources/CrossSections16x16.png diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index d8237bb602..d383601934 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -60,7 +60,7 @@ CAF_PDM_SOURCE_INIT(RimCrossSection, "CrossSection"); //-------------------------------------------------------------------------------------------------- RimCrossSection::RimCrossSection() { - CAF_PDM_InitObject("Intersection", "", "", ""); + CAF_PDM_InitObject("Intersection", ":/CrossSection16x16.png", "", ""); CAF_PDM_InitField(&name, "UserDescription", QString("Intersection Name"), "Name", "", "", ""); CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index bb6a17ca2d..7b8f54d3fb 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -32,7 +32,7 @@ CAF_PDM_SOURCE_INIT(RimCrossSectionCollection, "CrossSectionCollection"); //-------------------------------------------------------------------------------------------------- RimCrossSectionCollection::RimCrossSectionCollection() { - CAF_PDM_InitObject("Intersections", ":/undefined_image.png", "", ""); + CAF_PDM_InitObject("Intersections", ":/CrossSections16x16.png", "", ""); CAF_PDM_InitFieldNoDefault(&m_crossSections, "CrossSections", "Intersections", "", "", ""); m_crossSections.uiCapability()->setUiHidden(true); diff --git a/ApplicationCode/Resources/CrossSection16x16.png b/ApplicationCode/Resources/CrossSection16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..703aa14ad6c588dd5220b7240782e7e973e74c31 GIT binary patch literal 687 zcmV;g0#N;lP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2@A z3=l6R$edRI000?jR9JLFZ*6U5ZgcD~bc|+y0006CNklGD7{~GN``YG|ySlZ`)K;#-E{0SVn1UE}2-;&5g(RY2M6jKrQMwh;t+h){ zdXl;qgcOw^WlPW@4DwQ`tgD4PgQU~0?l}J0E>_~9vM&8j4-Y(_!}IXKf034!mWzKo zD*)Qt+oz00VAQp>F-x$6-+ZDYQv@FZD zZF_QIVPO(jl2Q%;`I3^7SAZ1^22;AOe_0EBy`8)>zBunup6{=naNI?uTKnux%7cB6 zXChH4<@RhgD||lRMj=GMZQCQ=-QD_Xz&^ZbDA`z?7-I@3pa6{uX6PCBgm*jMB7aI& zz8>}#1yW;$XJ+R-VW8JAjN=l(bzLRlRPUn(h!DQndVZ<-!mUw&Q0Ztx<=J;bPuret zZK(fvsJz@xdA-iK<2XkFHUIKZ9WR=hlKvmU*X`1&e%Q~%TTCTG<-UKMXVqIB(sEsGr0jS-<+x$7XJRb@O(m$8@ zJslk#Cp1lq0>PEmG>``>>O*}It!hMhu{r!`@MX!? zl+wR5^oa?jY-w&VQ}|n84R$P@PIu*Uxm`jCkjG9mSCYx(Wk4|uL;Ujtego%@ V#`YoPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2@A z3=j@!p^OOt000?jR9JLFZ*6U5ZgcD~bc|+y00083NklWH@12_;Q^wX5to)j?Q5i}InMgkL5K1*ee5oL~F)_1;2$IS_ z^p-?4YLIA9iixBd5)q0c)8=RKU5iUI~<5Ks!~d@-Dbj)&NS zL~qME2E1Z%$tI3-yP*sK0B2d&l1})apB8_ctPf9yt-dTOvB0;aKWXaO7a#FMF&K?9 z2pp1n*9tT*dWQ4tU;HvyAxVwUtec+RCbq zCTq&(4cO2%T^`oo%zz zbOwg`@aeiDn;Qv`WellLogPlot16x16.png WellLogPlots16x16.png WellLogCurve16x16.png - + CrossSection16x16.png + CrossSections16x16.png + fs_CellFace.glsl vs_CellFace.glsl From 85ca555163ff02b04b45cdc1b3b57fd829f8183f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 14:12:48 +0100 Subject: [PATCH 129/290] Rename --- ApplicationCode/ReservoirDataModel/RigGridBase.cpp | 10 +++++----- ApplicationCode/ReservoirDataModel/RigGridBase.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigGridBase.cpp b/ApplicationCode/ReservoirDataModel/RigGridBase.cpp index 08b9ce84d6..43ad22d847 100644 --- a/ApplicationCode/ReservoirDataModel/RigGridBase.cpp +++ b/ApplicationCode/ReservoirDataModel/RigGridBase.cpp @@ -68,23 +68,23 @@ std::string RigGridBase::gridName() const //-------------------------------------------------------------------------------------------------- /// Do we need this ? //-------------------------------------------------------------------------------------------------- -RigCell& RigGridBase::cell(size_t gridCellIndex) +RigCell& RigGridBase::cell(size_t gridLocalCellIndex) { CVF_ASSERT(m_mainGrid); - CVF_ASSERT(m_indexToStartOfCells + gridCellIndex < m_mainGrid->cells().size()); + CVF_ASSERT(m_indexToStartOfCells + gridLocalCellIndex < m_mainGrid->cells().size()); - return m_mainGrid->cells()[m_indexToStartOfCells + gridCellIndex]; + return m_mainGrid->cells()[m_indexToStartOfCells + gridLocalCellIndex]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const RigCell& RigGridBase::cell(size_t gridCellIndex) const +const RigCell& RigGridBase::cell(size_t gridLocalCellIndex) const { CVF_ASSERT(m_mainGrid); - return m_mainGrid->cells()[m_indexToStartOfCells + gridCellIndex]; + return m_mainGrid->cells()[m_indexToStartOfCells + gridLocalCellIndex]; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigGridBase.h b/ApplicationCode/ReservoirDataModel/RigGridBase.h index 7ea661d93f..6a3bbd550a 100644 --- a/ApplicationCode/ReservoirDataModel/RigGridBase.h +++ b/ApplicationCode/ReservoirDataModel/RigGridBase.h @@ -50,8 +50,8 @@ class RigGridBase : public cvf::StructGridInterface cvf::Vec3st gridPointDimensions() { return m_gridPointDimensions; } size_t cellCount() const { return cellCountI() * cellCountJ() * cellCountK(); } - RigCell& cell(size_t gridCellIndex); - const RigCell& cell(size_t gridCellIndex) const; + RigCell& cell(size_t gridLocalCellIndex); + const RigCell& cell(size_t gridLocalCellIndex) const; size_t reservoirCellIndex(size_t gridLocalCellIndex) const; void setIndexToStartOfCells(size_t indexToStartOfCells) { m_indexToStartOfCells = indexToStartOfCells; } From 1890ff19f91cdcca59015fcaa2f524867397c1e0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 14:14:14 +0100 Subject: [PATCH 130/290] (#664) Picking on intersections for eclipse and geo models --- .../ModelVisualization/CMakeLists_files.cmake | 2 + .../RivCrossSectionPartMgr.cpp | 6 +-- .../RivCrossSectionSourceInfo.cpp | 42 +++++++++++++++++++ .../RivCrossSectionSourceInfo.h | 37 ++++++++++++++++ .../UserInterface/RiuViewerCommands.cpp | 21 ++++++++++ 5 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp create mode 100644 ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index d3ab43480f..3672d3312c 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -36,6 +36,7 @@ ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.h ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.h ${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.h ${CEE_CURRENT_LIST_DIR}RivWellPipeSourceInfo.h +${CEE_CURRENT_LIST_DIR}RivCrossSectionSourceInfo.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -68,6 +69,7 @@ ${CEE_CURRENT_LIST_DIR}RivCellEdgeGeometryUtils.cpp ${CEE_CURRENT_LIST_DIR}RivPipeQuadToSegmentMapper.cpp ${CEE_CURRENT_LIST_DIR}RivSingleCellPartGenerator.cpp ${CEE_CURRENT_LIST_DIR}RivWellPipeSourceInfo.cpp +${CEE_CURRENT_LIST_DIR}RivCrossSectionSourceInfo.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index f5b2407fe1..10990afa34 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -36,6 +36,7 @@ #include "RimGeoMechView.h" #include "RimTernaryLegendConfig.h" +#include "RivCrossSectionSourceInfo.h" #include "RivResultToTextureMapper.h" #include "RivScalarMapperUtils.h" #include "RivTernaryScalarMapper.h" @@ -303,9 +304,8 @@ void RivCrossSectionPartMgr::generatePartGeometry() part->setDrawable(geo.p()); // Set mapping from triangle face index to cell index - //cvf::ref si = new RivSourceInfo(m_grid->gridIndex()); - //si->m_cellFaceFromTriangleMapper = m_nativeCrossSectionGenerator->triangleToCellFaceMapper(); - //part->setSourceInfo(si.p()); + cvf::ref si = new RivCrossSectionSourceInfo(m_crossSectionGenerator.p()); + part->setSourceInfo(si.p()); part->updateBoundingBox(); part->setEnableMask(surfaceBit); diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp new file mode 100644 index 0000000000..2a9f4889fc --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivCrossSectionSourceInfo.h" + +#include "RivCrossSectionGeometryGenerator.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivCrossSectionSourceInfo::RivCrossSectionSourceInfo(RivCrossSectionGeometryGenerator* geometryGenerator) + : m_crossSectionGeometryGenerator(geometryGenerator) +{ + CVF_ASSERT(m_crossSectionGeometryGenerator.notNull()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RivCrossSectionSourceInfo::triangleToCellIndex() const +{ + CVF_ASSERT(m_crossSectionGeometryGenerator.notNull()); + + return m_crossSectionGeometryGenerator->triangleToCellIndex(); +} diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h new file mode 100644 index 0000000000..c402319657 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfArray.h" + +class RivCrossSectionGeometryGenerator; + +class RivCrossSectionSourceInfo : public cvf::Object +{ +public: + RivCrossSectionSourceInfo(RivCrossSectionGeometryGenerator* geometryGenerator); + + const std::vector& triangleToCellIndex() const; + +private: + cvf::cref m_crossSectionGeometryGenerator; +}; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index c4eafb763e..fd8a0441c9 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -62,6 +62,7 @@ #include "RiuSelectionManager.h" #include "RiuViewer.h" +#include "RivCrossSectionSourceInfo.h" #include "RivFemPartGeometryGenerator.h" #include "RivFemPickSourceInfo.h" #include "RivSourceInfo.h" @@ -418,6 +419,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivCrossSectionSourceInfo* crossSectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (rivSourceInfo) { @@ -439,6 +441,25 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { wellPath = wellPathSourceInfo->wellPath(); } + else if (crossSectionSourceInfo) + { + RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + + if (eclipseView) + { + size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; + + const RigCell& cell = eclipseView->eclipseCase()->reservoirData()->mainGrid()->cells()[globalCellIndex]; + cellIndex = cell.gridLocalCellIndex(); + gridIndex = cell.hostGrid()->gridIndex(); + } + else if (geomView) + { + cellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; + gridIndex = 0; + } + } } if (firstNncHitPart && firstNncHitPart->sourceInfo()) From 9429458d32a20732d8be555a07c7442002490bf9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 14:21:02 +0100 Subject: [PATCH 131/290] Rename from cells to globalCellArray --- .../FileInterface/RifReaderEclipseOutput.cpp | 10 +++---- .../RivCrossSectionGeometryGenerator.cpp | 4 +-- .../RivNNCGeometryGenerator.cpp | 2 +- .../Rim3dOverlayInfoConfig.cpp | 2 +- .../RimEclipseStatisticsCaseEvaluator.cpp | 2 +- .../ProjectDataModel/RimEclipseView.cpp | 2 +- .../ProjectDataModel/RimFaultCollection.cpp | 4 +-- .../RimIdenticalGridCaseGroup.cpp | 4 +-- .../RimReservoirCellResultsStorage.cpp | 22 ++++++++-------- .../RigCaseCellResultsData.cpp | 2 +- .../ReservoirDataModel/RigCaseData.cpp | 2 +- .../RigCaseToCaseCellMapper.cpp | 4 +-- .../RigCaseToCaseCellMapperTools.cpp | 2 +- .../RigCaseToCaseRangeFilterMapper.cpp | 4 +-- .../RigEclipseWellLogExtractor.cpp | 2 +- .../ReservoirDataModel/RigGridBase.cpp | 6 ++--- .../ReservoirDataModel/RigMainGrid.h | 4 +-- .../ReservoirDataModel/RigNNCData.cpp | 4 +-- .../RigReservoirBuilderMock.cpp | 26 +++++++++---------- .../SocketInterface/RiaCaseInfoCommands.cpp | 2 +- .../SocketInterface/RiaGeometryCommands.cpp | 6 ++--- .../RiaPropertyDataCommands.cpp | 2 +- .../UserInterface/RiuResultTextBuilder.cpp | 8 +++--- .../UserInterface/RiuViewerCommands.cpp | 2 +- 24 files changed, 64 insertions(+), 64 deletions(-) diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp index 265943faeb..ccd23d12ae 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp @@ -99,12 +99,12 @@ bool transferGridCellData(RigMainGrid* mainGrid, RigActiveCellInfo* activeCellIn CVF_ASSERT(activeCellInfo && fractureActiveCellInfo); int cellCount = ecl_grid_get_global_size(localEclGrid); - size_t cellStartIndex = mainGrid->cells().size(); + size_t cellStartIndex = mainGrid->globalCellArray().size(); size_t nodeStartIndex = mainGrid->nodes().size(); RigCell defaultCell; defaultCell.setHostGrid(localGrid); - mainGrid->cells().resize(cellStartIndex + cellCount, defaultCell); + mainGrid->globalCellArray().resize(cellStartIndex + cellCount, defaultCell); mainGrid->nodes().resize(nodeStartIndex + cellCount*8, cvf::Vec3d(0,0,0)); @@ -117,7 +117,7 @@ bool transferGridCellData(RigMainGrid* mainGrid, RigActiveCellInfo* activeCellIn #pragma omp parallel for for (int gridLocalCellIndex = 0; gridLocalCellIndex < cellCount; ++gridLocalCellIndex) { - RigCell& cell = mainGrid->cells()[cellStartIndex + gridLocalCellIndex]; + RigCell& cell = mainGrid->globalCellArray()[cellStartIndex + gridLocalCellIndex]; cell.setGridLocalCellIndex(gridLocalCellIndex); @@ -295,7 +295,7 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, // Reserve room for the cells and nodes and fill them with data - mainGrid->cells().reserve(totalCellCount); + mainGrid->globalCellArray().reserve(totalCellCount); mainGrid->nodes().reserve(8*totalCellCount); caf::ProgressInfo progInfo(3 + numLGRs, ""); @@ -569,7 +569,7 @@ bool RifReaderEclipseOutput::readActiveCellInfo() } // Check if number of cells is matching - if (m_eclipseCase->mainGrid()->cells().size() != reservoirCellCount) + if (m_eclipseCase->mainGrid()->globalCellArray().size() != reservoirCellCount) { return false; } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index e178f42949..bede30df63 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1226,7 +1226,7 @@ void RivEclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& i //-------------------------------------------------------------------------------------------------- bool RivEclipseCrossSectionGrid::useCell(size_t cellIndex) const { - const RigCell& cell = m_mainGrid->cells()[cellIndex]; + const RigCell& cell = m_mainGrid->globalCellArray()[cellIndex]; return !(cell.isInvalid() || (cell.subGrid() != NULL)); } @@ -1244,7 +1244,7 @@ void RivEclipseCrossSectionGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d //-------------------------------------------------------------------------------------------------- void RivEclipseCrossSectionGrid::cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const { - const caf::SizeTArray8& cornerIndicesSource = m_mainGrid->cells()[cellIndex].cornerIndices(); + const caf::SizeTArray8& cornerIndicesSource = m_mainGrid->globalCellArray()[cellIndex].cornerIndices(); memcpy(cornerIndices, cornerIndicesSource.data(), 8); } diff --git a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp index 8f438f4763..31d019d018 100644 --- a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp @@ -79,7 +79,7 @@ void RivNNCGeometryGenerator::computeArrays() std::vector* allCells = NULL; if (isVisibilityCalcActive) { - allCells = &(m_grid->mainGrid()->cells()); + allCells = &(m_grid->mainGrid()->globalCellArray()); } #pragma omp parallel for ordered diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index ee5c33ddf4..3889bc75e2 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -265,7 +265,7 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * eclipseView) if (eclipseView->eclipseCase() && eclipseView->eclipseCase()->reservoirData() && eclipseView->eclipseCase()->reservoirData()->mainGrid()) { caseName = eclipseView->eclipseCase()->caseUserDescription(); - totCellCount = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->cells().size()); + totCellCount = QString::number(eclipseView->eclipseCase()->reservoirData()->mainGrid()->globalCellArray().size()); size_t mxActCellCount = eclipseView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::MATRIX_RESULTS)->reservoirActiveCellCount(); size_t frActCellCount = eclipseView->eclipseCase()->reservoirData()->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS)->reservoirActiveCellCount(); if (frActCellCount > 0) activeCellCountText += "Matrix : "; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp index ccaa7261fc..3daa9f75c6 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp @@ -312,7 +312,7 @@ RimEclipseStatisticsCaseEvaluator::RimEclipseStatisticsCaseEvaluator(const std:: { if (sourceCases.size() > 0) { - m_reservoirCellCount = sourceCases[0]->reservoirData()->mainGrid()->cells().size(); + m_reservoirCellCount = sourceCases[0]->reservoirData()->mainGrid()->globalCellArray().size(); } CVF_ASSERT(m_destinationCase); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index cb1ffe622c..a425773b06 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1578,7 +1578,7 @@ void RimEclipseView::setOverridePropertyFilterCollection(RimEclipsePropertyFilte void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility) { size_t gridCount = this->eclipseCase()->reservoirData()->gridCount(); - size_t cellCount = this->eclipseCase()->reservoirData()->mainGrid()->cells().size(); + size_t cellCount = this->eclipseCase()->reservoirData()->mainGrid()->globalCellArray().size(); totalVisibility->resize(cellCount); totalVisibility->setAll(false); diff --git a/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp b/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp index 37f4e13c57..a4f4d41521 100644 --- a/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimFaultCollection.cpp @@ -256,7 +256,7 @@ void RimFaultCollection::syncronizeFaults() QString secondConnectionText; { - const RigCell& cell = mainGrid->cells()[nncConnections[i].m_c1GlobIdx]; + const RigCell& cell = mainGrid->globalCellArray()[nncConnections[i].m_c1GlobIdx]; RigGridBase* hostGrid = cell.hostGrid(); size_t gridLocalCellIndex = cell.gridLocalCellIndex(); @@ -279,7 +279,7 @@ void RimFaultCollection::syncronizeFaults() } { - const RigCell& cell = mainGrid->cells()[nncConnections[i].m_c2GlobIdx]; + const RigCell& cell = mainGrid->globalCellArray()[nncConnections[i].m_c2GlobIdx]; RigGridBase* hostGrid = cell.hostGrid(); size_t gridLocalCellIndex = cell.gridLocalCellIndex(); diff --git a/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp b/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp index 3519e2cf0f..a1346db662 100644 --- a/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp +++ b/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp @@ -294,8 +294,8 @@ void RimIdenticalGridCaseGroup::computeUnionOfActiveCells() return; } - m_unionOfMatrixActiveCells->setReservoirCellCount(m_mainGrid->cells().size()); - m_unionOfFractureActiveCells->setReservoirCellCount(m_mainGrid->cells().size()); + m_unionOfMatrixActiveCells->setReservoirCellCount(m_mainGrid->globalCellArray().size()); + m_unionOfFractureActiveCells->setReservoirCellCount(m_mainGrid->globalCellArray().size()); m_unionOfMatrixActiveCells->setGridCount(m_mainGrid->gridCount()); m_unionOfFractureActiveCells->setGridCount(m_mainGrid->gridCount()); diff --git a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp index 63a2d10190..ea1b71d9b5 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp +++ b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp @@ -589,7 +589,7 @@ void RimReservoirCellResultsStorage::computeDepthRelatedResults() bool computeTops = false; bool computeBottom = false; - size_t resultValueCount = m_ownerMainGrid->cells().size(); + size_t resultValueCount = m_ownerMainGrid->globalCellArray().size(); if (depthResultGridIndex == cvf::UNDEFINED_SIZE_T) { @@ -635,9 +635,9 @@ void RimReservoirCellResultsStorage::computeDepthRelatedResults() std::vector< std::vector >& bottom = m_cellResults->cellScalarResults(bottomResultGridIndex); size_t cellIdx = 0; - for (cellIdx = 0; cellIdx < m_ownerMainGrid->cells().size(); cellIdx++) + for (cellIdx = 0; cellIdx < m_ownerMainGrid->globalCellArray().size(); cellIdx++) { - const RigCell& cell = m_ownerMainGrid->cells()[cellIdx]; + const RigCell& cell = m_ownerMainGrid->globalCellArray()[cellIdx]; if (computeDepth) { @@ -866,14 +866,14 @@ void RimReservoirCellResultsStorage::computeRiTransComponent(const QString& riTr const std::vector& nodes = m_ownerMainGrid->nodes(); bool isFaceNormalsOutwards = m_ownerMainGrid->isFaceNormalsOutwards(); - for (size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->cells().size(); nativeResvCellIndex++) + for (size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->globalCellArray().size(); nativeResvCellIndex++) { // Do nothing if we are only dealing with active cells, and this cell is not active: size_t tranResIdx = (*riTranIdxFunc)(activeCellInfo, nativeResvCellIndex); if (tranResIdx == cvf::UNDEFINED_SIZE_T) continue; - const RigCell& nativeCell = m_ownerMainGrid->cells()[nativeResvCellIndex]; + const RigCell& nativeCell = m_ownerMainGrid->globalCellArray()[nativeResvCellIndex]; RigGridBase* grid = nativeCell.hostGrid(); size_t gridLocalNativeCellIndex = nativeCell.gridLocalCellIndex(); @@ -885,7 +885,7 @@ void RimReservoirCellResultsStorage::computeRiTransComponent(const QString& riTr if (grid->cellIJKNeighbor(i, j, k, faceId, &gridLocalNeighborCellIdx)) { size_t neighborResvCellIdx = grid->reservoirCellIndex(gridLocalNeighborCellIdx); - const RigCell& neighborCell = m_ownerMainGrid->cells()[neighborResvCellIdx]; + const RigCell& neighborCell = m_ownerMainGrid->globalCellArray()[neighborResvCellIdx]; // Do nothing if neighbor cell has no results size_t neighborCellPermResIdx = (*permIdxFunc)(activeCellInfo, neighborResvCellIdx); @@ -1059,8 +1059,8 @@ void RimReservoirCellResultsStorage::computeNncCombRiTrans() if (neighborCellPermResIdx == cvf::UNDEFINED_SIZE_T) continue; - const RigCell& nativeCell = m_ownerMainGrid->cells()[nativeResvCellIndex]; - const RigCell& neighborCell = m_ownerMainGrid->cells()[neighborResvCellIdx]; + const RigCell& nativeCell = m_ownerMainGrid->globalCellArray()[nativeResvCellIndex]; + const RigCell& neighborCell = m_ownerMainGrid->globalCellArray()[neighborResvCellIdx]; // Connection geometry @@ -1299,14 +1299,14 @@ void RimReservoirCellResultsStorage::computeRiTRANSbyAreaComponent(const QString const RigActiveCellInfo* activeCellInfo = m_cellResults->activeCellInfo(); const std::vector& nodes = m_ownerMainGrid->nodes(); - for (size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->cells().size(); nativeResvCellIndex++) + for (size_t nativeResvCellIndex = 0; nativeResvCellIndex < m_ownerMainGrid->globalCellArray().size(); nativeResvCellIndex++) { // Do nothing if we are only dealing with active cells, and this cell is not active: size_t nativeCellResValIdx = (*resValIdxFunc)(activeCellInfo, nativeResvCellIndex); if (nativeCellResValIdx == cvf::UNDEFINED_SIZE_T) continue; - const RigCell& nativeCell = m_ownerMainGrid->cells()[nativeResvCellIndex]; + const RigCell& nativeCell = m_ownerMainGrid->globalCellArray()[nativeResvCellIndex]; RigGridBase* grid = nativeCell.hostGrid(); size_t gridLocalNativeCellIndex = nativeCell.gridLocalCellIndex(); @@ -1318,7 +1318,7 @@ void RimReservoirCellResultsStorage::computeRiTRANSbyAreaComponent(const QString if (grid->cellIJKNeighbor(i, j, k, faceId, &gridLocalNeighborCellIdx)) { size_t neighborResvCellIdx = grid->reservoirCellIndex(gridLocalNeighborCellIdx); - const RigCell& neighborCell = m_ownerMainGrid->cells()[neighborResvCellIdx]; + const RigCell& neighborCell = m_ownerMainGrid->globalCellArray()[neighborResvCellIdx]; // Connection geometry diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 48f2aa9083..4a84bd599a 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -341,7 +341,7 @@ bool RigCaseCellResultsData::isUsingGlobalActiveIndex(size_t scalarResultIndex) if (!m_cellScalarResults[scalarResultIndex].size()) return true; size_t firstTimeStepResultValueCount = m_cellScalarResults[scalarResultIndex][0].size(); - if (firstTimeStepResultValueCount == m_ownerMainGrid->cells().size()) return false; + if (firstTimeStepResultValueCount == m_ownerMainGrid->globalCellArray().size()) return false; return true; } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp index 3b40771fc9..de4ce29adf 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp @@ -450,7 +450,7 @@ void RigCaseData::computeActiveCellsGeometryBoundingBox() { if (activeInfos[acIdx]->isActive(i)) { - const RigCell& c = m_mainGrid->cells()[i]; + const RigCell& c = m_mainGrid->globalCellArray()[i]; const caf::SizeTArray8& indices = c.cornerIndices(); size_t idx; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapper.cpp b/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapper.cpp index 2bdf14543f..82b74df1db 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapper.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapper.cpp @@ -34,7 +34,7 @@ RigCaseToCaseCellMapper::RigCaseToCaseCellMapper(RigMainGrid* masterEclGrid, Rig m_masterFemPart(NULL), m_dependentFemPart(NULL) { - m_masterCellOrIntervalIndex.resize(dependentEclGrid->cells().size(), cvf::UNDEFINED_INT); + m_masterCellOrIntervalIndex.resize(dependentEclGrid->globalCellArray().size(), cvf::UNDEFINED_INT); } @@ -47,7 +47,7 @@ RigCaseToCaseCellMapper::RigCaseToCaseCellMapper(RigFemPart* masterFemPart, RigM m_masterFemPart(masterFemPart), m_dependentFemPart(NULL) { - m_masterCellOrIntervalIndex.resize(dependentEclGrid->cells().size(), cvf::UNDEFINED_INT); + m_masterCellOrIntervalIndex.resize(dependentEclGrid->globalCellArray().size(), cvf::UNDEFINED_INT); this->calculateEclToGeomCellMapping(dependentEclGrid, masterFemPart, false); } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapperTools.cpp b/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapperTools.cpp index 2b352274ff..48b1219292 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapperTools.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseToCaseCellMapperTools.cpp @@ -49,7 +49,7 @@ class RigNeighborCornerFinder if (offsetK > 0 && m_baseK == m_mainGrid->cellCountK()-1) return NULL; size_t gridLocalCellIndex = m_mainGrid->cellIndexFromIJK(m_baseI + offsetI, m_baseJ + offsetJ, m_baseK + offsetK); - const RigCell& cell = m_mainGrid->cells()[gridLocalCellIndex]; + const RigCell& cell = m_mainGrid->globalCellArray()[gridLocalCellIndex]; return &(cell.cornerIndices()); } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp index b4f46328ce..8af8e0f1d3 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp @@ -352,7 +352,7 @@ RigCaseToCaseRangeFilterMapper::findBestFemCellFromEclCell(const RigMainGrid* ma size_t cellIdx = masterEclGrid->cellIndexFromIJK(ei, ej, ek); - bool isCollapsedCell = masterEclGrid->cells()[cellIdx].isCollapsedCell(); + bool isCollapsedCell = masterEclGrid->globalCellArray()[cellIdx].isCollapsedCell(); cvf::Vec3d geoMechConvertedEclCell[8]; RigCaseToCaseCellMapperTools::estimatedFemCellFromEclCell(masterEclGrid, cellIdx, geoMechConvertedEclCell); @@ -475,7 +475,7 @@ RigCaseToCaseRangeFilterMapper::findBestEclCellFromFemCell(const RigFemPart* dep if (globCellIdxToBestMatch != cvf::UNDEFINED_SIZE_T) { masterEclGrid->ijkFromCellIndex(globCellIdxToBestMatch, ei, ej, ek); - isCollapsedCell = masterEclGrid->cells()[globCellIdxToBestMatch].isCollapsedCell(); + isCollapsedCell = masterEclGrid->globalCellArray()[globCellIdxToBestMatch].isCollapsedCell(); } else { diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp index 9109e9d2f4..5b7d458bb6 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp @@ -69,7 +69,7 @@ void RigEclipseWellLogExtractor::calculateIntersection() cvf::Vec3d hexCorners[8]; for (size_t cIdx = 0; cIdx < closeCells.size(); ++cIdx) { - const RigCell& cell = m_caseData->mainGrid()->cells()[closeCells[cIdx]]; + const RigCell& cell = m_caseData->mainGrid()->globalCellArray()[closeCells[cIdx]]; const caf::SizeTArray8& cornerIndices = cell.cornerIndices(); hexCorners[0] = nodeCoords[cornerIndices[0]]; diff --git a/ApplicationCode/ReservoirDataModel/RigGridBase.cpp b/ApplicationCode/ReservoirDataModel/RigGridBase.cpp index 43ad22d847..061f8b7def 100644 --- a/ApplicationCode/ReservoirDataModel/RigGridBase.cpp +++ b/ApplicationCode/ReservoirDataModel/RigGridBase.cpp @@ -72,9 +72,9 @@ RigCell& RigGridBase::cell(size_t gridLocalCellIndex) { CVF_ASSERT(m_mainGrid); - CVF_ASSERT(m_indexToStartOfCells + gridLocalCellIndex < m_mainGrid->cells().size()); + CVF_ASSERT(m_indexToStartOfCells + gridLocalCellIndex < m_mainGrid->globalCellArray().size()); - return m_mainGrid->cells()[m_indexToStartOfCells + gridLocalCellIndex]; + return m_mainGrid->globalCellArray()[m_indexToStartOfCells + gridLocalCellIndex]; } //-------------------------------------------------------------------------------------------------- @@ -84,7 +84,7 @@ const RigCell& RigGridBase::cell(size_t gridLocalCellIndex) const { CVF_ASSERT(m_mainGrid); - return m_mainGrid->cells()[m_indexToStartOfCells + gridLocalCellIndex]; + return m_mainGrid->globalCellArray()[m_indexToStartOfCells + gridLocalCellIndex]; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.h b/ApplicationCode/ReservoirDataModel/RigMainGrid.h index 11ea6639f8..9a9100722a 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.h +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.h @@ -45,8 +45,8 @@ class RigMainGrid : public RigGridBase std::vector& nodes() {return m_nodes;} const std::vector& nodes() const {return m_nodes;} - std::vector& cells() {return m_cells;} - const std::vector& cells() const {return m_cells;} + std::vector& globalCellArray() {return m_cells;} + const std::vector& globalCellArray() const {return m_cells;} void addLocalGrid(RigLocalGrid* localGrid); size_t gridCount() const { return m_localGrids.size() + 1; } diff --git a/ApplicationCode/ReservoirDataModel/RigNNCData.cpp b/ApplicationCode/ReservoirDataModel/RigNNCData.cpp index 2b5abde1f0..b383cbb665 100644 --- a/ApplicationCode/ReservoirDataModel/RigNNCData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigNNCData.cpp @@ -40,8 +40,8 @@ void RigNNCData::processConnections(const RigMainGrid& mainGrid) for (size_t cnIdx = 0; cnIdx < m_connections.size(); ++cnIdx) { - const RigCell& c1 = mainGrid.cells()[m_connections[cnIdx].m_c1GlobIdx]; - const RigCell& c2 = mainGrid.cells()[m_connections[cnIdx].m_c2GlobIdx]; + const RigCell& c1 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c1GlobIdx]; + const RigCell& c2 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c2GlobIdx]; // Try to find the shared face diff --git a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp index 11f91ba69a..c18c58da66 100644 --- a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp +++ b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp @@ -173,7 +173,7 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase) size_t mainGridCellCount = mainGridNodeCount / 8; // Must create cells in main grid here, as this information is used when creating LGRs - appendCells(0, mainGridCellCount, eclipseCase->mainGrid(), eclipseCase->mainGrid()->cells()); + appendCells(0, mainGridCellCount, eclipseCase->mainGrid(), eclipseCase->mainGrid()->globalCellArray()); size_t totalCellCount = mainGridCellCount; @@ -217,7 +217,7 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase) size_t cellIdx; for (cellIdx = 0; cellIdx < mainGridIndicesWithSubGrid.size(); cellIdx++) { - RigCell& cell = eclipseCase->mainGrid()->cells()[mainGridIndicesWithSubGrid[cellIdx]]; + RigCell& cell = eclipseCase->mainGrid()->globalCellArray()[mainGridIndicesWithSubGrid[cellIdx]]; caf::SizeTArray8& indices = cell.cornerIndices(); int nodeIdx; @@ -233,7 +233,7 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase) appendNodes(bb.min(), bb.max(), lgrCellDimensions, mainGridNodes); size_t subGridCellCount = (mainGridNodes.size() / 8) - totalCellCount; - appendCells(totalCellCount*8, subGridCellCount, localGrid, eclipseCase->mainGrid()->cells()); + appendCells(totalCellCount*8, subGridCellCount, localGrid, eclipseCase->mainGrid()->globalCellArray()); totalCellCount += subGridCellCount; } @@ -248,14 +248,14 @@ void RigReservoirBuilderMock::populateReservoir(RigCaseData* eclipseCase) // Set all cells active RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS); - activeCellInfo->setReservoirCellCount(eclipseCase->mainGrid()->cells().size()); - for (size_t i = 0; i < eclipseCase->mainGrid()->cells().size(); i++) + activeCellInfo->setReservoirCellCount(eclipseCase->mainGrid()->globalCellArray().size()); + for (size_t i = 0; i < eclipseCase->mainGrid()->globalCellArray().size(); i++) { activeCellInfo->setCellResultIndex(i, i); } activeCellInfo->setGridCount(1); - activeCellInfo->setGridActiveCellCounts(0, eclipseCase->mainGrid()->cells().size()); + activeCellInfo->setGridActiveCellCounts(0, eclipseCase->mainGrid()->globalCellArray().size()); activeCellInfo->computeDerivedData(); // Add grid coarsening for main grid @@ -300,7 +300,7 @@ bool RigReservoirBuilderMock::inputProperty(RigCaseData* eclipseCase, const QStr /* generate secret number: */ int iSecret = rand() % 20 + 1; - for (k = 0; k < eclipseCase->mainGrid()->cells().size(); k++) + for (k = 0; k < eclipseCase->mainGrid()->globalCellArray().size(); k++) { values->push_back(k * iSecret); } @@ -313,12 +313,12 @@ bool RigReservoirBuilderMock::inputProperty(RigCaseData* eclipseCase, const QStr //-------------------------------------------------------------------------------------------------- bool RigReservoirBuilderMock::staticResult(RigCaseData* eclipseCase, const QString& result, std::vector* values) { - values->resize(eclipseCase->mainGrid()->cells().size()); + values->resize(eclipseCase->mainGrid()->globalCellArray().size()); #pragma omp parallel for - for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->cells().size()); k++) + for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->globalCellArray().size()); k++) { - values->at(k) = (k * 2) % eclipseCase->mainGrid()->cells().size(); + values->at(k) = (k * 2) % eclipseCase->mainGrid()->globalCellArray().size(); } return false; @@ -341,12 +341,12 @@ bool RigReservoirBuilderMock::dynamicResult(RigCaseData* eclipseCase, const QStr double scaleValue = 1.0 + resultIndex * 0.1; double offsetValue = 100 * resultIndex; - values->resize(eclipseCase->mainGrid()->cells().size()); + values->resize(eclipseCase->mainGrid()->globalCellArray().size()); #pragma omp parallel for - for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->cells().size()); k++) + for (long long k = 0; k < static_cast(eclipseCase->mainGrid()->globalCellArray().size()); k++) { - double val = offsetValue + scaleValue * ( (stepIndex * 1000 + k) % eclipseCase->mainGrid()->cells().size() ); + double val = offsetValue + scaleValue * ( (stepIndex * 1000 + k) % eclipseCase->mainGrid()->globalCellArray().size() ); values->at(k) = val; } diff --git a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp index 68b4e41ca5..768df7361e 100644 --- a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp @@ -171,7 +171,7 @@ class RiaGetActiveCellInfo: public RiaSocketCommand hostCellK.reserve(numMatrixModelActiveCells); globalCoarseningBoxIdx.reserve(numMatrixModelActiveCells); - const std::vector& reservoirCells = reservoirCase->reservoirData()->mainGrid()->cells(); + const std::vector& reservoirCells = reservoirCase->reservoirData()->mainGrid()->globalCellArray(); std::vector globalCoarseningBoxIndexStart; diff --git a/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp b/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp index 1b6b3fe9cb..0d52a47e0a 100644 --- a/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaGeometryCommands.cpp @@ -178,11 +178,11 @@ class RiaGetActiveCellCenters : public RiaSocketCommand { quint64 valueIndex = 0; - for (size_t reservoirCellIndex = 0; reservoirCellIndex < mainGrid->cells().size(); reservoirCellIndex++) + for (size_t reservoirCellIndex = 0; reservoirCellIndex < mainGrid->globalCellArray().size(); reservoirCellIndex++) { if (!actCellInfo->isActive(reservoirCellIndex)) continue; - cvf::Vec3d center = mainGrid->cells()[reservoirCellIndex].center(); + cvf::Vec3d center = mainGrid->globalCellArray()[reservoirCellIndex].center(); doubleValues[valueIndex++] = center[coordIdx]; } @@ -352,7 +352,7 @@ class RiaGetActiveCellCorners : public RiaSocketCommand quint64 valueIndex = 0; - for (size_t reservoirCellIndex = 0; reservoirCellIndex < mainGrid->cells().size(); reservoirCellIndex++) + for (size_t reservoirCellIndex = 0; reservoirCellIndex < mainGrid->globalCellArray().size(); reservoirCellIndex++) { if (!actCellInfo->isActive(reservoirCellIndex)) continue; diff --git a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp index a5d9f5a760..d40db3aa32 100644 --- a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp @@ -949,7 +949,7 @@ class RiaSetGridProperty : public RiaSocketCommand // The size of this array must match the test in RigCaseCellResultsData::isUsingGlobalActiveIndex(), // as it is used to determine if we have data for active cells or all cells // See RigCaseCellResultsData::isUsingGlobalActiveIndex() - size_t totalNumberOfCellsIncludingLgrCells = grid->mainGrid()->cells().size(); + size_t totalNumberOfCellsIncludingLgrCells = grid->mainGrid()->globalCellArray().size(); m_scalarResultsToAdd->at(tsId).resize(totalNumberOfCellsIncludingLgrCells, HUGE_VAL); } diff --git a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp index 5dde69324d..6f4fb754ef 100644 --- a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp +++ b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp @@ -515,8 +515,8 @@ QString RiuResultTextBuilder::nncDetails() // First cell of NNC { - CVF_ASSERT(conn.m_c1GlobIdx < grid->cells().size()); - const RigCell& cell = grid->cells()[conn.m_c1GlobIdx]; + CVF_ASSERT(conn.m_c1GlobIdx < grid->globalCellArray().size()); + const RigCell& cell = grid->globalCellArray()[conn.m_c1GlobIdx]; RigGridBase* hostGrid = cell.hostGrid(); size_t gridLocalCellIndex = cell.gridLocalCellIndex(); @@ -536,8 +536,8 @@ QString RiuResultTextBuilder::nncDetails() // Second cell of NNC { - CVF_ASSERT(conn.m_c2GlobIdx < grid->cells().size()); - const RigCell& cell = grid->cells()[conn.m_c2GlobIdx]; + CVF_ASSERT(conn.m_c2GlobIdx < grid->globalCellArray().size()); + const RigCell& cell = grid->globalCellArray()[conn.m_c2GlobIdx]; RigGridBase* hostGrid = cell.hostGrid(); size_t gridLocalCellIndex = cell.gridLocalCellIndex(); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index fd8a0441c9..c0b8006beb 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -450,7 +450,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; - const RigCell& cell = eclipseView->eclipseCase()->reservoirData()->mainGrid()->cells()[globalCellIndex]; + const RigCell& cell = eclipseView->eclipseCase()->reservoirData()->mainGrid()->globalCellArray()[globalCellIndex]; cellIndex = cell.gridLocalCellIndex(); gridIndex = cell.hostGrid()->gridIndex(); } From f18ad19fe227335449e297a5cd511a543112bbe5 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 24 Nov 2015 19:45:53 +0100 Subject: [PATCH 132/290] Intersections: Added icons to commands --- .../RicAppendCrossSectionFeature.cpp | 12 ++++++++---- .../RicNewWellPathCrossSectionFeature.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp index 618e21092f..53e57f1156 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendCrossSectionFeature.cpp @@ -44,12 +44,16 @@ bool RicAppendCrossSectionFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicAppendCrossSectionFeature::onActionTriggered(bool isChecked) { - std::vector collection; + std::vector collection; caf::SelectionManager::instance()->objectsByType(&collection); - CVF_ASSERT(collection.size() == 1); - RicAppendCrossSectionFeatureCmd* cmd = new RicAppendCrossSectionFeatureCmd(collection[0]); + RimCrossSectionCollection* crossSectionCollection = NULL; + collection[0]->firstAnchestorOrThisOfType(crossSectionCollection); + + CVF_ASSERT(crossSectionCollection); + + RicAppendCrossSectionFeatureCmd* cmd = new RicAppendCrossSectionFeatureCmd(crossSectionCollection); caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); } @@ -58,7 +62,7 @@ void RicAppendCrossSectionFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicAppendCrossSectionFeature::setupActionLook(QAction* actionToSetup) { -// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setIcon(QIcon(":/CrossSection16x16.png")); actionToSetup->setText("New Intersection"); } diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp index 662d55969b..5e7362fce5 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathCrossSectionFeature.cpp @@ -74,7 +74,7 @@ void RicNewWellPathCrossSectionFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicNewWellPathCrossSectionFeature::setupActionLook(QAction* actionToSetup) { -// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setIcon(QIcon(":/CrossSection16x16.png")); actionToSetup->setText("New Intersection"); } From faf35d32c616726dca323fe895767fbf43669b00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 10:14:43 +0100 Subject: [PATCH 133/290] (#633) Moved well centerline calculation to make it available for cross sections --- .../RivWellPipesPartMgr.cpp | 348 +--------------- .../ModelVisualization/RivWellPipesPartMgr.h | 7 - .../CMakeLists_filesNotToUnitTest.cmake | 2 + .../RigSimulationWellCenterLineCalculator.cpp | 380 ++++++++++++++++++ .../RigSimulationWellCenterLineCalculator.h | 36 ++ 5 files changed, 420 insertions(+), 353 deletions(-) create mode 100644 ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp create mode 100644 ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index b326f2a4a1..61bd77ec8b 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -49,6 +49,7 @@ #include "cvfRay.h" #include "cvfScalarMapperDiscreteLinear.h" #include "cvfTransform.h" +#include "RigSimulationWellCenterLineCalculator.h" //-------------------------------------------------------------------------------------------------- @@ -101,7 +102,7 @@ void RivWellPipesPartMgr::buildWellPipeParts() m_pipeBranchesCLCoords.clear(); std::vector< std::vector > pipeBranchesCellIds; - calculateWellPipeCenterline(m_pipeBranchesCLCoords, pipeBranchesCellIds); + RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(m_rimWell.p(), m_pipeBranchesCLCoords, pipeBranchesCellIds); double characteristicCellSize = m_rimReservoirView->eclipseCase()->reservoirData()->mainGrid()->characteristicIJCellSize(); double pipeRadius = m_rimReservoirView->wellCollection()->pipeRadiusScaleFactor() *m_rimWell->pipeRadiusScaleFactor() * characteristicCellSize; @@ -167,351 +168,6 @@ void RivWellPipesPartMgr::buildWellPipeParts() m_needsTransformUpdate = false; } - -//-------------------------------------------------------------------------------------------------- -/// Based on the points and cells, calculate a pipe centerline -/// The returned CellIds is one less than the number of centerline points, -/// and are describing the lines between the points, starting with the first line -//-------------------------------------------------------------------------------------------------- -void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector >& pipeBranchesCLCoords, - std::vector< std::vector >& pipeBranchesCellIds) const -{ - CVF_ASSERT(m_rimWell.notNull()); - CVF_ASSERT(m_rimReservoirView.notNull()); - - bool isAutoDetectBranches = m_rimReservoirView->wellCollection()->isAutoDetectingBranches(); - - RigCaseData* rigReservoir = m_rimReservoirView->eclipseCase()->reservoirData(); - RigSingleWellResultsData* wellResults = m_rimWell->wellResults(); - - // Make sure we have computed the static representation of the well - if (wellResults->m_staticWellCells.m_wellResultBranches.size() == 0) - { - wellResults->computeStaticWellCellPath(); - } - - const RigWellResultFrame& staticWellFrame = wellResults->m_staticWellCells; - if (staticWellFrame.m_wellResultBranches.size() == 0) return; - - // Initialize the return arrays - pipeBranchesCLCoords.clear(); - pipeBranchesCellIds.clear(); - - // Well head - // Match this position with well head position in RivWellHeadPartMgr::buildWellHeadParts() - const RigCell& whCell = rigReservoir->cellFromWellResultCell(staticWellFrame.m_wellHead); - cvf::Vec3d whStartPos = whCell.faceCenter(cvf::StructGridInterface::NEG_K); - const RigWellResultPoint* whResCell = &(staticWellFrame.m_wellHead); - - // Loop over all the well branches - const std::vector& resBranches = staticWellFrame.m_wellResultBranches; - bool hasResultCells = false; - if (resBranches.size()) - { - for (size_t i = 0 ; i < resBranches.size(); ++i) - { - if (resBranches[i].m_branchResultPoints.size() != 0) - { - hasResultCells = true; - break; - } - } - } - - if (hasResultCells) - { - - // Add extra coordinate between cell face and cell center - // to make sure the well pipe terminated in a segment parallel to z-axis - cvf::Vec3d whIntermediate = whStartPos; - whIntermediate.z() = (whStartPos.z() + whCell.center().z()) / 2.0; - - const RigWellResultPoint* prevWellResPoint = NULL; - - CVF_ASSERT(wellResults->isMultiSegmentWell() || resBranches.size() <= 1); - - // The centerline is calculated by adding a point when the pipe enters a cell, - // and one when the line leaves the cell. - // For the sake of the loop: - // The currentResultPoint (Cell) and the one we index by the loop variable is the one we calculate the entry point to. - // The previous cell is the one we leave, and calculate the "out-point" from - - - for (size_t brIdx = 0; brIdx < resBranches.size(); brIdx++) - { - - // Skip empty branches. Do not know why they exist, but they make problems. - - bool hasValidData = false; - for (size_t cIdx = 0; cIdx < resBranches[brIdx].m_branchResultPoints.size(); ++cIdx) - { - if (resBranches[brIdx].m_branchResultPoints[cIdx].isValid()) - { - hasValidData = true; - break; - } - } - if (!hasValidData) continue; - - - prevWellResPoint = NULL; - - // Find the start the MSW well-branch centerline. Normal wells are started "once" at wellhead in the code above - - pipeBranchesCLCoords.push_back(std::vector()); - pipeBranchesCellIds.push_back(std::vector ()); - - if (brIdx == 0) - { - // The first branch contains segment number 1, and this is the only segment connected to well head - // See Eclipse documentation for the keyword WELSEGS - prevWellResPoint = whResCell; - - pipeBranchesCLCoords.back().push_back(whStartPos); - pipeBranchesCellIds.back().push_back(*prevWellResPoint); - - pipeBranchesCLCoords.back().push_back(whIntermediate); - pipeBranchesCellIds.back().push_back(*prevWellResPoint); - } - - // Loop over all the resultPoints in the branch - - const std::vector& resBranchCells = resBranches[brIdx].m_branchResultPoints; - - for (int cIdx = 0; cIdx < static_cast(resBranchCells.size()); cIdx++) // Need int because cIdx can temporarily end on -1 - { - std::vector& branchCLCoords = pipeBranchesCLCoords.back(); - std::vector& branchCellIds = pipeBranchesCellIds.back(); - - const RigWellResultPoint& currentWellResPoint = resBranchCells[cIdx]; - - // Ignore invalid cells - - if (!currentWellResPoint.isValid()) - { - //CVF_ASSERT(false); // Some segments does not get anything yet. - continue; - } - - // Add cl contribution for a geometrical resultPoint by adding exit point from previous cell, - // and then the result point position - - if (!currentWellResPoint.isCell()) - { - // Use the interpolated value of branch head - CVF_ASSERT(currentWellResPoint.isPointValid()); - - cvf::Vec3d currentPoint = currentWellResPoint.m_bottomPosition; - - // If we have a real previous cell, we need to go out of it, before adding the current point - // That is: add a CL-point describing where it leaves the previous cell. - - if (prevWellResPoint && prevWellResPoint->isCell()) - { - // Create ray between the previous and this position - - const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevWellResPoint); - cvf::Vec3d centerPreviousCell = prevCell.center(); - - cvf::Ray rayToThisCell; - rayToThisCell.setOrigin(centerPreviousCell); - rayToThisCell.setDirection((currentPoint - centerPreviousCell).getNormalized()); - - cvf::Vec3d outOfPrevCell(centerPreviousCell); - - //int intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); - //CVF_ASSERT(intersectionOk); - //CVF_ASSERT(intersectionOk); - if ((currentPoint - outOfPrevCell).lengthSquared() > 1e-3) - { - branchCLCoords.push_back(outOfPrevCell); - branchCellIds.push_back(RigWellResultPoint()); - } - - } - - branchCLCoords.push_back(currentPoint); - branchCellIds.push_back(currentWellResPoint); - - prevWellResPoint = ¤tWellResPoint; - - continue; - } - - // - // Handle currentWellResPoint as a real cell result points. - // - - const RigCell& cell = rigReservoir->cellFromWellResultCell(currentWellResPoint); - - // Check if this and the previous cells has shared faces - - cvf::StructGridInterface::FaceType sharedFace; - if (prevWellResPoint && prevWellResPoint->isCell() && rigReservoir->findSharedSourceFace(sharedFace, currentWellResPoint, *prevWellResPoint)) - { - // If they share faces, the shared face center is used as point - // describing the entry of this cell. (And exit of the previous cell) - - branchCLCoords.push_back(cell.faceCenter(sharedFace)); - branchCellIds.push_back(currentWellResPoint); - } - else - { - // This and the previous cell does not share a face. - // Then we need to calculate the exit of the previous cell, and the entry point into this cell - - cvf::Vec3d centerPreviousCell(cvf::Vec3d::ZERO); - cvf::Vec3d centerThisCell = cell.center(); - bool distanceToWellHeadIsLonger = true; - - // If we have a previous well result point, use its center as measure point and ray intersection start - // when considering things. - - if (prevWellResPoint && prevWellResPoint->isValid()) - { - if (prevWellResPoint->isCell()) - { - const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevWellResPoint); - centerPreviousCell = prevCell.center(); - } - else - { - centerPreviousCell = prevWellResPoint->m_bottomPosition; - } - - distanceToWellHeadIsLonger = (centerThisCell - centerPreviousCell).lengthSquared() <= (centerThisCell - whStartPos).lengthSquared(); - } - - - // First make sure this cell is not starting a new "display" branch for none MSW's - - if ( wellResults->isMultiSegmentWell() - || !isAutoDetectBranches - || (prevWellResPoint == whResCell) - || distanceToWellHeadIsLonger) - { - // Not starting a "display" branch for normal wells - // Calculate the exit of the previous cell, and the entry point into this cell - - cvf::Vec3d intoThisCell(centerThisCell); // Use cell center as default for "into" point. - - if (prevWellResPoint && prevWellResPoint->isValid()) - { - // We have a defined previous point - // Create ray between the previous and this cell - - cvf::Ray rayToThisCell; - rayToThisCell.setOrigin(centerPreviousCell); - rayToThisCell.setDirection((centerThisCell - centerPreviousCell).getNormalized()); - - // Intersect with the current cell to find a better entry point than the cell center - - int intersectionCount = cell.firstIntersectionPoint(rayToThisCell, &intoThisCell); - bool isPreviousResPointInsideCurrentCell = (intersectionCount % 2); // Must intersect uneven times to be inside. (1 % 2 = 1) - - // If we have a real previous cell, we need to go out of it, before entering this. - // That is: add a CL-point describing where it leaves the previous cell. - - if ( prevWellResPoint->isCell()) - { - cvf::Vec3d outOfPrevCell(centerPreviousCell); - - const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevWellResPoint); - //bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); - //CVF_ASSERT(intersectionOk); - //CVF_ASSERT(intersectionOk); - if ((intoThisCell - outOfPrevCell).lengthSquared() > 1e-3) - { - branchCLCoords.push_back(outOfPrevCell); - branchCellIds.push_back(RigWellResultPoint()); - } - } - else if (isPreviousResPointInsideCurrentCell) - { - // Since the previous point actually is inside this cell, - /// use that as the entry point into this cell - intoThisCell = centerPreviousCell; - } - - } - - branchCLCoords.push_back(intoThisCell); - branchCellIds.push_back(currentWellResPoint); - } - else - { - // Need to start a "display branch" for a Normal Well. - - CVF_ASSERT(!wellResults->isMultiSegmentWell()); - - // This cell is further from the previous cell than from the well head, - // thus we interpret it as a new branch. - - // First finish the current branch in the previous cell - //branchCLCoords.push_back(branchCLCoords.back() + 1.5*(centerPreviousCell - branchCLCoords.back()) ); - finishPipeCenterLine(pipeBranchesCLCoords, centerPreviousCell); - - // Create new display branch - pipeBranchesCLCoords.push_back(std::vector()); - pipeBranchesCellIds.push_back(std::vector ()); - - // Start the new branch by entering the first cell (the wellhead) and intermediate - prevWellResPoint = whResCell; - pipeBranchesCLCoords.back().push_back(whStartPos); - pipeBranchesCellIds.back().push_back(*prevWellResPoint); - - // Include intermediate - pipeBranchesCLCoords.back().push_back(whIntermediate); - pipeBranchesCellIds.back().push_back(*prevWellResPoint); - - // Well now we need to step one back to take this cell again, but in the new branch. - cIdx--; - continue; - } - } - - prevWellResPoint = ¤tWellResPoint; - } - - // For the last cell, add the point 0.5 past the center of that cell - // Remember that prevWellResPoint actually is the last one in this branch. - - cvf::Vec3d centerLastCell; - if (prevWellResPoint && prevWellResPoint->isCell()) - { - const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevWellResPoint); - centerLastCell = prevCell.center(); - finishPipeCenterLine(pipeBranchesCLCoords, centerLastCell); - } - else - { - // Remove the ID that is superfluous since we will not add an ending point - pipeBranchesCellIds.back().pop_back(); - } - } - } - - CVF_ASSERT(pipeBranchesCellIds.size() == pipeBranchesCLCoords.size()); - for (size_t i = 0 ; i < pipeBranchesCellIds.size() ; ++i) - { - CVF_ASSERT(pipeBranchesCellIds[i].size() == pipeBranchesCLCoords[i].size()-1); - } -} - -//-------------------------------------------------------------------------------------------------- -/// All branches are completed using the point 0.5 past the center of -/// last cell. -//-------------------------------------------------------------------------------------------------- -void RivWellPipesPartMgr::finishPipeCenterLine(std::vector< std::vector > &pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter) const -{ - CVF_ASSERT(pipeBranchesCLCoords.size()); - CVF_ASSERT(pipeBranchesCLCoords.back().size()); - - cvf::Vec3d entryPointLastCell = pipeBranchesCLCoords.back().back(); - - pipeBranchesCLCoords.back().push_back(entryPointLastCell + 1.5*(lastCellCenter - entryPointLastCell) ); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h index 383984dd0b..ecaaef8c73 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.h @@ -65,13 +65,6 @@ class RivWellPipesPartMgr : public cvf::Object void buildWellPipeParts(); - //void calculateWellPipeCenterline(std::vector& coords) const; - - void calculateWellPipeCenterline(std::vector< std::vector >& pipeBranchesCLCoords, - std::vector< std::vector >& pipeBranchesCellIds ) const; - - void finishPipeCenterLine( std::vector< std::vector > &pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter ) const; - struct RivPipeBranchData { std::vector m_cellIds; diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake index d7ef0c9661..c4a8d123b6 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_filesNotToUnitTest.cmake @@ -9,6 +9,7 @@ set (SOURCE_GROUP_HEADER_FILES ${CEE_CURRENT_LIST_DIR}RigCaseToCaseCellMapper.h ${CEE_CURRENT_LIST_DIR}RigCaseToCaseCellMapperTools.h ${CEE_CURRENT_LIST_DIR}RigCaseToCaseRangeFilterMapper.h + ${CEE_CURRENT_LIST_DIR}RigSimulationWellCenterLineCalculator.h ${CEE_CURRENT_LIST_DIR}RigWellLogFile.h ) @@ -17,6 +18,7 @@ set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RigCaseToCaseCellMapper.cpp ${CEE_CURRENT_LIST_DIR}RigCaseToCaseCellMapperTools.cpp ${CEE_CURRENT_LIST_DIR}RigCaseToCaseRangeFilterMapper.cpp + ${CEE_CURRENT_LIST_DIR}RigSimulationWellCenterLineCalculator.cpp ${CEE_CURRENT_LIST_DIR}RigWellLogFile.cpp ) diff --git a/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp new file mode 100644 index 0000000000..fdfd37cc49 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp @@ -0,0 +1,380 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigSimulationWellCenterLineCalculator.h" +#include "RimEclipseView.h" +#include "RimEclipseWell.h" +#include "RimEclipseWellCollection.h" +#include "RimEclipseCase.h" +#include "RigCaseData.h" +#include "cvfRay.h" + +//-------------------------------------------------------------------------------------------------- +/// Based on the points and cells, calculate a pipe centerline +/// The returned CellIds is one less than the number of centerline points, +/// and are describing the lines between the points, starting with the first line +//-------------------------------------------------------------------------------------------------- +void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(RimEclipseWell* rimWell, + std::vector< std::vector >& pipeBranchesCLCoords, + std::vector< std::vector >& pipeBranchesCellIds) +{ + bool isAutoDetectBranches = false; + RigCaseData* eclipseCaseData = NULL; + RigSingleWellResultsData* wellResults = NULL; + + { + CVF_ASSERT(rimWell); + RimEclipseView* eclipseView; + rimWell->firstAnchestorOrThisOfType(eclipseView); + CVF_ASSERT(eclipseView); + + isAutoDetectBranches = eclipseView->wellCollection()->isAutoDetectingBranches(); + eclipseCaseData = eclipseView->eclipseCase()->reservoirData(); + wellResults = rimWell->wellResults(); + } + + // Make sure we have computed the static representation of the well + if (wellResults->m_staticWellCells.m_wellResultBranches.size() == 0) + { + wellResults->computeStaticWellCellPath(); + } + + const RigWellResultFrame& staticWellFrame = wellResults->m_staticWellCells; + if (staticWellFrame.m_wellResultBranches.size() == 0) return; + + // Initialize the return arrays + pipeBranchesCLCoords.clear(); + pipeBranchesCellIds.clear(); + + // Well head + // Match this position with well head position in RivWellHeadPartMgr::buildWellHeadParts() + const RigCell& whCell = eclipseCaseData->cellFromWellResultCell(staticWellFrame.m_wellHead); + cvf::Vec3d whStartPos = whCell.faceCenter(cvf::StructGridInterface::NEG_K); + const RigWellResultPoint* whResCell = &(staticWellFrame.m_wellHead); + + // Loop over all the well branches + const std::vector& resBranches = staticWellFrame.m_wellResultBranches; + bool hasResultCells = false; + if (resBranches.size()) + { + for (size_t i = 0 ; i < resBranches.size(); ++i) + { + if (resBranches[i].m_branchResultPoints.size() != 0) + { + hasResultCells = true; + break; + } + } + } + + if (hasResultCells) + { + + // Add extra coordinate between cell face and cell center + // to make sure the well pipe terminated in a segment parallel to z-axis + cvf::Vec3d whIntermediate = whStartPos; + whIntermediate.z() = (whStartPos.z() + whCell.center().z()) / 2.0; + + const RigWellResultPoint* prevWellResPoint = NULL; + + CVF_ASSERT(wellResults->isMultiSegmentWell() || resBranches.size() <= 1); + + // The centerline is calculated by adding a point when the pipe enters a cell, + // and one when the line leaves the cell. + // For the sake of the loop: + // The currentResultPoint (Cell) and the one we index by the loop variable is the one we calculate the entry point to. + // The previous cell is the one we leave, and calculate the "out-point" from + + + for (size_t brIdx = 0; brIdx < resBranches.size(); brIdx++) + { + + // Skip empty branches. Do not know why they exist, but they make problems. + + bool hasValidData = false; + for (size_t cIdx = 0; cIdx < resBranches[brIdx].m_branchResultPoints.size(); ++cIdx) + { + if (resBranches[brIdx].m_branchResultPoints[cIdx].isValid()) + { + hasValidData = true; + break; + } + } + if (!hasValidData) continue; + + + prevWellResPoint = NULL; + + // Find the start the MSW well-branch centerline. Normal wells are started "once" at wellhead in the code above + + pipeBranchesCLCoords.push_back(std::vector()); + pipeBranchesCellIds.push_back(std::vector ()); + + if (brIdx == 0) + { + // The first branch contains segment number 1, and this is the only segment connected to well head + // See Eclipse documentation for the keyword WELSEGS + prevWellResPoint = whResCell; + + pipeBranchesCLCoords.back().push_back(whStartPos); + pipeBranchesCellIds.back().push_back(*prevWellResPoint); + + pipeBranchesCLCoords.back().push_back(whIntermediate); + pipeBranchesCellIds.back().push_back(*prevWellResPoint); + } + + // Loop over all the resultPoints in the branch + + const std::vector& resBranchCells = resBranches[brIdx].m_branchResultPoints; + + for (int cIdx = 0; cIdx < static_cast(resBranchCells.size()); cIdx++) // Need int because cIdx can temporarily end on -1 + { + std::vector& branchCLCoords = pipeBranchesCLCoords.back(); + std::vector& branchCellIds = pipeBranchesCellIds.back(); + + const RigWellResultPoint& currentWellResPoint = resBranchCells[cIdx]; + + // Ignore invalid cells + + if (!currentWellResPoint.isValid()) + { + //CVF_ASSERT(false); // Some segments does not get anything yet. + continue; + } + + // Add cl contribution for a geometrical resultPoint by adding exit point from previous cell, + // and then the result point position + + if (!currentWellResPoint.isCell()) + { + // Use the interpolated value of branch head + CVF_ASSERT(currentWellResPoint.isPointValid()); + + cvf::Vec3d currentPoint = currentWellResPoint.m_bottomPosition; + + // If we have a real previous cell, we need to go out of it, before adding the current point + // That is: add a CL-point describing where it leaves the previous cell. + + if (prevWellResPoint && prevWellResPoint->isCell()) + { + // Create ray between the previous and this position + + const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell(*prevWellResPoint); + cvf::Vec3d centerPreviousCell = prevCell.center(); + + cvf::Ray rayToThisCell; + rayToThisCell.setOrigin(centerPreviousCell); + rayToThisCell.setDirection((currentPoint - centerPreviousCell).getNormalized()); + + cvf::Vec3d outOfPrevCell(centerPreviousCell); + + //int intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); + //CVF_ASSERT(intersectionOk); + //CVF_ASSERT(intersectionOk); + if ((currentPoint - outOfPrevCell).lengthSquared() > 1e-3) + { + branchCLCoords.push_back(outOfPrevCell); + branchCellIds.push_back(RigWellResultPoint()); + } + + } + + branchCLCoords.push_back(currentPoint); + branchCellIds.push_back(currentWellResPoint); + + prevWellResPoint = ¤tWellResPoint; + + continue; + } + + // + // Handle currentWellResPoint as a real cell result points. + // + + const RigCell& cell = eclipseCaseData->cellFromWellResultCell(currentWellResPoint); + + // Check if this and the previous cells has shared faces + + cvf::StructGridInterface::FaceType sharedFace; + if (prevWellResPoint && prevWellResPoint->isCell() && eclipseCaseData->findSharedSourceFace(sharedFace, currentWellResPoint, *prevWellResPoint)) + { + // If they share faces, the shared face center is used as point + // describing the entry of this cell. (And exit of the previous cell) + + branchCLCoords.push_back(cell.faceCenter(sharedFace)); + branchCellIds.push_back(currentWellResPoint); + } + else + { + // This and the previous cell does not share a face. + // Then we need to calculate the exit of the previous cell, and the entry point into this cell + + cvf::Vec3d centerPreviousCell(cvf::Vec3d::ZERO); + cvf::Vec3d centerThisCell = cell.center(); + bool distanceToWellHeadIsLonger = true; + + // If we have a previous well result point, use its center as measure point and ray intersection start + // when considering things. + + if (prevWellResPoint && prevWellResPoint->isValid()) + { + if (prevWellResPoint->isCell()) + { + const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell(*prevWellResPoint); + centerPreviousCell = prevCell.center(); + } + else + { + centerPreviousCell = prevWellResPoint->m_bottomPosition; + } + + distanceToWellHeadIsLonger = (centerThisCell - centerPreviousCell).lengthSquared() <= (centerThisCell - whStartPos).lengthSquared(); + } + + + // First make sure this cell is not starting a new "display" branch for none MSW's + + if ( wellResults->isMultiSegmentWell() + || !isAutoDetectBranches + || (prevWellResPoint == whResCell) + || distanceToWellHeadIsLonger) + { + // Not starting a "display" branch for normal wells + // Calculate the exit of the previous cell, and the entry point into this cell + + cvf::Vec3d intoThisCell(centerThisCell); // Use cell center as default for "into" point. + + if (prevWellResPoint && prevWellResPoint->isValid()) + { + // We have a defined previous point + // Create ray between the previous and this cell + + cvf::Ray rayToThisCell; + rayToThisCell.setOrigin(centerPreviousCell); + rayToThisCell.setDirection((centerThisCell - centerPreviousCell).getNormalized()); + + // Intersect with the current cell to find a better entry point than the cell center + + int intersectionCount = cell.firstIntersectionPoint(rayToThisCell, &intoThisCell); + bool isPreviousResPointInsideCurrentCell = (intersectionCount % 2); // Must intersect uneven times to be inside. (1 % 2 = 1) + + // If we have a real previous cell, we need to go out of it, before entering this. + // That is: add a CL-point describing where it leaves the previous cell. + + if ( prevWellResPoint->isCell()) + { + cvf::Vec3d outOfPrevCell(centerPreviousCell); + + const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell(*prevWellResPoint); + //bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); + //CVF_ASSERT(intersectionOk); + //CVF_ASSERT(intersectionOk); + if ((intoThisCell - outOfPrevCell).lengthSquared() > 1e-3) + { + branchCLCoords.push_back(outOfPrevCell); + branchCellIds.push_back(RigWellResultPoint()); + } + } + else if (isPreviousResPointInsideCurrentCell) + { + // Since the previous point actually is inside this cell, + /// use that as the entry point into this cell + intoThisCell = centerPreviousCell; + } + + } + + branchCLCoords.push_back(intoThisCell); + branchCellIds.push_back(currentWellResPoint); + } + else + { + // Need to start a "display branch" for a Normal Well. + + CVF_ASSERT(!wellResults->isMultiSegmentWell()); + + // This cell is further from the previous cell than from the well head, + // thus we interpret it as a new branch. + + // First finish the current branch in the previous cell + //branchCLCoords.push_back(branchCLCoords.back() + 1.5*(centerPreviousCell - branchCLCoords.back()) ); + finishPipeCenterLine(pipeBranchesCLCoords, centerPreviousCell); + + // Create new display branch + pipeBranchesCLCoords.push_back(std::vector()); + pipeBranchesCellIds.push_back(std::vector ()); + + // Start the new branch by entering the first cell (the wellhead) and intermediate + prevWellResPoint = whResCell; + pipeBranchesCLCoords.back().push_back(whStartPos); + pipeBranchesCellIds.back().push_back(*prevWellResPoint); + + // Include intermediate + pipeBranchesCLCoords.back().push_back(whIntermediate); + pipeBranchesCellIds.back().push_back(*prevWellResPoint); + + // Well now we need to step one back to take this cell again, but in the new branch. + cIdx--; + continue; + } + } + + prevWellResPoint = ¤tWellResPoint; + } + + // For the last cell, add the point 0.5 past the center of that cell + // Remember that prevWellResPoint actually is the last one in this branch. + + cvf::Vec3d centerLastCell; + if (prevWellResPoint && prevWellResPoint->isCell()) + { + const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell(*prevWellResPoint); + centerLastCell = prevCell.center(); + finishPipeCenterLine(pipeBranchesCLCoords, centerLastCell); + } + else + { + // Remove the ID that is superfluous since we will not add an ending point + pipeBranchesCellIds.back().pop_back(); + } + } + } + + CVF_ASSERT(pipeBranchesCellIds.size() == pipeBranchesCLCoords.size()); + for (size_t i = 0 ; i < pipeBranchesCellIds.size() ; ++i) + { + CVF_ASSERT(pipeBranchesCellIds[i].size() == pipeBranchesCLCoords[i].size()-1); + } +} + +//-------------------------------------------------------------------------------------------------- +/// All branches are completed using the point 0.5 past the center of +/// last cell. +//-------------------------------------------------------------------------------------------------- +void RigSimulationWellCenterLineCalculator::finishPipeCenterLine(std::vector< std::vector > &pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter) +{ + CVF_ASSERT(pipeBranchesCLCoords.size()); + CVF_ASSERT(pipeBranchesCLCoords.back().size()); + + cvf::Vec3d entryPointLastCell = pipeBranchesCLCoords.back().back(); + + pipeBranchesCLCoords.back().push_back(entryPointLastCell + 1.5*(lastCellCenter - entryPointLastCell) ); +} + + diff --git a/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h new file mode 100644 index 0000000000..7fc3396a67 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RigSingleWellResultsData.h" +#include "cvfVector3.h" +#include + +class RimEclipseWell; + +class RigSimulationWellCenterLineCalculator +{ +public: + static void calculateWellPipeCenterline(RimEclipseWell* m_rimWell, + std::vector< std::vector >& pipeBranchesCLCoords, + std::vector< std::vector >& pipeBranchesCellIds) ; +private: + static void finishPipeCenterLine( std::vector< std::vector > &pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter ) ; +}; + From 3e78eebee3bd73b2ed87e695295c00b94a1926b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 11:08:38 +0100 Subject: [PATCH 134/290] (#633) Cross sections on simulation wells --- .../RivCrossSectionGeometryGenerator.cpp | 205 +++++++++--------- .../RivCrossSectionGeometryGenerator.h | 4 +- .../RivCrossSectionPartMgr.cpp | 8 +- .../ProjectDataModel/RimCrossSection.cpp | 15 +- .../UserInterface/RiuViewerCommands.cpp | 4 +- 5 files changed, 121 insertions(+), 115 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index bede30df63..f08201bfb9 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -29,10 +29,10 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector &polyline, +RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector > &polylines, const cvf::Vec3d& extrusionDirection, const RivCrossSectionHexGridIntf* grid) - : m_polyLine(polyline), + : m_polyLines(polylines), m_extrusionDirection(extrusionDirection), m_hexGrid(grid) { @@ -968,136 +968,137 @@ void RivCrossSectionGeometryGenerator::calculateArrays() if (m_triangleVxes->size()) return; m_extrusionDirection.normalize(); - std::vector m_adjustedPolyline; - - adjustPolyline(m_polyLine, m_extrusionDirection, &m_adjustedPolyline); - std::vector triangleVertices; std::vector cellBorderLineVxes; - cvf::Vec3d displayOffset = m_hexGrid->displayOffset(); cvf::BoundingBox gridBBox = m_hexGrid->boundingBox(); - size_t lineCount = m_adjustedPolyline.size(); - for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) + for (size_t pLineIdx = 0; pLineIdx < m_polyLines.size(); ++pLineIdx) { - cvf::Vec3d p1 = m_adjustedPolyline[lIdx]; - cvf::Vec3d p2 = m_adjustedPolyline[lIdx+1]; - - cvf::BoundingBox sectionBBox; - sectionBBox.add(p1); - sectionBBox.add(p2); - double maxSectionHeight = gridBBox.radius(); - sectionBBox.add(p1 + m_extrusionDirection*maxSectionHeight); - sectionBBox.add(p1 - m_extrusionDirection*maxSectionHeight); - sectionBBox.add(p2 + m_extrusionDirection*maxSectionHeight); - sectionBBox.add(p2 - m_extrusionDirection*maxSectionHeight); - - std::vector columnCellCandidates; - m_hexGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); - - cvf::Plane plane; - plane.setFromPoints(p1, p2, p2 + m_extrusionDirection*maxSectionHeight); - - cvf::Plane p1Plane; - p1Plane.setFromPoints(p1, p1 + m_extrusionDirection*maxSectionHeight, p1 + plane.normal()); - cvf::Plane p2Plane; - p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 - plane.normal() ); - - - std::vector hexPlaneCutTriangleVxes; - hexPlaneCutTriangleVxes.reserve(5*3); - std::vector isTriangleEdgeCellContour; - isTriangleEdgeCellContour.reserve(5*3); - cvf::Vec3d cellCorners[8]; - size_t cornerIndices[8]; - - for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) + const std::vector& m_polyLine = m_polyLines[pLineIdx]; + std::vector m_adjustedPolyline; + adjustPolyline(m_polyLine, m_extrusionDirection, &m_adjustedPolyline); + + size_t lineCount = m_adjustedPolyline.size(); + for (size_t lIdx = 0; lIdx < lineCount - 1; ++lIdx) { - size_t globalCellIdx = columnCellCandidates[cccIdx]; + cvf::Vec3d p1 = m_adjustedPolyline[lIdx]; + cvf::Vec3d p2 = m_adjustedPolyline[lIdx+1]; + + cvf::BoundingBox sectionBBox; + sectionBBox.add(p1); + sectionBBox.add(p2); + double maxSectionHeight = gridBBox.radius(); + sectionBBox.add(p1 + m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p1 - m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p2 + m_extrusionDirection*maxSectionHeight); + sectionBBox.add(p2 - m_extrusionDirection*maxSectionHeight); + + std::vector columnCellCandidates; + m_hexGrid->findIntersectingCells(sectionBBox, &columnCellCandidates); + + cvf::Plane plane; + plane.setFromPoints(p1, p2, p2 + m_extrusionDirection*maxSectionHeight); + + cvf::Plane p1Plane; + p1Plane.setFromPoints(p1, p1 + m_extrusionDirection*maxSectionHeight, p1 + plane.normal()); + cvf::Plane p2Plane; + p2Plane.setFromPoints(p2, p2 + m_extrusionDirection*maxSectionHeight, p2 - plane.normal()); + + + std::vector hexPlaneCutTriangleVxes; + hexPlaneCutTriangleVxes.reserve(5*3); + std::vector isTriangleEdgeCellContour; + isTriangleEdgeCellContour.reserve(5*3); + cvf::Vec3d cellCorners[8]; + size_t cornerIndices[8]; + + for (size_t cccIdx = 0; cccIdx < columnCellCandidates.size(); ++cccIdx) + { + size_t globalCellIdx = columnCellCandidates[cccIdx]; - if (!m_hexGrid->useCell(globalCellIdx)) continue; - - hexPlaneCutTriangleVxes.clear(); - m_hexGrid->cellCornerVertices(globalCellIdx, cellCorners); - m_hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); + if (!m_hexGrid->useCell(globalCellIdx)) continue; - int triangleCount = planeHexIntersectionMC(plane, - cellCorners, - cornerIndices, - &hexPlaneCutTriangleVxes, - &isTriangleEdgeCellContour); - - std::vector clippedTriangleVxes; - std::vector isClippedTriEdgeCellContour; + hexPlaneCutTriangleVxes.clear(); + m_hexGrid->cellCornerVertices(globalCellIdx, cellCorners); + m_hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); - clipTrianglesBetweenTwoParallelPlanes(hexPlaneCutTriangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, - &clippedTriangleVxes, &isClippedTriEdgeCellContour); + int triangleCount = planeHexIntersectionMC(plane, + cellCorners, + cornerIndices, + &hexPlaneCutTriangleVxes, + &isTriangleEdgeCellContour); - size_t clippedTriangleCount = clippedTriangleVxes.size()/3; + std::vector clippedTriangleVxes; + std::vector isClippedTriEdgeCellContour; - for (uint tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) - { - uint triVxIdx = tIdx*3; + clipTrianglesBetweenTwoParallelPlanes(hexPlaneCutTriangleVxes, isTriangleEdgeCellContour, p1Plane, p2Plane, + &clippedTriangleVxes, &isClippedTriEdgeCellContour); - // Accumulate triangle vertices + size_t clippedTriangleCount = clippedTriangleVxes.size()/3; - cvf::Vec3f p0(clippedTriangleVxes[triVxIdx+0].vx - displayOffset); - cvf::Vec3f p1(clippedTriangleVxes[triVxIdx+1].vx - displayOffset); - cvf::Vec3f p2(clippedTriangleVxes[triVxIdx+2].vx - displayOffset); + for (uint tIdx = 0; tIdx < clippedTriangleCount; ++tIdx) + { + uint triVxIdx = tIdx*3; - triangleVertices.push_back(p0); - triangleVertices.push_back(p1); - triangleVertices.push_back(p2); + // Accumulate triangle vertices + cvf::Vec3f p0(clippedTriangleVxes[triVxIdx+0].vx - displayOffset); + cvf::Vec3f p1(clippedTriangleVxes[triVxIdx+1].vx - displayOffset); + cvf::Vec3f p2(clippedTriangleVxes[triVxIdx+2].vx - displayOffset); - // Accumulate mesh lines + triangleVertices.push_back(p0); + triangleVertices.push_back(p1); + triangleVertices.push_back(p2); - if (isClippedTriEdgeCellContour[triVxIdx]) - { - cellBorderLineVxes.push_back(p0); - cellBorderLineVxes.push_back(p1); - } - if (isClippedTriEdgeCellContour[triVxIdx+1]) - { - cellBorderLineVxes.push_back(p1); - cellBorderLineVxes.push_back(p2); - } - if (isClippedTriEdgeCellContour[triVxIdx+2]) - { - cellBorderLineVxes.push_back(p2); - cellBorderLineVxes.push_back(p0); - } - - // Mapping to cell index - m_triangleToCellIdxMap.push_back(globalCellIdx); + // Accumulate mesh lines - // Interpolation from nodes - for (int i = 0; i < 3; ++i) - { - ClipVx cvx = clippedTriangleVxes[triVxIdx+i]; - if (cvx.isVxIdsNative) + if (isClippedTriEdgeCellContour[triVxIdx]) + { + cellBorderLineVxes.push_back(p0); + cellBorderLineVxes.push_back(p1); + } + if (isClippedTriEdgeCellContour[triVxIdx+1]) { - m_triVxToCellCornerWeights.push_back( - RivVertexWeights(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1)); + cellBorderLineVxes.push_back(p1); + cellBorderLineVxes.push_back(p2); } - else + if (isClippedTriEdgeCellContour[triVxIdx+2]) { - ClipVx cvx1 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx1Id]; - ClipVx cvx2 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx2Id]; + cellBorderLineVxes.push_back(p2); + cellBorderLineVxes.push_back(p0); + } + + // Mapping to cell index - m_triVxToCellCornerWeights.push_back( - RivVertexWeights(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, - cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, - cvx.normDistFromEdgeVx1)); + m_triangleToCellIdxMap.push_back(globalCellIdx); + // Interpolation from nodes + for (int i = 0; i < 3; ++i) + { + ClipVx cvx = clippedTriangleVxes[triVxIdx+i]; + if (cvx.isVxIdsNative) + { + m_triVxToCellCornerWeights.push_back( + RivVertexWeights(cvx.clippedEdgeVx1Id, cvx.clippedEdgeVx2Id, cvx.normDistFromEdgeVx1)); + } + else + { + ClipVx cvx1 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx1Id]; + ClipVx cvx2 = hexPlaneCutTriangleVxes[cvx.clippedEdgeVx2Id]; + + m_triVxToCellCornerWeights.push_back( + RivVertexWeights(cvx1.clippedEdgeVx1Id, cvx1.clippedEdgeVx2Id, cvx1.normDistFromEdgeVx1, + cvx2.clippedEdgeVx1Id, cvx2.clippedEdgeVx2Id, cvx2.normDistFromEdgeVx1, + cvx.normDistFromEdgeVx1)); + + } } } } } } - m_triangleVxes->assign(triangleVertices); m_cellBorderLineVxes->assign(cellBorderLineVxes); } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index e20ade141c..f2e96c74c4 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -124,7 +124,7 @@ class RivVertexWeights class RivCrossSectionGeometryGenerator : public cvf::Object { public: - RivCrossSectionGeometryGenerator(const std::vector &polyline, + RivCrossSectionGeometryGenerator(const std::vector > &polylines, const cvf::Vec3d& extrusionDirection, const RivCrossSectionHexGridIntf* grid ); @@ -145,7 +145,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object std::vector* adjustedPolyline); cvf::cref m_hexGrid; - std::vector m_polyLine; + const std::vector > m_polyLines; cvf::Vec3d m_extrusionDirection; // Output arrays diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 10990afa34..75a8cdcf89 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -412,12 +412,12 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::computeData() { - std::vector< std::vector > polyLine = m_rimCrossSection->polyLines(); - if (polyLine.size() > 0) + std::vector< std::vector > polyLines = m_rimCrossSection->polyLines(); + if (polyLines.size() > 0) { - cvf::Vec3d direction = extrusionDirection(polyLine[0]); + cvf::Vec3d direction = extrusionDirection(polyLines[0]); cvf::ref hexGrid = createHexGridInterface(); - m_crossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLine[0], direction, hexGrid.p()); + m_crossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLines, direction, hexGrid.p()); } } diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index d383601934..4a371906eb 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -29,6 +29,7 @@ #include "RimWellPath.h" #include "RivCrossSectionPartMgr.h" +#include "RigSimulationWellCenterLineCalculator.h" namespace caf { @@ -37,7 +38,7 @@ template<> void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() { addItem(RimCrossSection::CS_WELL_PATH, "CS_WELL_PATH", "Well Path"); -// addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); + addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); // addItem(RimCrossSection::CS_USER_DEFINED, "CS_USER_DEFINED", "User defined"); setDefault(RimCrossSection::CS_WELL_PATH); } @@ -111,7 +112,7 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& } else if (type == CS_SIMULATION_WELL) { - //uiOrdering.add(&simulationWell); + uiOrdering.add(&simulationWell); } else { @@ -211,14 +212,18 @@ std::vector< std::vector > RimCrossSection::polyLines() const std::vector< std::vector > lines; if (type == CS_WELL_PATH) { - if (wellPath) + if (wellPath()) { lines.push_back(wellPath->wellPathGeometry()->m_wellPathPoints); } } else if (type == CS_SIMULATION_WELL) { - + if (simulationWell()) + { + std::vector< std::vector > pipeBranchesCellIds; + RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(simulationWell(), lines, pipeBranchesCellIds); + } } else { @@ -231,8 +236,10 @@ std::vector< std::vector > RimCrossSection::polyLines() const { cvf::Vec3d startToEnd = (lines[lIdx].back() - lines[lIdx].front()); startToEnd[2] = 0.0; + cvf::Vec3d newStart = lines[lIdx].front() - startToEnd * 0.1; cvf::Vec3d newEnd = lines[lIdx].back() + startToEnd * 0.1; + lines[lIdx].insert(lines[lIdx].begin(), newStart); lines[lIdx].push_back(newEnd); } diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index c0b8006beb..3816b46598 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -240,8 +240,6 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) } } -// TODO: Include when cross section from simulation wells are ready -/* const RivEclipseWellSourceInfo* eclipseWellSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (eclipseWellSourceInfo) { @@ -253,7 +251,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) commandIds << "RicNewSimWellCrossSectionFeature"; } } -*/ + } // View Link commands From d808c268a46e11df11fd45bea005f9c0d818e2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 13:38:27 +0100 Subject: [PATCH 135/290] Added icon to Simulation Well Intersection command --- .../CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp index 4b8be2785e..a8ca952fe9 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewSimWellCrossSectionFeature.cpp @@ -65,7 +65,7 @@ void RicNewSimWellCrossSectionFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicNewSimWellCrossSectionFeature::setupActionLook(QAction* actionToSetup) { -// actionToSetup->setIcon(QIcon(":/CellFilter_Values.png")); + actionToSetup->setIcon(QIcon(":/CrossSection16x16.png")); actionToSetup->setText("New Intersection"); } From b075c57515a1e2332e8929d773d1e538c0c7da5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 13:39:31 +0100 Subject: [PATCH 136/290] (#633) Added branch control to simulation well cross sections. --- .../ProjectDataModel/RimCrossSection.cpp | 69 +++++++++++++++++-- .../ProjectDataModel/RimCrossSection.h | 3 + 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 4a371906eb..2f112541fd 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -67,11 +67,12 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); - CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); CAF_PDM_InitFieldNoDefault(&type, "Type", "Type", "", "", ""); CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); - + CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); + CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); + CAF_PDM_InitField (&branchIndex, "Branch", -1, "Branch", "", "", ""); + uiCapability()->setUiChildrenHidden(true); } @@ -84,7 +85,8 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, changedField == &type || changedField == &direction || changedField == &wellPath || - changedField == &simulationWell) + changedField == &simulationWell || + changedField == &branchIndex) { m_crossSectionPartMgr = NULL; @@ -95,6 +97,15 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, rimView->scheduleCreateDisplayModelAndRedraw(); } } + + if (changedField == &simulationWell + || changedField == &isActive + || changedField == &type) + { + m_wellBranchCenterlines.clear(); + updateWellCenterline(); + branchIndex = -1; + } } //-------------------------------------------------------------------------------------------------- @@ -113,6 +124,11 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& else if (type == CS_SIMULATION_WELL) { uiOrdering.add(&simulationWell); + updateWellCenterline(); + if (simulationWell() && m_wellBranchCenterlines.size() > 1) + { + uiOrdering.add(&branchIndex); + } } else { @@ -168,7 +184,19 @@ QList RimCrossSection::calculateValueOptions(const caf:: options.push_front(caf::PdmOptionItemInfo("None", QVariant::fromValue(caf::PdmPointer(NULL)))); } } + else if (fieldNeedingOptions == &branchIndex) + { + updateWellCenterline(); + + size_t branchCount = m_wellBranchCenterlines.size(); + + options.push_back(caf::PdmOptionItemInfo("All", -1)); + for (int bIdx = 0; bIdx < branchCount; ++bIdx) + { + options.push_back(caf::PdmOptionItemInfo(QString::number(bIdx + 1), QVariant::fromValue(bIdx))); + } + } return options; } @@ -221,8 +249,17 @@ std::vector< std::vector > RimCrossSection::polyLines() const { if (simulationWell()) { - std::vector< std::vector > pipeBranchesCellIds; - RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(simulationWell(), lines, pipeBranchesCellIds); + updateWellCenterline(); + + if (0 <= branchIndex && branchIndex < m_wellBranchCenterlines.size()) + { + lines.push_back(m_wellBranchCenterlines[branchIndex]); + } + + if (branchIndex == -1) + { + lines = m_wellBranchCenterlines; + } } } else @@ -258,3 +295,23 @@ RivCrossSectionPartMgr* RimCrossSection::crossSectionPartMgr() return m_crossSectionPartMgr.p(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::updateWellCenterline() const +{ + if (isActive() && type == CS_SIMULATION_WELL && simulationWell()) + { + if (m_wellBranchCenterlines.size() == 0) + { + std::vector< std::vector > pipeBranchesCellIds; + + RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(simulationWell(), m_wellBranchCenterlines, pipeBranchesCellIds); + } + } + else + { + m_wellBranchCenterlines.clear(); + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 3589e00fa2..d43dad5b4a 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -67,6 +67,7 @@ class RimCrossSection : public caf::PdmObject caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; + caf::PdmField branchIndex; std::vector< std::vector > polyLines() const; @@ -83,7 +84,9 @@ class RimCrossSection : public caf::PdmObject private: RimEclipseWellCollection* simulationWellCollection(); + void updateWellCenterline() const; private: cvf::ref m_crossSectionPartMgr; + mutable std::vector< std::vector > m_wellBranchCenterlines; }; From 941d117fbf9a0dbb626b720e4acffae896b755e5 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 08:15:28 +0100 Subject: [PATCH 137/290] [Fwk] Updated Cvf test application --- CMakeLists.txt | 1 + .../TapCvfSpecialization.cpp | 56 ------ .../cafTestApplication/TapCvfSpecialization.h | 41 ----- .../cafTestCvfApplication/CMakeLists.txt | 60 +++--- .../cafTests/cafTestCvfApplication/Main.cpp | 2 - .../cafTestCvfApplication/MainWindow.cpp | 171 ++++++------------ .../cafTestCvfApplication/MainWindow.h | 9 +- .../TapCvfSpecialization.cpp | 29 --- .../TapCvfSpecialization.h | 3 +- .../cafTestCvfApplication/TapProject.h | 2 +- 10 files changed, 98 insertions(+), 276 deletions(-) delete mode 100644 Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.cpp delete mode 100644 Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 85a8a82a38..43df9b07d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,7 @@ add_subdirectory(Fwk/AppFwk/cafUserInterface) add_subdirectory(Fwk/AppFwk/cafPdmCvf) add_subdirectory(Fwk/AppFwk/CommonCode) +add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication) add_subdirectory(Fwk/AppFwk/cafTensor) diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.cpp deleted file mode 100644 index 4b12fea0a1..0000000000 --- a/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "TapCvfSpecialization.h" -/* - -#include "MainWindow.h" -#include "WidgetLayoutTest.h" - -#include -#include -#include -#include -#include - - -#include "cafAppEnum.h" -#include "cafAppExecCommandManager.h" -#include "cafCommandFeaturesCore.h" -#include "cafCommandFeatureManager.h" -#include "cafPdmDocument.h" -#include "cafPdmObject.h" -#include "cafPdmUiFilePathEditor.h" -#include "cafPdmUiListEditor.h" -#include "cafPdmUiPropertyView.h" -#include "cafPdmUiTableView.h" -#include "cafPdmUiTextEditor.h" -#include "cafPdmUiTreeView.h" -#include "cafPdmReferenceHelper.h" -#include "cafSelectionManager.h" -#include "cafUiTreeModelPdm.h" -#include "cafPdmProxyValueField.h" -#include "cafPdmPtrField.h" -*/ - -CAF_PDM_SOURCE_INIT(TapCvfSpecialization, "TapCvfSpecialization"); - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TapCvfSpecialization::TapCvfSpecialization() -{ - CAF_PDM_InitObject("Test Object for type specializations", "", "", ""); - -/* - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Toggle Field", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Text", "", "Text tooltip", "This is a place you can enter a small integer value if you want"); - - m_proxyDoubleField.registerSetMethod(this, &SmallDemoPdmObject::setDoubleMember); - m_proxyDoubleField.registerGetMethod(this, &SmallDemoPdmObject::doubleMember); - CAF_PDM_InitFieldNoDefault(&m_proxyDoubleField, "ProxyDouble", "Proxy Double", "", "", ""); - - m_proxyDoubleField = 0; - if (!(m_proxyDoubleField == 3)) { std::cout << "Double is not 3 " << std::endl; } -*/ -} diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.h b/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.h deleted file mode 100644 index c2c7bc9cbe..0000000000 --- a/Fwk/AppFwk/cafTests/cafTestApplication/TapCvfSpecialization.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - - -#include "..\LibCore\cvfBase.h" -#include "..\LibCore\cvfColor3.h" -#include "..\LibCore\cvfVector3.h" -#include "..\LibCore\cvfMatrix4.h" - -#include "cafPdmObject.h" -#include "cafPdmField.h" - - - -class TapCvfSpecialization : public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - - TapCvfSpecialization(); - - caf::PdmField m_colorField; - caf::PdmField m_vectorField; - caf::PdmField m_matrixField; - -/* - virtual caf::PdmFieldHandle* objectToggleField() - { - return &m_toggleField; - } - - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) - { - if (changedField == &m_toggleField) - { - std::cout << "Toggle Field changed" << std::endl; - } - } -*/ - -}; - diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt b/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt index 2497678191..5aaa740f70 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt @@ -6,6 +6,9 @@ include (${QT_USE_FILE}) project ( cafTestCvfApplication ) + +option(USE_COMMAND_FRAMEWORK "Use Caf Command Framework" ON) + # Qt MOC set ( QT_MOC_HEADERS MainWindow.h @@ -27,32 +30,39 @@ qt4_add_resources( QRC_FILES_CPP ) include_directories ( - ${LibCore_SOURCE_DIR} + ${LibCore_SOURCE_DIR} ${LibGeometry_SOURCE_DIR} ${LibGuiQt_SOURCE_DIR} ${LibRender_SOURCE_DIR} ${LibViewing_SOURCE_DIR} + + ${cafProjectDataModel_SOURCE_DIR} + ${cafUserInterface_SOURCE_DIR} +) + +if (USE_COMMAND_FRAMEWORK) + include_directories ( + ${cafCommand_SOURCE_DIR} + ) + ADD_DEFINITIONS(-DTAP_USE_COMMAND_FRAMEWORK) +endif(USE_COMMAND_FRAMEWORK) - ${cafPdmCore_SOURCE_DIR} + +include_directories ( + ${cafPdmCore_SOURCE_DIR} ${cafPdmUiCore_SOURCE_DIR} ${cafPdmXml_SOURCE_DIR} - ${cafProjectDataModel_SOURCE_DIR} - - ${cafCommand_SOURCE_DIR} -# ${cafViewer_SOURCE_DIR} - ${cafUserInterface_SOURCE_DIR} - ${cafPdmCvf_SOURCE_DIR} -# ${CommonCode_SOURCE_DIR} - + + ${cafPdmCvf_SOURCE_DIR} ) set( PROJECT_FILES Main.cpp MainWindow.cpp WidgetLayoutTest.cpp - - TapCvfSpecialization.cpp - TapProject.cpp + + TapCvfSpecialization.cpp + TapProject.cpp ) @@ -63,21 +73,23 @@ add_executable ( ${PROJECT_NAME} ${QRC_FILES_CPP} ) -target_link_libraries ( ${PROJECT_NAME} - - LibCore - - cafPdmCore - cafPdmUiCore +set (TAP_LINK_LIBRARIES + cafUserInterface cafPdmXml - cafProjectDataModel + cafPdmCvf + ${QT_LIBRARIES} + ) - cafCommand - cafUserInterface +if (USE_COMMAND_FRAMEWORK) + set (TAP_LINK_LIBRARIES + ${TAP_LINK_LIBRARIES} + cafCommand + ) +endif(USE_COMMAND_FRAMEWORK) - cafPdmCvf - ${QT_LIBRARIES} +target_link_libraries ( ${PROJECT_NAME} + ${TAP_LINK_LIBRARIES} ) source_group("" FILES ${PROJECT_FILES}) diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/Main.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/Main.cpp index 8151364084..5fe2f4f22c 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/Main.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/Main.cpp @@ -3,8 +3,6 @@ #include -#include "cafPdmFieldCvfColor.h" - int main(int argc, char *argv[]) { QApplication app(argc, argv); diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp index e249c45eee..1070ca1279 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp @@ -12,31 +12,36 @@ #include "cafAppEnum.h" -#include "cafAppExecCommandManager.h" -#include "cafCommandFeaturesCore.h" -#include "cafCommandFeatureManager.h" -#include "cafPdmDocument.h" + +#ifdef TAP_USE_COMMAND_FRAMEWORK +#include "cafCmdExecCommandManager.h" +#include "cafCmdSelectionHelper.h" +#include "cafCmdFeatureManager.h" +#endif + #include "cafPdmObject.h" +#include "cafPdmObjectGroup.h" +#include "cafPdmProxyValueField.h" +#include "cafPdmPtrField.h" +#include "cafPdmReferenceHelper.h" #include "cafPdmUiFilePathEditor.h" #include "cafPdmUiListEditor.h" #include "cafPdmUiPropertyView.h" #include "cafPdmUiTableView.h" #include "cafPdmUiTextEditor.h" #include "cafPdmUiTreeView.h" -#include "cafPdmReferenceHelper.h" #include "cafSelectionManager.h" -#include "cafUiTreeModelPdm.h" -#include "cafPdmProxyValueField.h" -#include "cafPdmPtrField.h" -class DemoPdmObjectGroup: public caf::PdmObjectGroup + +class DemoPdmObjectGroup : public caf::PdmObjectCollection { CAF_PDM_HEADER_INIT; public: DemoPdmObjectGroup() { + objects.uiCapability()->setUiHidden(true); } }; @@ -176,12 +181,12 @@ class SmallDemoPdmObjectA: public caf::PdmObject { if (uiObject->userDescriptionField()) { - caf::PdmUiFieldHandle* uiFieldHandle = caf::uiField(uiObject->userDescriptionField()); - if (uiFieldHandle) - { - userDesc = uiFieldHandle->uiValue().toString(); - } - } + caf::PdmUiFieldHandle* uiFieldHandle = uiObject->userDescriptionField()->uiCapability(); + if (uiFieldHandle) + { + userDesc = uiFieldHandle->uiValue().toString(); + } + } options.push_back(caf::PdmOptionItemInfo(uiObject->uiName() + "(" + userDesc + ")", QVariant::fromValue(caf::PdmPointer(objects[i])))); } @@ -363,11 +368,6 @@ MainWindow::MainWindow() // Register default command features (add/delete item in list) - caf::AppExecCommandManager::instance()->enableUndoStack(true); - - m_treeView = NULL; - m_treeModelPdm = NULL; - createActions(); createDockPanels(); @@ -377,7 +377,11 @@ MainWindow::MainWindow() sm_mainWindowInstance = this; caf::SelectionManager::instance()->setPdmRootObject(m_testRoot); - undoView->setStack(caf::AppExecCommandManager::instance()->undoStack()); +#ifdef TAP_USE_COMMAND_FRAMEWORK + caf::CmdExecCommandManager::instance()->enableUndoCommandSystem(true); + undoView->setStack(caf::CmdExecCommandManager::instance()->undoStack()); +#endif + } //-------------------------------------------------------------------------------------------------- @@ -386,17 +390,7 @@ MainWindow::MainWindow() void MainWindow::createDockPanels() { { - QDockWidget* dockWidget = new QDockWidget("Workspace", this); - dockWidget->setObjectName("dockWidget"); - dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - - m_treeView = new QTreeView(dockWidget); - dockWidget->setWidget(m_treeView); - - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); - } - { - QDockWidget* dockWidget = new QDockWidget("PdmTreeView", this); + QDockWidget* dockWidget = new QDockWidget("PdmTreeView - controls property view", this); dockWidget->setObjectName("dockWidget"); dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); @@ -405,28 +399,29 @@ void MainWindow::createDockPanels() addDockWidget(Qt::LeftDockWidgetArea, dockWidget); } - /* + { - QDockWidget* dockWidget = new QDockWidget("WidgetLayoutTest", this); + QDockWidget* dockWidget = new QDockWidget("cafPropertyView", this); dockWidget->setObjectName("dockWidget"); dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - WidgetLayoutTest* widgetLayoutTest = new WidgetLayoutTest(dockWidget); - dockWidget->setWidget(widgetLayoutTest); + m_pdmUiPropertyView = new caf::PdmUiPropertyView(dockWidget); + dockWidget->setWidget(m_pdmUiPropertyView); addDockWidget(Qt::LeftDockWidgetArea, dockWidget); } - */ { - QDockWidget* dockWidget = new QDockWidget("cafPropertyView", this); + QDockWidget* dockWidget = new QDockWidget("PdmTreeView2 - controls table view", this); dockWidget->setObjectName("dockWidget"); dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - m_pdmUiPropertyView = new caf::PdmUiPropertyView(dockWidget); - dockWidget->setWidget(m_pdmUiPropertyView); + m_pdmUiTreeView2 = new caf::PdmUiTreeView(dockWidget); + m_pdmUiTreeView2->enableDefaultContextMenu(true); + m_pdmUiTreeView2->enableSelectionManagerUpdating(true); + dockWidget->setWidget(m_pdmUiTreeView2); - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + addDockWidget(Qt::RightDockWidgetArea, dockWidget); } { @@ -440,20 +435,9 @@ void MainWindow::createDockPanels() dockWidget->setWidget(m_pdmUiTableView); - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + addDockWidget(Qt::RightDockWidgetArea, dockWidget); } - { - QDockWidget* dockWidget = new QDockWidget("PdmTreeView2", this); - dockWidget->setObjectName("dockWidget"); - dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); - - m_pdmUiTreeView2 = new caf::PdmUiTreeView(dockWidget); - m_pdmUiTreeView2->enableDefaultContextMenu(true); - dockWidget->setWidget(m_pdmUiTreeView2); - - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); - } { QDockWidget* dockWidget = new QDockWidget("Undo stack", this); @@ -463,7 +447,7 @@ void MainWindow::createDockPanels() undoView = new QUndoView(this); dockWidget->setWidget(undoView); - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + addDockWidget(Qt::RightDockWidgetArea, dockWidget); } } @@ -476,13 +460,13 @@ void MainWindow::buildTestModel() m_testRoot = new DemoPdmObjectGroup; DemoPdmObject* demoObject = new DemoPdmObject; - m_testRoot->addObject(demoObject); + m_testRoot->objects.push_back(demoObject); SmallDemoPdmObject* smallObj1 = new SmallDemoPdmObject; - m_testRoot->addObject(smallObj1); + m_testRoot->objects.push_back(smallObj1); SmallDemoPdmObjectA* smallObj2 = new SmallDemoPdmObjectA; - m_testRoot->addObject(smallObj2); + m_testRoot->objects.push_back(smallObj2); DemoPdmObject* demoObj2 = new DemoPdmObject; @@ -512,26 +496,6 @@ void MainWindow::buildTestModel() //-------------------------------------------------------------------------------------------------- void MainWindow::setPdmRoot(caf::PdmObjectHandle* pdmRoot) { - caf::PdmUiTreeItem* treeItemRoot = caf::UiTreeItemBuilderPdm::buildViewItems(NULL, 0, pdmRoot); - - if (!m_treeModelPdm) - { - m_treeModelPdm = new caf::UiTreeModelPdm(this); - } - - m_treeModelPdm->setTreeItemRoot(treeItemRoot); - - assert(m_treeView); - m_treeView->setModel(m_treeModelPdm); - - if (treeItemRoot) - { - if (m_treeView->selectionModel()) - { - connect(m_treeView->selectionModel(), SIGNAL(selectionChanged( const QItemSelection & , const QItemSelection & )), SLOT(slotSelectionChanged( const QItemSelection & , const QItemSelection & ))); - } - } - caf::PdmUiObjectHandle* uiObject = uiObj(pdmRoot); if (uiObject) { @@ -548,7 +512,7 @@ void MainWindow::setPdmRoot(caf::PdmObjectHandle* pdmRoot) if (fields.size()) { caf::PdmFieldHandle* field = fields[0]; - caf::PdmUiFieldHandle* uiFieldHandle = uiField(field); + caf::PdmUiFieldHandle* uiFieldHandle = field->uiCapability(); if (uiFieldHandle) { m_pdmUiTreeView2->setPdmItem(uiFieldHandle); @@ -569,6 +533,10 @@ void MainWindow::setPdmRoot(caf::PdmObjectHandle* pdmRoot) //-------------------------------------------------------------------------------------------------- MainWindow::~MainWindow() { + m_pdmUiTreeView->setPdmItem(NULL); + m_pdmUiTreeView2->setPdmItem(NULL); + m_pdmUiPropertyView->showProperties(NULL); + m_pdmUiTableView->setListField(NULL); } //-------------------------------------------------------------------------------------------------- @@ -576,15 +544,9 @@ MainWindow::~MainWindow() //-------------------------------------------------------------------------------------------------- void MainWindow::releaseTestData() { - m_treeView->setModel(NULL); - if (m_treeModelPdm) - { - delete m_treeModelPdm; - } - if (m_testRoot) { - m_testRoot->deleteObjects(); + m_testRoot->objects.deleteAllChildObjects(); delete m_testRoot; } } @@ -625,7 +587,7 @@ void MainWindow::createActions() void MainWindow::slotInsert() { std::vector selection; - m_pdmUiTreeView->selectedObjects(selection); + m_pdmUiTreeView->selectedUiItems(selection); for (size_t i = 0; i < selection.size(); ++i) { @@ -661,7 +623,7 @@ void MainWindow::slotInsert() void MainWindow::slotRemove() { std::vector selection; - m_pdmUiTreeView->selectedObjects(selection); + m_pdmUiTreeView->selectedUiItems(selection); for (size_t i = 0; i < selection.size(); ++i) { @@ -678,11 +640,7 @@ void MainWindow::slotRemove() delete obj; // Update editors - caf::PdmUiFieldHandle* uiFieldHandle = uiField(field); - if (uiFieldHandle) - { - uiFieldHandle->updateConnectedEditors(); - } + field->uiCapability()->updateConnectedEditors(); break; } @@ -697,40 +655,20 @@ void MainWindow::slotRemoveAll() } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void MainWindow::slotSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected ) -{ - if (selected.indexes().size() == 1) - { - QModelIndex mi = selected.indexes()[0]; - caf::PdmUiTreeItem* treeItem = m_treeModelPdm->getTreeItemFromIndex(mi); - if (treeItem && treeItem->dataObject()) - { - m_pdmUiPropertyView->showProperties(treeItem->dataObject()); - } - } - else - { - m_pdmUiPropertyView->showProperties(NULL); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void MainWindow::slotSimpleSelectionChanged() { std::vector selection; - m_pdmUiTreeView->selectedObjects(selection); + m_pdmUiTreeView->selectedUiItems(selection); caf::PdmObjectHandle* obj = NULL; caf::PdmChildArrayFieldHandle* listField = NULL; if (selection.size()) { caf::PdmUiObjectHandle* pdmUiObj = dynamic_cast( selection[0] ); - if (pdmUiObj) obj = pdmUiObj->owner(); + if (pdmUiObj) obj = pdmUiObj->objectHandle(); } m_pdmUiPropertyView->showProperties(obj); @@ -742,7 +680,7 @@ void MainWindow::slotSimpleSelectionChanged() void MainWindow::slotShowTableView() { std::vector selection; - m_pdmUiTreeView2->selectedObjects(selection); + m_pdmUiTreeView2->selectedUiItems(selection); caf::PdmObjectHandle* obj = NULL; caf::PdmChildArrayFieldHandle* listField = NULL; @@ -764,8 +702,9 @@ void MainWindow::slotShowTableView() } m_pdmUiTableView->setListField(listField); + if (listField) { - listField->capability()->updateConnectedEditors(); + listField->uiCapability()->updateConnectedEditors(); } } diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h index f1512ec64d..b9728a6824 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h @@ -10,7 +10,7 @@ class QUndoView; namespace caf { - class PdmObjectGroup; + class PdmObjectCollection; class PdmObjectHandle; class UiTreeModelPdm; class PdmUiPropertyView; @@ -43,7 +43,7 @@ private slots: void slotInsert(); void slotRemove(); void slotRemoveAll(); - void slotSelectionChanged(const QItemSelection &, const QItemSelection & ); + void slotSimpleSelectionChanged(); void slotShowTableView(); @@ -52,15 +52,12 @@ private slots: static MainWindow* sm_mainWindowInstance; private: - QTreeView* m_treeView; QUndoView* undoView; - caf::UiTreeModelPdm* m_treeModelPdm; caf::PdmUiTreeView* m_pdmUiTreeView; caf::PdmUiTreeView* m_pdmUiTreeView2; caf::PdmUiPropertyView* m_pdmUiPropertyView; caf::PdmUiTableView* m_pdmUiTableView; - caf::PdmObjectGroup* m_testRoot; - + caf::PdmObjectCollection* m_testRoot; }; diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index b3fe87f5cf..0043f0ac58 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -1,34 +1,5 @@ #include "TapCvfSpecialization.h" -/* -#include "MainWindow.h" -#include "WidgetLayoutTest.h" - -#include -#include -#include -#include -#include - - -#include "cafAppEnum.h" -#include "cafAppExecCommandManager.h" -#include "cafCommandFeaturesCore.h" -#include "cafCommandFeatureManager.h" -#include "cafPdmDocument.h" -#include "cafPdmObject.h" -#include "cafPdmUiFilePathEditor.h" -#include "cafPdmUiListEditor.h" -#include "cafPdmUiPropertyView.h" -#include "cafPdmUiTableView.h" -#include "cafPdmUiTextEditor.h" -#include "cafPdmUiTreeView.h" -#include "cafPdmReferenceHelper.h" -#include "cafSelectionManager.h" -#include "cafUiTreeModelPdm.h" -#include "cafPdmProxyValueField.h" -#include "cafPdmPtrField.h" -*/ CAF_PDM_SOURCE_INIT(TapCvfSpecialization, "TapCvfSpecialization"); diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h index 7114b7c361..d9ca7aa07f 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h @@ -13,7 +13,7 @@ #include "cafPdmFieldCvfVec3d.h" #include "cafPdmFieldCvfMat4d.h" - +#include class TapCvfSpecialization : public caf::PdmObject @@ -29,5 +29,6 @@ class TapCvfSpecialization : public caf::PdmObject caf::PdmField m_vectorField; caf::PdmField m_matrixField; + //caf::PdmField< std::vector< cvf::Vec3d> > m_vecArrayField; }; diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h index 4116f343ee..9ce03e4c9b 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h @@ -1,7 +1,7 @@ #pragma once #include "cafPdmDocument.h" - +#include "cafPdmChildArrayField.h" class TapProject : public caf::PdmDocument From 6cecdf7fc31fb07e4490eee565177fcb13bbd386 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 10:06:48 +0100 Subject: [PATCH 138/290] [Fwk] Added new top level cmakefile for both AppFwk and VizFwk --- .../CMakeLists.txt | 8 +- .../cafProjectDataModel_UnitTests/Parent.cpp | 4 +- .../gtest/cvftestUtils.h | 43 + .../gtest/gtest-all.cpp | 8510 ++++++++ .../gtest/gtest.h | 18007 ++++++++++++++++ .../TapCvfSpecialization.cpp | 18 +- .../TapCvfSpecialization.h | 9 +- Fwk/CMakeLists.txt | 41 + 8 files changed, 26619 insertions(+), 21 deletions(-) create mode 100644 Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h create mode 100644 Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp create mode 100644 Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h create mode 100644 Fwk/CMakeLists.txt diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt index e6034e0d79..03412c98d8 100644 --- a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt @@ -6,14 +6,16 @@ include (${QT_USE_FILE}) project ( cafProjectDataModel_UnitTests ) include_directories ( - ${CMAKE_SOURCE_DIR}/cafProjectDataModel - ${CMAKE_SOURCE_DIR}/cafTests + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. ) include_directories ( ${cafPdmCore_SOURCE_DIR} ${cafPdmUiCore_SOURCE_DIR} ${cafPdmXml_SOURCE_DIR} + + ${cafProjectDataModel_SOURCE_DIR} ) set( PROJECT_FILES @@ -28,7 +30,7 @@ set( PROJECT_FILES # add the executable add_executable (${PROJECT_NAME} ${PROJECT_FILES} - ${CMAKE_SOURCE_DIR}/cafTests/gtest/gtest-all.cpp + gtest/gtest-all.cpp ) message(${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp index 16892e55ff..097413e073 100644 --- a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp @@ -1,6 +1,8 @@ #include "Child.h" #include "Parent.h" +#include "gtest/gtest.h" + CAF_PDM_SOURCE_INIT(Parent, "Parent"); @@ -24,8 +26,6 @@ Parent::~Parent() } } -#include - TEST(IncludeTest, Basic) { Parent* p = new Parent; diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h new file mode 100644 index 0000000000..c2a5a960d6 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h @@ -0,0 +1,43 @@ + + + +namespace cvftest { + + +//================================================================================================== +// +// +//================================================================================================== +class Utils +{ +public: + static cvf::String getTestDataDir(const cvf::String& unitTestFolder) + { +#ifdef WIN32 + std::string exe = std::string(testing::internal::GetArgvs()[0]); +#else + std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString()); + std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]); +#endif + std::string testPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("TestData/"); + + return testPath; + } + + static cvf::String getGLSLDir(const cvf::String& unitTestFolder) + { +#ifdef WIN32 + std::string exe = std::string(testing::internal::GetArgvs()[0]); +#else + std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString()); + std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]); +#endif + std::string glslPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("../LibRender/glsl/"); + + return glslPath; + } +}; + + +} + diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp new file mode 100644 index 0000000000..644479a63c --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp @@ -0,0 +1,8510 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include + +// The following lines pull in the real gtest *.cc files. +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const char* substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const String substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY_ 1 + +#include +#include +#include +// Declares vsnprintf(). This header is not available on Windows. +#include +#include +#include +#include +#include +#include + +#elif GTEST_OS_SYMBIAN +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT + +#elif GTEST_OS_ZOS +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +#include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +#include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT +#endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT +#include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +#include +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +#error "gtest-internal-inl.h is part of Google Test's internal implementation." +#error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +#include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + + +#if GTEST_OS_WINDOWS +#include // For DWORD. +#endif // GTEST_OS_WINDOWS + + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + bool pretty_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + return static_cast(std::count_if(c.begin(), c.end(), predicate)); +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +class TestInfoImpl { + public: + TestInfoImpl(TestInfo* parent, const char* test_case_name, + const char* name, const char* test_case_comment, + const char* comment, TypeId fixture_class_id, + internal::TestFactoryBase* factory); + ~TestInfoImpl(); + + // Returns true if this test should run. + bool should_run() const { return should_run_; } + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Returns true if this test is disabled. Disabled tests are not run. + bool is_disabled() const { return is_disabled_; } + + // Sets the is_disabled member. + void set_is_disabled(bool is) { is_disabled_ = is; } + + // Returns true if this test matches the filter specified by the user. + bool matches_filter() const { return matches_filter_; } + + // Sets the matches_filter member. + void set_matches_filter(bool matches) { matches_filter_ = matches; } + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the test case comment. + const char* test_case_comment() const { return test_case_comment_.c_str(); } + + // Returns the test comment. + const char* comment() const { return comment_.c_str(); } + + // Returns the ID of the test fixture class. + TypeId fixture_class_id() const { return fixture_class_id_; } + + // Returns the test result. + TestResult* result() { return &result_; } + const TestResult* result() const { return &result_; } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + // Clears the test result. + void ClearResult() { result_.Clear(); } + + // Clears the test result in the given TestInfo object. + static void ClearTestResult(TestInfo * test_info) { + test_info->impl()->ClearResult(); + } + + private: + // These fields are immutable properties of the test. + TestInfo* const parent_; // The owner of this object + const String test_case_name_; // Test case name + const String name_; // Test name + const String test_case_comment_; // Test case comment + const String comment_; // Test comment + const TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo * test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->test_case_comment(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has + // guards protecting from registering the tests more then once. + // If value-parameterized tests are disabled, RegisterParameterizedTests + // is present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns 0 if all tests are successful, or 1 otherwise. If any + // exception is thrown during a test on Windows, this test is + // considered to be failed, but the rest of the tests will still be + // run. (We disable exceptions on Linux and Mac OS X, so the issue + // doesn't apply there.) + int RunAllTests(); + + // Clears the results of all tests, including the ad hoc test. + void ClearResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + private: + friend class ::testing::UnitTest; + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsDigit(char ch); +GTEST_API_ bool IsPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsWhiteSpace(char ch); +GTEST_API_ bool IsWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastErrnoDescription(); + +#if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +#endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !isdigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. +#if GTEST_OS_WINDOWS && !defined(__GNUC__) + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); +#else + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); +#endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +#define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", false), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_OS_WINDOWS +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle an exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception. + return (GTEST_FLAG(catch_exceptions) && + exception_code != EXCEPTION_BREAKPOINT) ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_OS_WINDOWS + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const char* substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure(msg); + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + msg << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + if (strstr(r.message(), substr) == NULL) { + msg << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const char* substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; +#ifdef _MSC_VER + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +#pragma warning(pop) // Restores the warning state. +#else + _ftime64(&now); +#endif // _MSC_VER + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +#error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +namespace internal { + +// Formats a value to be used in a failure message. + +// For a char value, we print it as a C++ char literal and as an +// unsigned integer (both in decimal and in hexadecimal). +String FormatForFailureMessage(char ch) { + const unsigned int ch_as_uint = ch; + // A String object cannot contain '\0', so we print "\\0" when ch is + // '\0'. + return String::Format("'%s' (%u, 0x%X)", + ch ? String::Format("%c", ch).c_str() : "\\0", + ch_as_uint, ch_as_uint); +} + +// For a wchar_t value, we print it as a C++ wchar_t literal and as an +// unsigned integer (both in decimal and in hexidecimal). +String FormatForFailureMessage(wchar_t wchar) { + // The C++ standard doesn't specify the exact size of the wchar_t + // type. It just says that it shall have the same size as another + // integral type, called its underlying type. + // + // Therefore, in order to print a wchar_t value in the numeric form, + // we first convert it to the largest integral type (UInt64) and + // then print the converted value. + // + // We use streaming to print the value as "%llu" doesn't work + // correctly with MSVC 7.1. + const UInt64 wchar_as_uint64 = wchar; + Message msg; + // A String object cannot contain '\0', so we print "\\0" when wchar is + // L'\0'. + char buffer[32]; // CodePointToUtf8 requires a buffer that big. + msg << "L'" + << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") + << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) + << wchar_as_uint64 << ")"; + return msg.GetString(); +} + +} // namespace internal + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new internal::String(*other.message_) : + static_cast(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure(msg); +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + Message msg; + msg << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; + return AssertionFailure(msg); +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + StrStream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + StrStream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + Message msg; + msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StrStreamToString(&val1_ss) << " vs " + << StrStreamToString(&val2_ss); + + return AssertionFailure(msg); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + Message msg;\ + msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return AssertionFailure(msg);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure( + Message() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""); +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; +#else + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && isspace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } +#endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + Message msg; + msg << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; + + return ::testing::AssertionFailure(msg); +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + StrStream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StrStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); + return AssertionFailure(msg); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX + return wcscasecmp(lhs, rhs) == 0; +#else + // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes + // may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a StrStream to a String, converting NUL +// bytes to "\\0" along the way. +String StrStreamToString(StrStream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper StrStream to do this transformation + // because String doesn't support push_back(). + StrStream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +#if GTEST_OS_WINDOWS +// We are on Windows. + +// Adds an "exception thrown" fatal failure to the current test. +static void AddExceptionThrownFailure(DWORD exception_code, + const char* location) { + Message message; + message << "Exception thrown with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " in " << location << "."; + + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + message.GetString()); +} + +#endif // GTEST_OS_WINDOWS + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const internal::TestInfoImpl* const first_test_info = + test_case->test_info_list()[0]->impl(); + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const internal::TestInfoImpl* const this_test_info = + impl->current_test_info()->impl(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + SetUp(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); + } + + // We will run the test only if SetUp() had no fatal failure. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TestBody(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "the test body"); + } + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TearDown(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); + } + +#else // We are on a compiler or platform that doesn't support SEH. + impl->os_stack_trace_getter()->UponLeavingGTest(); + SetUp(); + + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + TestBody(); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + TearDown(); +#endif // GTEST_HAS_SEH +} + + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object via impl_. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) { + impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, + a_test_case_comment, a_comment, + fixture_class_id, factory); +} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { + delete impl_; +} + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// test_case_comment: a comment on the test case that will be included in +// the test output +// comment: a comment on the test that will be included in the +// test output +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, test_case_comment, comment, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +// Returns the test case name. +const char* TestInfo::test_case_name() const { + return impl_->test_case_name(); +} + +// Returns the test name. +const char* TestInfo::name() const { + return impl_->name(); +} + +// Returns the test case comment. +const char* TestInfo::test_case_comment() const { + return impl_->test_case_comment(); +} + +// Returns the test comment. +const char* TestInfo::comment() const { + return impl_->comment(); +} + +// Returns true if this test should run. +bool TestInfo::should_run() const { return impl_->should_run(); } + +// Returns true if this test matches the user-specified filter. +bool TestInfo::matches_filter() const { return impl_->matches_filter(); } + +// Returns the result of the test. +const TestResult* TestInfo::result() const { return impl_->result(); } + +// Increments the number of death tests encountered in this test so +// far. +int TestInfo::increment_death_test_count() { + return impl_->result()->increment_death_test_count(); +} + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfoImpl::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(parent_); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*parent_); + + const TimeInMillis start = GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + Test* test = NULL; + + __try { + // Creates the test object. + test = factory_->CreateTest(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), + "the test fixture's constructor"); + return; + } +#else // We are on a compiler or platform that doesn't support SEH. + + // TODO(wan): If test->Run() throws, test won't be deleted. This is + // not a problem now as we don't use exceptions. If we were to + // enable exceptions, we should revise the following to be + // exception-safe. + + // Creates the test object. + Test* test = factory_->CreateTest(); +#endif // GTEST_HAS_SEH + + // Runs the test only if the constructor of the test fixture didn't + // generate a fatal failure. + if (!Test::HasFatalFailure()) { + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + delete test; + test = NULL; + + result_.set_elapsed_time(GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*parent_); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +} // namespace internal + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + comment_(a_comment), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + set_up_tc_(); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->impl()->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + tear_down_tc_(); + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); +} + +// Returns true iff test passed. +bool TestCase::TestPassed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Passed(); +} + +// Returns true iff test failed. +bool TestCase::TestFailed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Failed(); +} + +// Returns true iff test is disabled. +bool TestCase::TestDisabled(const TestInfo * test_info) { + return test_info->impl()->is_disabled(); +} + +// Returns true if the given test should run. +bool TestCase::ShouldRunTest(const TestInfo *test_info) { + return test_info->impl()->should_run(); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + } + + return "Unknown result type"; +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %s of %s.\n", + internal::posix::GetEnv(kTestShardIndex), + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_case.comment()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_info.comment()); + } + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + if (test_case.comment()[0] != '\0' || + test_info.comment()[0] != '\0') { + printf(", where %s", test_case.comment()); + if (test_case.comment()[0] != '\0' && + test_info.comment()[0] != '\0') { + printf(" and "); + } + } + printf("%s\n", test_info.comment()); + } + } +} + + void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static String RemoveInvalidXmlCharacters(const char* str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { + char* const output = new char[strlen(str) + 1]; + char* appender = output; + for (char ch = *str; ch != '\0'; ch = *++str) + if (IsValidXmlCharacter(ch)) + *appender++ = ch; + *appender = '\0'; + + String ret_value(output); + delete[] output; + return ret_value; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const String message = RemoveInvalidXmlCharacters(String::Format( + "%s:%d\n%s", + part.file_name(), part.line_number(), + part.message()).c_str()); + OutputXmlCDataSection(stream, message.c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + StrStream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StrStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +#if GTEST_HAS_EXCEPTIONS +// A failed Google Test assertion will throw an exception of this type +// when exceptions are enabled. We derive it from std::runtime_error, +// which is for errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected.. + if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { +#if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +#endif // !GTEST_OS_WINDOWS_MOBILE + +#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +#endif + +#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +#endif + } + + __try { + return impl_->RunAllTests(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); + fflush(stdout); + return 1; + } + +#else // We are on a compiler or platform that doesn't support SEH. + + return impl_->RunAllTests(); +#endif // GTEST_HAS_SEH +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. +#if GTEST_HAS_DEATH_TEST + elapsed_time_(0), + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory) { +#else + elapsed_time_(0) { +#endif // GTEST_HAS_DEATH_TEST + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns 0 if all tests are successful, or 1 otherwise. If any +// exception is thrown during a test on Windows, this test is +// considered to be failed, but the rest of the tests will still be +// run. (We disable exceptions on Linux and Mac OS X, so the issue +// doesn't apply there.) +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +int UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return 1; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return 0; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return 0; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + ClearResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + // Returns 0 if all tests passed, or 1 other wise. + return failed ? 1 : 0; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->impl()->set_is_disabled(is_disabled); + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->impl()->set_matches_filter(matches_filter); + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->impl()->set_should_run(is_selected); + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter()) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + current_test_info_->impl()->result() : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// TestInfoImpl constructor. The new instance assumes ownership of the test +// factory object. +TestInfoImpl::TestInfoImpl(TestInfo* parent, + const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, + TypeId a_fixture_class_id, + internal::TestFactoryBase* factory) : + parent_(parent), + test_case_name_(String(a_test_case_name)), + name_(String(a_name)), + test_case_comment_(String(a_test_case_comment)), + comment_(String(a_comment)), + fixture_class_id_(a_fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory) { +} + +// TestInfoImpl destructor. +TestInfoImpl::~TestInfoImpl() { + delete factory_; +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable +// code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +#if GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" +" Suppress pop-ups caused by exceptions.\n" +#endif // GTEST_OS_WINDOWS +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + + +#if GTEST_HAS_DEATH_TEST + +#if GTEST_OS_MAC +#include +#endif // GTEST_OS_MAC + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS +#include +#else +#include +#include +#endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +#if GTEST_OS_WINDOWS + return exit_status == exit_code_; +#else + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; +#endif // GTEST_OS_WINDOWS +} + +#if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +#endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; +#if GTEST_OS_WINDOWS + m << "Exited with exit status " << exit_code; +#else + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +#ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +#endif +#endif // GTEST_OS_WINDOWS + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +#if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +#endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test +// can conclude. DIED means that the process died while executing the +// test code; LIVED means that process lived beyond the end of the test +// code; and RETURNED means that the test statement attempted a "return," +// which is not allowed. IN_PROGRESS means the test has not yet +// concluded. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +#define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, or RETURNED. The death test fails +// in the latter two cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg: " << error_message; + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg: " << error_message; + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg: " << error_message; + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n"; + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +#if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* statement, + const RE* regex, + const char* file, + int line) + : DeathTestImpl(statement, regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status; + GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) + != FALSE); + child_handle_.Reset(); + set_status(static_cast(status)); + return this->status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +#else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +#if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +#else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +#endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +#if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +#else + const bool use_fork = true; +#endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +#endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +#if GTEST_OS_WINDOWS + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } +#else + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } +#endif // GTEST_OS_WINDOWS + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +#if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +#endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +#if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +#else + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } +#endif // GTEST_OS_WINDOWS + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + + +#include + +#if GTEST_OS_WINDOWS_MOBILE +#include +#elif GTEST_OS_WINDOWS +#include +#include +#elif GTEST_OS_SYMBIAN +// Symbian OpenC has PATH_MAX in sys/syslimits.h +#include +#else +#include +#include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +#define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +#define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +#define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +#else +const char kCurrentDirectoryString[] = ".\\"; +#endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +#include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +#include +#include +#else +#include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +#include +#include +#include +#endif // GTEST_OS_MAC + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsDigit(ch); + case 'D': return !IsDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsWhiteSpace(ch); + case 'S': return !IsWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsWordChar(ch); + case 'W': return !IsWordChar(ch); + } + return IsPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION_ + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { +#if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +#else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +#endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION_ + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << static_cast(toupper(full_flag.c_str()[i])); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (isspace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h new file mode 100644 index 0000000000..c0a1902e25 --- /dev/null +++ b/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h @@ -0,0 +1,18007 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_LINUX - Linux +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax. Not available on +// Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // For ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +#include +#endif // !_WIN32_WCE + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +#define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +#define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +#define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +#define GTEST_OS_WINDOWS 1 +#ifdef _WIN32_WCE +#define GTEST_OS_WINDOWS_MOBILE 1 +#elif defined(__MINGW__) || defined(__MINGW32__) +#define GTEST_OS_WINDOWS_MINGW 1 +#else +#define GTEST_OS_WINDOWS_DESKTOP 1 +#endif // _WIN32_WCE +#elif defined __APPLE__ +#define GTEST_OS_MAC 1 +#elif defined __linux__ +#define GTEST_OS_LINUX 1 +#elif defined __MVS__ +#define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +#define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +#define GTEST_OS_AIX 1 +#endif // __CYGWIN__ + +#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \ + GTEST_OS_SOLARIS || GTEST_OS_AIX + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +#if !GTEST_OS_WINDOWS_MOBILE +#include // NOLINT +#include // NOLINT +#endif + +// is not available on Windows. Use our own simple regex +// implementation instead. +#define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +#define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || + // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +#ifndef _HAS_EXCEPTIONS +#define _HAS_EXCEPTIONS 1 +#endif // _HAS_EXCEPTIONS +#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +#elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#else +// For other compilers, we assume exceptions are disabled to be +// conservative. +#define GTEST_HAS_EXCEPTIONS 0 +#endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +#define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +#error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +#define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.5 and below doesn't support ::std::wstring. +// Cygwin 1.7 might add wstring support; this should be updated when clear. +// Solaris' libc++ doesn't support it either. +#define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +#define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +#ifdef _MSC_VER + +#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +#ifdef __GXX_RTTI +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif // __GXX_RTTI + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +#ifdef __RTTI_ALL__ +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif + +#else + +// For all other compilers, we assume RTTI is enabled. +#define GTEST_HAS_RTTI 1 + +#endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +#include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) +#endif // GTEST_HAS_PTHREAD + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +// The user didn't tell us not to do it, so we assume it's OK. +#define GTEST_HAS_TR1_TUPLE 1 +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, GCC 4.0.0+ and MSVC +// 2010 are the only mainstream compilers that come with a TR1 tuple +// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by +// defining __GNUC__ and friends, but cannot compile GCC's tuple +// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB +// Feature Pack download, which we cannot assume the user has. +#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ + || _MSC_VER >= 1600 +#define GTEST_USE_OWN_TR1_TUPLE 0 +#else +#define GTEST_USE_OWN_TR1_TUPLE 1 +#endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +#if GTEST_USE_OWN_TR1_TUPLE +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { typedef T0 type; }; + +template +struct TupleElement { typedef T1 type; }; + +template +struct TupleElement { typedef T2 type; }; + +template +struct TupleElement { typedef T3 type; }; + +template +struct TupleElement { typedef T4 type; }; + +template +struct TupleElement { typedef T5 type; }; + +template +struct TupleElement { typedef T6 type; }; + +template +struct TupleElement { typedef T7 type; }; + +template +struct TupleElement { typedef T8 type; }; + +template +struct TupleElement { typedef T9 type; }; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { static const int value = 0; }; + +template +struct tuple_size { static const int value = 1; }; + +template +struct tuple_size { static const int value = 2; }; + +template +struct tuple_size { static const int value = 3; }; + +template +struct tuple_size { static const int value = 4; }; + +template +struct tuple_size { static const int value = 5; }; + +template +struct tuple_size { static const int value = 6; }; + +template +struct tuple_size { static const int value = 7; }; + +template +struct tuple_size { static const int value = 8; }; + +template +struct tuple_size { static const int value = 9; }; + +template +struct tuple_size { static const int value = 10; }; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +#ifdef BOOST_HAS_TR1_TUPLE +#undef BOOST_HAS_TR1_TUPLE +#endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +#include + +#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +#define _TR1_FUNCTIONAL 1 +#include +#undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +#else +#include // NOLINT +#endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +#else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +#include // NOLINT +#endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +#if GTEST_OS_LINUX && !defined(__ia64__) +#define GTEST_HAS_CLONE 1 +#else +#define GTEST_HAS_CLONE 0 +#endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#define GTEST_HAS_STREAM_REDIRECTION_ 1 +#endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX) +#define GTEST_HAS_DEATH_TEST 1 +#include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, and IBM Visual Age support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) +#define GTEST_HAS_TYPED_TEST 1 +#define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +#define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +#define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +#define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +#define GTEST_HAS_SEH 1 +#else +// Assume no SEH. +#define GTEST_HAS_SEH 0 +#endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +#if GTEST_LINKED_AS_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllimport) +#elif GTEST_CREATE_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllexport) +#endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +#define GTEST_API_ +#endif + +namespace testing { + +class Message; + +namespace internal { + +class String; + +typedef ::std::stringstream StrStream; + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of a string, as Google Test may be used + // where string is not available. We also do not use Google Test's own + // String type here, in order to simplify dependencies between the + // files. + const char* pattern_; + bool is_valid_; +#if GTEST_USES_POSIX_RE + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). +#else // GTEST_USES_SIMPLE_RE + const char* full_pattern_; // For FullMatch(); +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION_ + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ String GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ String GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION_ + + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +// GTEST_HAS_DEATH_TEST implies we have ::std::string. +const ::std::vector& GetArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +#include + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + } + + // Releases this mutex. + void Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_ = 0; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. +}; + +// Forward-declares a static mutex. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + owner_ = 0; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +#define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void AssertHeld() const {} +}; + +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +#define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +#define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +#define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +#define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +#if GTEST_OS_WINDOWS +#define GTEST_PATH_SEP_ "\\" +#define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +#define GTEST_PATH_SEP_ "/" +#define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +#ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +#else // !__BORLANDC__ +#if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +#else +inline int IsATTY(int fd) { return _isatty(fd); } +#endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +#endif // __BORLANDC__ + +#if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +#else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +#endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +#pragma warning(push) +#pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +#if GTEST_OS_LINUX +#include +#include +#include +#include +#endif // GTEST_OS_LINUX + +#include +#include +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +#include +#endif + +#include + +#include + +namespace testing { +namespace internal { + +// String - a UTF-8 string class. +// +// For historic reasons, we don't use std::string. +// +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. +// +// NULL and the empty string are considered different. NULL is less +// than anything (including the empty string) except itself. +// +// This class only provides minimum functionality necessary for +// implementing Google Test. We do not intend to implement a full-fledged +// string class here. +// +// Since the purpose of this class is to provide a substitute for +// std::string on platforms where it cannot be used, we define a copy +// constructor and assignment operators such that we don't need +// conditional compilation in a lot of places. +// +// In order to make the representation efficient, the d'tor of String +// is not virtual. Therefore DO NOT INHERIT FROM String. +class GTEST_API_ String { + public: + // Static utility methods + + // Returns the input enclosed in double quotes if it's not NULL; + // otherwise returns "(null)". For example, "\"Hello\"" is returned + // for input "Hello". + // + // This is useful for printing a C string in the syntax of a literal. + // + // Known issue: escape sequences are not handled yet. + static String ShowCStringQuoted(const char* c_str); + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static String ShowWideCString(const wchar_t* wide_c_str); + + // Similar to ShowWideCString(), except that this function encloses + // the converted string in double quotes. + static String ShowWideCStringQuoted(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Formats a list of arguments to a String, using the same format + // spec string as for printf. + // + // We do not use the StringPrintf class as it is not universally + // available. + // + // The result is limited to 4096 characters (including the tailing + // 0). If 4096 characters are not enough to format the input, + // "" is returned. + static String Format(const char* format, ...); + + // C'tors + + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} + + // Constructs a String by cloning a 0-terminated C string. + String(const char* a_c_str) { // NOLINT + if (a_c_str == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(a_c_str, strlen(a_c_str)); + } + } + + // Constructs a String by copying a given number of chars from a + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t a_length) { + ConstructNonNull(buffer, a_length); + } + + // The copy c'tor creates a new copy of the string. The two + // String objects do not share content. + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } + + // D'tor. String is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~String() { delete[] c_str_; } + + // Allows a String to be implicitly converted to an ::std::string or + // ::string, and vice versa. Converting a String containing a NULL + // pointer to ::std::string or ::string is undefined behavior. + // Converting a ::std::string or ::string containing an embedded NUL + // character to a String will result in the prefix up to the first + // NUL character. + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::std::string() const { return ::std::string(c_str(), length()); } + +#if GTEST_HAS_GLOBAL_STRING + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::string() const { return ::string(c_str(), length()); } +#endif // GTEST_HAS_GLOBAL_STRING + + // Returns true iff this is an empty string (i.e. ""). + bool empty() const { return (c_str() != NULL) && (length() == 0); } + + // Compares this with another String. + // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 + // if this is greater than rhs. + int Compare(const String& rhs) const; + + // Returns true iff this String equals the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } + + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". + bool operator<(const String& rhs) const { return Compare(rhs) < 0; } + + // Returns true iff this String doesn't equal the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } + + // Returns true iff this String ends with the given suffix. *Any* + // String is considered to end with a NULL or empty suffix. + bool EndsWith(const char* suffix) const; + + // Returns true iff this String ends with the given suffix, not considering + // case. Any String is considered to end with a NULL or empty suffix. + bool EndsWithCaseInsensitive(const char* suffix) const; + + // Returns the length of the encapsulated string, or 0 if the + // string is NULL. + size_t length() const { return length_; } + + // Gets the 0-terminated C string this String object represents. + // The String object still owns the string. Therefore the caller + // should NOT delete the return value. + const char* c_str() const { return c_str_; } + + // Assigns a C string to this object. Self-assignment works. + const String& operator=(const char* a_c_str) { + return *this = String(a_c_str); + } + + // Assigns a String object to this object. Self-assignment works. + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); + } + } + + return *this; + } + + private: + // Constructs a non-NULL String from the given content. This + // function can only be called when data_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t a_length) { + char* const str = new char[a_length + 1]; + memcpy(str, buffer, a_length); + str[a_length] = '\0'; + c_str_ = str; + length_ = a_length; + } + + const char* c_str_; + size_t length_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; +} + +// Gets the content of the StrStream's buffer as a String. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ String StrStreamToString(StrStream* stream); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". + +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const char* pathname) : pathname_(pathname) { + Normalize(); + } + + explicit FilePath(const String& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + String ToString() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is NULL or "". + bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + String pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +#ifdef __GLIBCXX__ +#include +#endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// GetTypeName() returns a human-readable name of type T. +template +String GetTypeName() { +#if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +#ifdef __GLIBCXX__ + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. + char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +#else + return name; +#endif // __GLIBCXX__ + +#else + return ""; +#endif // GTEST_HAS_RTTI +} + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +#define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +#define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Google Test defines the testing::Message class to allow construction of +// test messages via the << operator. The idea is that anything +// streamable to std::ostream can be streamed to a testing::Message. +// This allows a user to use his own types in Google Test assertions by +// overloading the << operator. +// +// util/gtl/stl_logging-inl.h overloads << for STL containers. These +// overloads cannot be defined in the std namespace, as that will be +// undefined behavior. Therefore, they are defined in the global +// namespace instead. +// +// C++'s symbol lookup rule (i.e. Koenig lookup) says that these +// overloads are visible in either the std namespace or the global +// namespace, but not other namespaces, including the testing +// namespace which Google Test's Message class is in. +// +// To allow STL containers (and other types that has a << operator +// defined in the global namespace) to be used in Google Test assertions, +// testing::Message must access the custom << operator from the global +// namespace. Hence this helper function. +// +// Note: Jeffrey Yasskin suggested an alternative fix by "using +// ::operator<<;" in the definition of Message's operator<<. That fix +// doesn't require a helper function, but unfortunately doesn't +// compile with MSVC. +template +inline void GTestStreamToHelper(std::ostream* os, const T& val) { + *os << val; +} + +namespace testing { + +// Forward declaration of classes. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +#define GTEST_IS_NULL_LITERAL_(x) false +#else +#define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ String AppendUserMessage(const String& gtest_msg, + const Message& user_msg); + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +// Formats a value to be used in a failure message. + +#ifdef GTEST_NEEDS_IS_POINTER_ + +// These are needed as the Nokia Symbian and IBM XL C/C++ compilers +// cannot decide between const T& and const T* in a function template. +// These compilers _can_ decide between class template specializations +// for T and T*, so a tr1::type_traits-like is_pointer works, and we +// can overload on that. + +// This overload makes sure that all pointers (including +// those to char or wchar_t) are printed as raw pointers. +template +inline String FormatValueForFailureMessage(internal::true_type /*dummy*/, + T* pointer) { + return StreamableToString(static_cast(pointer)); +} + +template +inline String FormatValueForFailureMessage(internal::false_type /*dummy*/, + const T& value) { + return StreamableToString(value); +} + +template +inline String FormatForFailureMessage(const T& value) { + return FormatValueForFailureMessage( + typename internal::is_pointer::type(), value); +} + +#else + +// These are needed as the above solution using is_pointer has the +// limitation that T cannot be a type without external linkage, when +// compiled using MSVC. + +template +inline String FormatForFailureMessage(const T& value) { + return StreamableToString(value); +} + +// This overload makes sure that all pointers (including +// those to char or wchar_t) are printed as raw pointers. +template +inline String FormatForFailureMessage(T* pointer) { + return StreamableToString(static_cast(pointer)); +} + +#endif // GTEST_NEEDS_IS_POINTER_ + +// These overloaded versions handle narrow and wide characters. +GTEST_API_ String FormatForFailureMessage(char ch); +GTEST_API_ String FormatForFailureMessage(wchar_t wchar); + +// When this operand is a const char* or char*, and the other operand +// is a ::std::string or ::string, we print this operand as a C string +// rather than a pointer. We do the same for wide strings. + +// This internal macro is used to avoid duplicated code. +#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ +inline String FormatForComparisonFailureMessage(\ + operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +}\ +inline String FormatForComparisonFailureMessage(\ + const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +} + +GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) +#if GTEST_HAS_STD_WSTRING +GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) +#endif // GTEST_HAS_GLOBAL_STRING +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_GLOBAL_WSTRING + +#undef GTEST_FORMAT_IMPL_ + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ String GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Formats a source file path and a line number as they would appear +// in a compiler error message. +inline String FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? "unknown file" : file; + if (line < 0) { + return String::Format("%s:", file_name); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line); +#else + return String::Format("%s:%d:", file_name, line); +#endif // _MSC_VER +} + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// test_case_comment: a comment on the test case that will be included in +// the test output +// comment: a comment on the test that will be included in the +// test output +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (isspace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline String GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? String(str) : String(str, comma - str); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", + case_name, index).c_str(), + GetPrefixUntilComma(test_names).c_str(), + String::Format("TypeParam = %s", GetTypeName().c_str()).c_str(), + "", + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, + int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_(message, result_type) \ + ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \ + = ::testing::Message() + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg = "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different " \ + "type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg = "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail(gtest_msg) + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + gtest_msg = "Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail(gtest_msg) + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + gtest_msg = "Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail(gtest_msg) + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, "", "", \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the two reasons that a test might be aborted. + enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const String& message); + + private: + // A string containing a description of the outcome of the last death test. + static String last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const String& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + String file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + String file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +#define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i); +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +#define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +#define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +#define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +#define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +#if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +#endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +#ifdef NDEBUG + +#define EXPECT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +#define ASSERT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +#else + +#define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +#define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +#endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a StrStream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that StrStream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + // We allocate the StrStream separately because it otherwise each use of + // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's + // stack frame leading to huge stack frames in some cases; gcc does not reuse + // the stack space. + Message() : ss_(new internal::StrStream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); + } + + // Copy constructor. + Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new internal::StrStream) { + *ss_ << str; + } + + ~Message() { delete ss_; } +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + ::GTestStreamToHelper(ss_, val); + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_, pointer); + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + Message& operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as a String. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::String GetString() const { + return internal::StrStreamToString(ss_); + } + + private: +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_, pointer); + } + } + template + inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { + ::GTestStreamToHelper(ss_, value); + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + internal::StrStream* const ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It must be derived from testing::TestWithParam, where T is +// the type of your parameter values. TestWithParam is itself derived +// from testing::Test. T can be any copyable type. If it's a raw pointer, +// you are responsible for managing the lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. + +#endif // 0 + + +#if !GTEST_OS_SYMBIAN +#include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + // Release ownership of the pointed object and returns it. + // Sole ownership by this linked_ptr object is required. + T* release() { + bool last = link_.depart(); + assert(last); + T* v = value_; + value_ = NULL; + return v; + } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + ::testing::internal::linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const String& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const String& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const char* instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const String& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + Message test_case_name_stream; + if ( !instantiation_name.empty() ) + test_case_name_stream << instantiation_name.c_str() << "/"; + test_case_name_stream << test_info->test_case_base_name.c_str(); + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name.c_str() << "/" << i; + ::testing::internal::MakeAndRegisterTestInfo( + test_case_name_stream.GetString().c_str(), + test_name_stream.GetString().c_str(), + "", // test_case_comment + "", // comment; TODO(vladl@google.com): provide parameter value + // representation. + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const String test_case_base_name; + const String test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const String test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::std::iterator_traits::value_type> ValuesIn( + ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, + v23_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, + v35_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, + v47_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_, v50_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +#if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +#endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::std::iterator_traits::value_type> ValuesIn( + ForwardIterator begin, + ForwardIterator end) { + typedef typename ::std::iterator_traits::value_type + ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +#if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +#endif // GTEST_HAS_COMBINE + + + +#define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { return file_name_.c_str(); } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static internal::String ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // NULL if the source file is unknown. + internal::String file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + internal::String summary_; // The test failure summary. + internal::String message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +#define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +#define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +#define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +#define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +#define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class TestInfoImpl; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message); +class PrettyUnitTestResultPrinter; +class XmlUnitTestResultPrinter; + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared in gtest-internal.h but defined here, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL && message_->c_str() != NULL ? + message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value); + + private: + // No implementation - we want AssertionResult to be + // copy-constructible but not assignable. + void operator=(const AssertionResult& other); + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr message_; +}; // class AssertionResult + +// Streams a custom failure message into this object. +template +AssertionResult& AssertionResult::operator<<(const T& value) { + Message msg; + if (message_.get() != NULL) + msg << *message_; + msg << value; + message_.reset(new internal::String(msg.GetString())); + return *this; +} + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class internal::TestInfoImpl; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test. Only the last value for a given + // key is remembered. + // These are public static so they can be called from utility functions + // that are not members of the test fixture. + // The arguments are const char* instead strings, as Google Test is used + // on platforms where string doesn't compile. + // + // Note that a driving consideration for these RecordProperty methods + // was to produce xml output suited to the Greenspan charting utility, + // which at present will only chart values that fit in a 32-bit int. It + // is the user's responsibility to restrict their values to 32-bit ints + // if they intend them to be used with Greenspan. + static void RecordProperty(const char* key, const char* value); + static void RecordProperty(const char* key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* a_key, const char* a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + internal::String key_; + // The value supplied by the user. + internal::String value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestInfoImpl; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const; + + // Returns the test name. + const char* name() const; + + // Returns the test case comment. + const char* test_case_comment() const; + + // Returns the test comment. + const char* comment() const; + + // Returns true if this test should run, that is if the test is not disabled + // (or it is disabled but the also_run_disabled_tests flag has been specified) + // and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const; + + // Returns the result of the test. + const TestResult* result() const; + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::TestInfoImpl; + friend class internal::UnitTestImpl; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Returns true if this test matches the user-specified filter. + bool matches_filter() const; + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count(); + + // Accessors for the implementation object. + internal::TestInfoImpl* impl() { return impl_; } + const internal::TestInfoImpl* impl() const { return impl_; } + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // An opaque implementation object. + internal::TestInfoImpl* impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the test case comment. + const char* comment() const { return comment_.c_str(); } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Returns true iff test passed. + static bool TestPassed(const TestInfo * test_info); + + // Returns true iff test failed. + static bool TestFailed(const TestInfo * test_info); + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo * test_info); + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo *test_info); + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + internal::String name_; + // Comment on the test case. + internal::String comment_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCESS(). + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::TestInfoImpl; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const; + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const; + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace); + + // Adds a TestProperty to the current TestResult object. If the result already + // contains a property with the same key, the value will be updated. + void RecordPropertyForCurrentTest(const char* key, const char* value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const internal::String& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace(); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// These overloaded versions handle ::std::string and ::std::wstring. +GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) { + return (Message() << '"' << str << '"').GetString(); +} + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) { + return (Message() << "L\"" << wstr << '"').GetString(); +} +#endif // GTEST_HAS_STD_WSTRING + +// These overloaded versions handle ::string and ::wstring. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ inline String FormatForFailureMessage(const ::string& str) { + return (Message() << '"' << str << '"').GetString(); +} +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) { + return (Message() << "L\"" << wstr << '"').GetString(); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char*, and print it as a C string when it is compared against an +// std::string object, for example. +// +// The default implementation ignores the type of the other operand. +// Some specialized versions are used to handle formatting wide or +// narrow C strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +String FormatForComparisonFailureMessage(const T1& value, + const T2& /* other_operand */) { + return FormatForFailureMessage(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to + // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& /* expected */, + T2* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + Message msg;\ + msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return AssertionFailure(msg);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, < ); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, > ); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + StrStream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + StrStream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StrStreamToString(&expected_ss), + StrStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The abstract base class that all value-parameterized tests inherit from. +// +// This class adds support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class TestWithParam : public Test { + public: + typedef T ParamType; + + // The current parameter value. Is also available in the test fixture's + // constructor. + const ParamType& GetParam() const { return *parameter_; } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of TestWithParam. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* TestWithParam::parameter_ = NULL; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// +// Examples: +// +// EXPECT_TRUE(server.StatusIsOK()); +// ASSERT_FALSE(server.HasPendingRequest(port)) +// << "There are still pending requests " << "on port " << port; + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +#define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +#define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// C String Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +#define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +#define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +#define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +namespace internal { + +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +} // namespace internal + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Use this macro in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). + +#define RUN_ALL_TESTS()\ + (::testing::UnitTest::GetInstance()->Run()) + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index 0043f0ac58..a06f74de5b 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -1,6 +1,11 @@ #include "TapCvfSpecialization.h" +#include "cafPdmCoreVec3d.h" +#include "cafPdmXmlVec3d.h" +#include "cafPdmUiCoreVec3d.h" + + CAF_PDM_SOURCE_INIT(TapCvfSpecialization, "TapCvfSpecialization"); @@ -15,17 +20,6 @@ TapCvfSpecialization::TapCvfSpecialization() CAF_PDM_InitField(&m_matrixField, "m_matrixField", cvf::Mat4d::ZERO, "Zero matrix", "", "", ""); CAF_PDM_InitField(&m_colorField, "m_colorField", cvf::Color3f(cvf::Color3::GREEN), "Color3f", "", "", ""); -/* - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Toggle Field", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Text", "", "Text tooltip", "This is a place you can enter a small integer value if you want"); - - m_proxyDoubleField.registerSetMethod(this, &SmallDemoPdmObject::setDoubleMember); - m_proxyDoubleField.registerGetMethod(this, &SmallDemoPdmObject::doubleMember); - CAF_PDM_InitFieldNoDefault(&m_proxyDoubleField, "ProxyDouble", "Proxy Double", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_vecArrayField, "Points", "Selected points", "", "", ""); - m_proxyDoubleField = 0; - if (!(m_proxyDoubleField == 3)) { std::cout << "Double is not 3 " << std::endl; } -*/ } diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h index d9ca7aa07f..6b3f9e994b 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h @@ -6,13 +6,14 @@ #include "cvfVector3.h" #include "cvfMatrix4.h" -#include "cafPdmObject.h" -#include "cafPdmField.h" - #include "cafPdmFieldCvfColor.h" #include "cafPdmFieldCvfVec3d.h" #include "cafPdmFieldCvfMat4d.h" +#include "cafPdmObject.h" +#include "cafPdmField.h" + + #include @@ -29,6 +30,6 @@ class TapCvfSpecialization : public caf::PdmObject caf::PdmField m_vectorField; caf::PdmField m_matrixField; - //caf::PdmField< std::vector< cvf::Vec3d> > m_vecArrayField; + caf::PdmField< std::vector< cvf::Vec3d> > m_vecArrayField; }; diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt new file mode 100644 index 0000000000..84863a43ff --- /dev/null +++ b/Fwk/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required (VERSION 2.8) + +project (TestCafAndVizFwk) + +find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) +include (${QT_USE_FILE}) + + +# Libraries +add_subdirectory(AppFwk/cafProjectDataModel/cafPdmCore) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdmUiCore) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdmXml) +add_subdirectory(AppFwk/cafProjectDataModel) +add_subdirectory(AppFwk/cafCommand) +add_subdirectory(AppFwk/cafUserInterface) + +# Unit Tests +add_subdirectory(AppFwk/cafTests/cafProjectDataModel_UnitTests) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests) +add_subdirectory(AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) + +# Executables +add_subdirectory(AppFwk/cafTests/cafTestApplication) + + +# Organize sub-projects into folders on Visual Studio +# Turn on using solution folders +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +set_property(TARGET cafPdmCore cafPdmUiCore cafPdmXml cafProjectDataModel PROPERTY FOLDER "ProjectDataModel") +set_property(TARGET cafPdmCore_UnitTests cafPdmXml_UnitTests cafProjectDataModel_UnitTests PROPERTY FOLDER "UnitTests") + +option (USE_CEE_VIZ "Enable visualization projects" ON) +if (USE_CEE_VIZ) + add_subdirectory(VizFwk/LibCore) + add_subdirectory(AppFwk/cafPdmCvf) + + add_subdirectory(AppFwk/cafTests/cafTestCvfApplication) + + set_property(TARGET LibCore cafPdmCvf cafTestCvfApplication PROPERTY FOLDER "CeeViz") +endif() From 1bdb68e3d7a5577c61e0cb7d846dfccb2a0654ee Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 10:12:36 +0100 Subject: [PATCH 139/290] [Fwk] Moved ProjectDataModel unit test --- .../CMakeLists.txt | 0 .../cafProjectDataModel_UnitTests/Child.cpp | 0 .../cafProjectDataModel_UnitTests/Child.h | 0 .../cafProjectDataModel_UnitTests/Parent.cpp | 0 .../cafProjectDataModel_UnitTests/Parent.h | 0 .../cafProjectDataModel_UnitTests/TestObj.cpp | 0 .../cafProjectDataModel_UnitTests/TestObj.h | 0 .../cafPdmBasicTest.cpp | 0 .../cafProjectDataModel_UnitTests.cpp | 0 .../gtest/cvftestUtils.h | 0 .../gtest/gtest-all.cpp | 0 .../gtest/gtest.h | 0 Fwk/AppFwk/cafTests/gtest/cvftestUtils.h | 43 - Fwk/AppFwk/cafTests/gtest/gtest-all.cpp | 8510 -------- Fwk/AppFwk/cafTests/gtest/gtest.h | 18007 ---------------- Fwk/CMakeLists.txt | 2 +- 16 files changed, 1 insertion(+), 26561 deletions(-) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/CMakeLists.txt (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/Child.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/Child.h (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/Parent.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/Parent.h (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/TestObj.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/TestObj.h (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp (100%) rename Fwk/AppFwk/{cafTests => cafProjectDataModel}/cafProjectDataModel_UnitTests/gtest/gtest.h (100%) delete mode 100644 Fwk/AppFwk/cafTests/gtest/cvftestUtils.h delete mode 100644 Fwk/AppFwk/cafTests/gtest/gtest-all.cpp delete mode 100644 Fwk/AppFwk/cafTests/gtest/gtest.h diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/CMakeLists.txt rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Child.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Child.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.h b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Child.h similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Child.h rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Child.h diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Parent.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Parent.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.h b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Parent.h similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/Parent.h rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/Parent.h diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/TestObj.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/TestObj.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.h b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/TestObj.h similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/TestObj.h rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/TestObj.h diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafProjectDataModel_UnitTests.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/cvftestUtils.h diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/gtest-all.cpp diff --git a/Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/gtest.h similarity index 100% rename from Fwk/AppFwk/cafTests/cafProjectDataModel_UnitTests/gtest/gtest.h rename to Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/gtest/gtest.h diff --git a/Fwk/AppFwk/cafTests/gtest/cvftestUtils.h b/Fwk/AppFwk/cafTests/gtest/cvftestUtils.h deleted file mode 100644 index c2a5a960d6..0000000000 --- a/Fwk/AppFwk/cafTests/gtest/cvftestUtils.h +++ /dev/null @@ -1,43 +0,0 @@ - - - -namespace cvftest { - - -//================================================================================================== -// -// -//================================================================================================== -class Utils -{ -public: - static cvf::String getTestDataDir(const cvf::String& unitTestFolder) - { -#ifdef WIN32 - std::string exe = std::string(testing::internal::GetArgvs()[0]); -#else - std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString()); - std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]); -#endif - std::string testPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("TestData/"); - - return testPath; - } - - static cvf::String getGLSLDir(const cvf::String& unitTestFolder) - { -#ifdef WIN32 - std::string exe = std::string(testing::internal::GetArgvs()[0]); -#else - std::string dir = std::string(testing::internal::FilePath::GetCurrentDir().ToString()); - std::string exe = dir + std::string("/") + std::string(testing::internal::GetArgvs()[0]); -#endif - std::string glslPath = exe.substr(0, exe.find(unitTestFolder.toStdString())) + std::string("../LibRender/glsl/"); - - return glslPath; - } -}; - - -} - diff --git a/Fwk/AppFwk/cafTests/gtest/gtest-all.cpp b/Fwk/AppFwk/cafTests/gtest/gtest-all.cpp deleted file mode 100644 index 644479a63c..0000000000 --- a/Fwk/AppFwk/cafTests/gtest/gtest-all.cpp +++ /dev/null @@ -1,8510 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) -// -// Sometimes it's desirable to build Google Test by compiling a single file. -// This file serves this purpose. - -// This line ensures that gtest.h can be compiled on its own, even -// when it's fused. -#include - -// The following lines pull in the real gtest *.cc files. -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) - -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// Utilities for testing Google Test itself and code that uses Google Test -// (e.g. frameworks built on top of Google Test). - -#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ -#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ - - -namespace testing { - -// This helper class can be used to mock out Google Test failure reporting -// so that we can test Google Test or code that builds on Google Test. -// -// An object of this class appends a TestPartResult object to the -// TestPartResultArray object given in the constructor whenever a Google Test -// failure is reported. It can either intercept only failures that are -// generated in the same thread that created this object or it can intercept -// all generated failures. The scope of this mock object can be controlled with -// the second argument to the two arguments constructor. -class GTEST_API_ ScopedFakeTestPartResultReporter - : public TestPartResultReporterInterface { - public: - // The two possible mocking modes of this object. - enum InterceptMode { - INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. - INTERCEPT_ALL_THREADS // Intercepts all failures. - }; - - // The c'tor sets this object as the test part result reporter used - // by Google Test. The 'result' parameter specifies where to report the - // results. This reporter will only catch failures generated in the current - // thread. DEPRECATED - explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); - - // Same as above, but you can choose the interception scope of this object. - ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, - TestPartResultArray* result); - - // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); - - // Appends the TestPartResult object to the TestPartResultArray - // received in the constructor. - // - // This method is from the TestPartResultReporterInterface - // interface. - virtual void ReportTestPartResult(const TestPartResult& result); - private: - void Init(); - - const InterceptMode intercept_mode_; - TestPartResultReporterInterface* old_reporter_; - TestPartResultArray* const result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); -}; - -namespace internal { - -// A helper class for implementing EXPECT_FATAL_FAILURE() and -// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -class GTEST_API_ SingleFailureChecker { - public: - // The constructor remembers the arguments. - SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const char* substr); - ~SingleFailureChecker(); - private: - const TestPartResultArray* const results_; - const TestPartResult::Type type_; - const String substr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); -}; - -} // namespace internal - -} // namespace testing - -// A set of macros for testing Google Test assertions or code that's expected -// to generate Google Test fatal failures. It verifies that the given -// statement will cause exactly one fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_FATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - 'statement' cannot reference local non-static variables or -// non-static members of the current object. -// - 'statement' cannot return a value. -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. The AcceptsMacroThatExpandsToUnprotectedComma test in -// gtest_unittest.cc will fail to compile if we do that. -#define EXPECT_FATAL_FAILURE(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ALL_THREADS, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -// A macro for testing Google Test assertions or code that's expected to -// generate Google Test non-fatal failures. It asserts that the given -// statement will cause exactly one non-fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// 'statement' is allowed to reference local variables and members of -// the current object. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. If we do that, the code won't compile when the user gives -// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that -// expands to code containing an unprotected comma. The -// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc -// catches that. -// -// For the same reason, we have to write -// if (::testing::internal::AlwaysTrue()) { statement; } -// instead of -// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) -// to avoid an MSVC warning on unreachable code. -#define EXPECT_NONFATAL_FAILURE(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ - >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if GTEST_OS_LINUX - -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 - -#include -#include -#include -// Declares vsnprintf(). This header is not available on Windows. -#include -#include -#include -#include -#include -#include - -#elif GTEST_OS_SYMBIAN -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT - -#elif GTEST_OS_ZOS -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT - -// On z/OS we additionally need strings.h for strcasecmp. -#include // NOLINT - -#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. - -#include // NOLINT - -#elif GTEST_OS_WINDOWS // We are on Windows proper. - -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. -#define GTEST_HAS_GETTIMEOFDAY_ 1 -#include // NOLINT -#endif // GTEST_OS_WINDOWS_MINGW - -// cpplint thinks that the header is already included, so we want to -// silence it. -#include // NOLINT - -#else - -// Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -#define GTEST_HAS_GETTIMEOFDAY_ 1 - -// cpplint thinks that the header is already included, so we want to -// silence it. -#include // NOLINT -#include // NOLINT - -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -#include -#endif - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// -// This file contains purely Google Test's internal implementation. Please -// DO NOT #INCLUDE IT IN A USER PROGRAM. - -#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ -#define GTEST_SRC_GTEST_INTERNAL_INL_H_ - -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -#error "gtest-internal-inl.h is part of Google Test's internal implementation." -#error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - -#ifndef _WIN32_WCE -#include -#endif // !_WIN32_WCE -#include -#include // For strtoll/_strtoul64/malloc/free. -#include // For memmove. - -#include -#include -#include - - -#if GTEST_OS_WINDOWS -#include // For DWORD. -#endif // GTEST_OS_WINDOWS - - -namespace testing { - -// Declares the flags. -// -// We don't want the users to modify this flag in the code, but want -// Google Test's own unit tests to be able to access it. Therefore we -// declare it here as opposed to in gtest.h. -GTEST_DECLARE_bool_(death_test_use_fork); - -namespace internal { - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; - -// Names of the flags (needed for parsing Google Test flags). -const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; -const char kBreakOnFailureFlag[] = "break_on_failure"; -const char kCatchExceptionsFlag[] = "catch_exceptions"; -const char kColorFlag[] = "color"; -const char kFilterFlag[] = "filter"; -const char kListTestsFlag[] = "list_tests"; -const char kOutputFlag[] = "output"; -const char kPrintTimeFlag[] = "print_time"; -const char kRandomSeedFlag[] = "random_seed"; -const char kRepeatFlag[] = "repeat"; -const char kShuffleFlag[] = "shuffle"; -const char kStackTraceDepthFlag[] = "stack_trace_depth"; -const char kThrowOnFailureFlag[] = "throw_on_failure"; - -// A valid random seed must be in [1, kMaxRandomSeed]. -const int kMaxRandomSeed = 99999; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -GTEST_API_ extern bool g_help_flag; - -// Returns the current time in milliseconds. -GTEST_API_ TimeInMillis GetTimeInMillis(); - -// Returns true iff Google Test should use colors in the output. -GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); - -// Formats the given time in milliseconds as seconds. -GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); - -// Parses a string for an Int32 flag, in the form of "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); - -// Returns a random seed in range [1, kMaxRandomSeed] based on the -// given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { - const unsigned int raw_seed = (random_seed_flag == 0) ? - static_cast(GetTimeInMillis()) : - static_cast(random_seed_flag); - - // Normalizes the actual seed to range [1, kMaxRandomSeed] such that - // it's easy to type. - const int normalized_seed = - static_cast((raw_seed - 1U) % - static_cast(kMaxRandomSeed)) + 1; - return normalized_seed; -} - -// Returns the first valid random seed after 'seed'. The behavior is -// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is -// considered to be 1. -inline int GetNextRandomSeed(int seed) { - GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) - << "Invalid random seed " << seed << " - must be in [1, " - << kMaxRandomSeed << "]."; - const int next_seed = seed + 1; - return (next_seed > kMaxRandomSeed) ? 1 : next_seed; -} - -// This class saves the values of all Google Test flags in its c'tor, and -// restores them in its d'tor. -class GTestFlagSaver { - public: - // The c'tor. - GTestFlagSaver() { - also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); - break_on_failure_ = GTEST_FLAG(break_on_failure); - catch_exceptions_ = GTEST_FLAG(catch_exceptions); - color_ = GTEST_FLAG(color); - death_test_style_ = GTEST_FLAG(death_test_style); - death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); - filter_ = GTEST_FLAG(filter); - internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); - list_tests_ = GTEST_FLAG(list_tests); - output_ = GTEST_FLAG(output); - print_time_ = GTEST_FLAG(print_time); - random_seed_ = GTEST_FLAG(random_seed); - repeat_ = GTEST_FLAG(repeat); - shuffle_ = GTEST_FLAG(shuffle); - stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); - throw_on_failure_ = GTEST_FLAG(throw_on_failure); - } - - // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. - ~GTestFlagSaver() { - GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; - GTEST_FLAG(break_on_failure) = break_on_failure_; - GTEST_FLAG(catch_exceptions) = catch_exceptions_; - GTEST_FLAG(color) = color_; - GTEST_FLAG(death_test_style) = death_test_style_; - GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; - GTEST_FLAG(filter) = filter_; - GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; - GTEST_FLAG(list_tests) = list_tests_; - GTEST_FLAG(output) = output_; - GTEST_FLAG(print_time) = print_time_; - GTEST_FLAG(random_seed) = random_seed_; - GTEST_FLAG(repeat) = repeat_; - GTEST_FLAG(shuffle) = shuffle_; - GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; - GTEST_FLAG(throw_on_failure) = throw_on_failure_; - } - private: - // Fields for saving the original values of flags. - bool also_run_disabled_tests_; - bool break_on_failure_; - bool catch_exceptions_; - String color_; - String death_test_style_; - bool death_test_use_fork_; - String filter_; - String internal_run_death_test_; - bool list_tests_; - String output_; - bool print_time_; - bool pretty_; - internal::Int32 random_seed_; - internal::Int32 repeat_; - bool shuffle_; - internal::Int32 stack_trace_depth_; - bool throw_on_failure_; -} GTEST_ATTRIBUTE_UNUSED_; - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded(); - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (e.g., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -GTEST_API_ bool ShouldShard(const char* total_shards_str, - const char* shard_index_str, - bool in_subprocess_for_death_test); - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and -// and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -GTEST_API_ bool ShouldRunTestOnShard( - int total_shards, int shard_index, int test_id); - -// STL container utilities. - -// Returns the number of elements in the given container that satisfy -// the given predicate. -template -inline int CountIf(const Container& c, Predicate predicate) { - return static_cast(std::count_if(c.begin(), c.end(), predicate)); -} - -// Applies a function/functor to each element in the container. -template -void ForEach(const Container& c, Functor functor) { - std::for_each(c.begin(), c.end(), functor); -} - -// Returns the i-th element of the vector, or default_value if i is not -// in range [0, v.size()). -template -inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; -} - -// Performs an in-place shuffle of a range of the vector's elements. -// 'begin' and 'end' are element indices as an STL-style range; -// i.e. [begin, end) are shuffled, where 'end' == size() means to -// shuffle to the end of the vector. -template -void ShuffleRange(internal::Random* random, int begin, int end, - std::vector* v) { - const int size = static_cast(v->size()); - GTEST_CHECK_(0 <= begin && begin <= size) - << "Invalid shuffle range start " << begin << ": must be in range [0, " - << size << "]."; - GTEST_CHECK_(begin <= end && end <= size) - << "Invalid shuffle range finish " << end << ": must be in range [" - << begin << ", " << size << "]."; - - // Fisher-Yates shuffle, from - // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - for (int range_width = end - begin; range_width >= 2; range_width--) { - const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); - } -} - -// Performs an in-place shuffle of the vector's elements. -template -inline void Shuffle(internal::Random* random, std::vector* v) { - ShuffleRange(random, 0, static_cast(v->size()), v); -} - -// A function for deleting an object. Handy for being used as a -// functor. -template -static void Delete(T* x) { - delete x; -} - -// A predicate that checks the key of a TestProperty against a known key. -// -// TestPropertyKeyIs is copyable. -class TestPropertyKeyIs { - public: - // Constructor. - // - // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const char* key) - : key_(key) {} - - // Returns true iff the test name of test property matches on key_. - bool operator()(const TestProperty& test_property) const { - return String(test_property.key()).Compare(key_) == 0; - } - - private: - String key_; -}; - -class TestInfoImpl { - public: - TestInfoImpl(TestInfo* parent, const char* test_case_name, - const char* name, const char* test_case_comment, - const char* comment, TypeId fixture_class_id, - internal::TestFactoryBase* factory); - ~TestInfoImpl(); - - // Returns true if this test should run. - bool should_run() const { return should_run_; } - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Returns true if this test is disabled. Disabled tests are not run. - bool is_disabled() const { return is_disabled_; } - - // Sets the is_disabled member. - void set_is_disabled(bool is) { is_disabled_ = is; } - - // Returns true if this test matches the filter specified by the user. - bool matches_filter() const { return matches_filter_; } - - // Sets the matches_filter member. - void set_matches_filter(bool matches) { matches_filter_ = matches; } - - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } - - // Returns the test name. - const char* name() const { return name_.c_str(); } - - // Returns the test case comment. - const char* test_case_comment() const { return test_case_comment_.c_str(); } - - // Returns the test comment. - const char* comment() const { return comment_.c_str(); } - - // Returns the ID of the test fixture class. - TypeId fixture_class_id() const { return fixture_class_id_; } - - // Returns the test result. - TestResult* result() { return &result_; } - const TestResult* result() const { return &result_; } - - // Creates the test object, runs it, records its result, and then - // deletes it. - void Run(); - - // Clears the test result. - void ClearResult() { result_.Clear(); } - - // Clears the test result in the given TestInfo object. - static void ClearTestResult(TestInfo * test_info) { - test_info->impl()->ClearResult(); - } - - private: - // These fields are immutable properties of the test. - TestInfo* const parent_; // The owner of this object - const String test_case_name_; // Test case name - const String name_; // Test name - const String test_case_comment_; // Test case comment - const String comment_; // Test comment - const TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - internal::TestFactoryBase* const factory_; // The factory that creates - // the test object - - // This field is mutable and needs to be reset before running the - // test for the second time. - TestResult result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); -}; - -// Class UnitTestOptions. -// -// This class contains functions for processing options the user -// specifies when running the tests. It has only static members. -// -// In most cases, the user can specify an option using either an -// environment variable or a command line flag. E.g. you can set the -// test filter using either GTEST_FILTER or --gtest_filter. If both -// the variable and the flag are present, the latter overrides the -// former. -class GTEST_API_ UnitTestOptions { - public: - // Functions for processing the gtest_output flag. - - // Returns the output format, or "" for normal printed output. - static String GetOutputFormat(); - - // Returns the absolute path of the requested output file, or the - // default (test_detail.xml in the original working directory) if - // none was explicitly specified. - static String GetAbsolutePathToOutputFile(); - - // Functions for processing the gtest_filter flag. - - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. - // - // This recursive algorithm isn't very efficient, but is clear and - // works well enough for matching test names, which are short. - static bool PatternMatchesString(const char *pattern, const char *str); - - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const String &test_case_name, - const String &test_name); - -#if GTEST_OS_WINDOWS - // Function for supporting the gtest_catch_exception flag. - - // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the - // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. - // This function is useful as an __except condition. - static int GTestShouldProcessSEH(DWORD exception_code); -#endif // GTEST_OS_WINDOWS - - // Returns true if "name" matches the ':' separated list of glob-style - // filters in "filter". - static bool MatchesFilter(const String& name, const char* filter); -}; - -// Returns the current application's name, removing directory path if that -// is present. Used by UnitTestOptions::GetOutputFile. -GTEST_API_ FilePath GetCurrentExecutableName(); - -// The role interface for getting the OS stack trace as a string. -class OsStackTraceGetterInterface { - public: - OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} - - // Returns the current OS stack trace as a String. Parameters: - // - // max_depth - the maximum number of stack frames to be included - // in the trace. - // skip_count - the number of top frames to be skipped; doesn't count - // against max_depth. - virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; - - // UponLeavingGTest() should be called immediately before Google Test calls - // user code. It saves some information about the current stack that - // CurrentStackTrace() will use to find and hide Google Test stack frames. - virtual void UponLeavingGTest() = 0; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); -}; - -// A working implementation of the OsStackTraceGetterInterface interface. -class OsStackTraceGetter : public OsStackTraceGetterInterface { - public: - OsStackTraceGetter() : caller_frame_(NULL) {} - virtual String CurrentStackTrace(int max_depth, int skip_count); - virtual void UponLeavingGTest(); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; - - private: - Mutex mutex_; // protects all internal state - - // We save the stack frame below the frame that calls user code. - // We do this because the address of the frame immediately below - // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); -}; - -// Information about a Google Test trace point. -struct TraceInfo { - const char* file; - int line; - String message; -}; - -// This is the default global test part result reporter used in UnitTestImpl. -// This class should only be used by UnitTestImpl. -class DefaultGlobalTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. Reports the test part - // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); -}; - -// This is the default per thread test part result reporter used in -// UnitTestImpl. This class should only be used by UnitTestImpl. -class DefaultPerThreadTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. The implementation just - // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); -}; - -// The private implementation of the UnitTest class. We don't protect -// the methods under a mutex, as this class is not accessible by a -// user and the UnitTest class that delegates work to this class does -// proper locking. -class GTEST_API_ UnitTestImpl { - public: - explicit UnitTestImpl(UnitTest* parent); - virtual ~UnitTestImpl(); - - // There are two different ways to register your own TestPartResultReporter. - // You can register your own repoter to listen either only for test results - // from the current thread or for results from all threads. - // By default, each per-thread test result repoter just passes a new - // TestPartResult to the global test result reporter, which registers the - // test part result for the currently running test. - - // Returns the global test part result reporter. - TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); - - // Sets the global test part result reporter. - void SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter); - - // Returns the test part result reporter for the current thread. - TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); - - // Sets the test part result reporter for the current thread. - void SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter); - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const { return !Failed(); } - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; - } - - // Provides access to the event listener list. - TestEventListeners* listeners() { return &listeners_; } - - // Returns the TestResult for the test that's currently running, or - // the TestResult for the ad hoc test if no test is running. - TestResult* current_test_result(); - - // Returns the TestResult for the ad hoc test. - const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } - - // Sets the OS stack trace getter. - // - // Does nothing if the input and the current OS stack trace getter - // are the same; otherwise, deletes the old getter and makes the - // input the current getter. - void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); - - // Returns the current OS stack trace getter if it is not NULL; - // otherwise, creates an OsStackTraceGetter, makes it the current - // getter, and returns it. - OsStackTraceGetterInterface* os_stack_trace_getter(); - - // Returns the current OS stack trace as a String. - // - // The maximum number of stack frames to be included is specified by - // the gtest_stack_trace_depth flag. The skip_count parameter - // specifies the number of top frames to be skipped, which doesn't - // count against the number of frames to be included. - // - // For example, if Foo() calls Bar(), which in turn calls - // CurrentOsStackTraceExceptTop(1), Foo() will be included in the - // trace but Bar() and CurrentOsStackTraceExceptTop() won't. - String CurrentOsStackTraceExceptTop(int skip_count); - - // Finds and returns a TestCase with the given name. If one doesn't - // exist, creates one and returns it. - // - // Arguments: - // - // test_case_name: name of the test case - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* comment, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Adds a TestInfo to the unit test. - // - // Arguments: - // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - TestInfo * test_info) { - // In order to support thread-safe death tests, we need to - // remember the original working directory when the test program - // was first invoked. We cannot do this in RUN_ALL_TESTS(), as - // the user may have changed the current directory before calling - // RUN_ALL_TESTS(). Therefore we capture the current directory in - // AddTestInfo(), which is called to register a TEST or TEST_F - // before main() is reached. - if (original_working_dir_.IsEmpty()) { - original_working_dir_.Set(FilePath::GetCurrentDir()); - GTEST_CHECK_(!original_working_dir_.IsEmpty()) - << "Failed to get the current working directory."; - } - - GetTestCase(test_info->test_case_name(), - test_info->test_case_comment(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); - } - -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { - return parameterized_test_registry_; - } -#endif // GTEST_HAS_PARAM_TEST - - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; - } - - // Sets the TestInfo object for the test that's currently running. If - // current_test_info is NULL, the assertion results will be stored in - // ad_hoc_test_result_. - void set_current_test_info(TestInfo* a_current_test_info) { - current_test_info_ = a_current_test_info; - } - - // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_P, creating regular tests for each test/parameter - // combination. This method can be called more then once; it has - // guards protecting from registering the tests more then once. - // If value-parameterized tests are disabled, RegisterParameterizedTests - // is present but does nothing. - void RegisterParameterizedTests(); - - // Runs all tests in this UnitTest object, prints the result, and - // returns 0 if all tests are successful, or 1 otherwise. If any - // exception is thrown during a test on Windows, this test is - // considered to be failed, but the rest of the tests will still be - // run. (We disable exceptions on Linux and Mac OS X, so the issue - // doesn't apply there.) - int RunAllTests(); - - // Clears the results of all tests, including the ad hoc test. - void ClearResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); - ad_hoc_test_result_.Clear(); - } - - enum ReactionToSharding { - HONOR_SHARDING_PROTOCOL, - IGNORE_SHARDING_PROTOCOL - }; - - // Matches the full name of each test against the user-specified - // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. - // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests - // based on sharding variables in the environment. - // Returns the number of tests that should run. - int FilterTests(ReactionToSharding shard_tests); - - // Prints the names of the tests matching the user-specified filter flag. - void ListTestsMatchingFilter(); - - const TestCase* current_test_case() const { return current_test_case_; } - TestInfo* current_test_info() { return current_test_info_; } - const TestInfo* current_test_info() const { return current_test_info_; } - - // Returns the vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector& environments() { return environments_; } - - // Getters for the per-thread Google Test trace stack. - std::vector& gtest_trace_stack() { - return *(gtest_trace_stack_.pointer()); - } - const std::vector& gtest_trace_stack() const { - return gtest_trace_stack_.get(); - } - -#if GTEST_HAS_DEATH_TEST - void InitDeathTestSubprocessControlInfo() { - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); - } - // Returns a pointer to the parsed --gtest_internal_run_death_test - // flag, or NULL if that flag was not specified. - // This information is useful only in a death test child process. - // Must not be called before a call to InitGoogleTest. - const InternalRunDeathTestFlag* internal_run_death_test_flag() const { - return internal_run_death_test_flag_.get(); - } - - // Returns a pointer to the current death test factory. - internal::DeathTestFactory* death_test_factory() { - return death_test_factory_.get(); - } - - void SuppressTestEventsIfInSubprocess(); - - friend class ReplaceDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - - // Initializes the event listener performing XML output as specified by - // UnitTestOptions. Must not be called before InitGoogleTest. - void ConfigureXmlOutput(); - - // Performs initialization dependent upon flag values obtained in - // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to - // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest - // this function is also called from RunAllTests. Since this function can be - // called more than once, it has to be idempotent. - void PostFlagParsingInit(); - - // Gets the random seed used at the start of the current test iteration. - int random_seed() const { return random_seed_; } - - // Gets the random number generator. - internal::Random* random() { return &random_; } - - // Shuffles all test cases, and the tests within each test case, - // making sure that death tests are still run first. - void ShuffleTests(); - - // Restores the test cases and tests to their order before the first shuffle. - void UnshuffleTests(); - - private: - friend class ::testing::UnitTest; - - // The UnitTest object that owns this implementation object. - UnitTest* const parent_; - - // The working directory when the first TEST() or TEST_F() was - // executed. - internal::FilePath original_working_dir_; - - // The default test part result reporters. - DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; - DefaultPerThreadTestPartResultReporter - default_per_thread_test_part_result_reporter_; - - // Points to (but doesn't own) the global test part result reporter. - TestPartResultReporterInterface* global_test_part_result_repoter_; - - // Protects read and write access to global_test_part_result_reporter_. - internal::Mutex global_test_part_result_reporter_mutex_; - - // Points to (but doesn't own) the per-thread test part result reporter. - internal::ThreadLocal - per_thread_test_part_result_reporter_; - - // The vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector environments_; - - // The vector of TestCases in their original order. It owns the - // elements in the vector. - std::vector test_cases_; - - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the - // shuffled order. - std::vector test_case_indices_; - -#if GTEST_HAS_PARAM_TEST - // ParameterizedTestRegistry object used to register value-parameterized - // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; - - // Indicates whether RegisterParameterizedTests() has been called already. - bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; - - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. - // When no test is running, this is set to NULL and Google Test - // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; - - // This points to the TestInfo for the currently running test. It - // changes as Google Test goes through one test after another. When - // no test is running, this is set to NULL and Google Test stores - // assertion results in ad_hoc_test_result_. Initially NULL. - TestInfo* current_test_info_; - - // Normally, a user only writes assertions inside a TEST or TEST_F, - // or inside a function called by a TEST or TEST_F. Since Google - // Test keeps track of which test is current running, it can - // associate such an assertion with the test it belongs to. - // - // If an assertion is encountered when no TEST or TEST_F is running, - // Google Test attributes the assertion result to an imaginary "ad hoc" - // test, and records the result in ad_hoc_test_result_. - TestResult ad_hoc_test_result_; - - // The list of event listeners that can be used to track events inside - // Google Test. - TestEventListeners listeners_; - - // The OS stack trace getter. Will be deleted when the UnitTest - // object is destructed. By default, an OsStackTraceGetter is used, - // but the user can set this field to use a custom getter if that is - // desired. - OsStackTraceGetterInterface* os_stack_trace_getter_; - - // True iff PostFlagParsingInit() has been called. - bool post_flag_parse_init_performed_; - - // The random number seed used at the beginning of the test run. - int random_seed_; - - // Our random number generator. - internal::Random random_; - - // How long the test took to run, in milliseconds. - TimeInMillis elapsed_time_; - -#if GTEST_HAS_DEATH_TEST - // The decomposed components of the gtest_internal_run_death_test flag, - // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; -#endif // GTEST_HAS_DEATH_TEST - - // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); -}; // class UnitTestImpl - -// Convenience function for accessing the global UnitTest -// implementation object. -inline UnitTestImpl* GetUnitTestImpl() { - return UnitTest::GetInstance()->impl(); -} - -// Internal helper functions for implementing the simple regular -// expression matcher. -GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsDigit(char ch); -GTEST_API_ bool IsPunct(char ch); -GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsWhiteSpace(char ch); -GTEST_API_ bool IsWordChar(char ch); -GTEST_API_ bool IsValidEscape(char ch); -GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ bool ValidateRegex(const char* regex); -GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); -GTEST_API_ bool MatchRepetitionAndRegexAtHead( - bool escaped, char ch, char repeat, const char* regex, const char* str); -GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); - -#if GTEST_HAS_DEATH_TEST - -// Returns the message describing the last system error, regardless of the -// platform. -String GetLastErrnoDescription(); - -#if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -#endif // GTEST_OS_WINDOWS - -// Attempts to parse a string into a positive integer pointed to by the -// number parameter. Returns true if that is possible. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use -// it here. -template -bool ParseNaturalNumber(const ::std::string& str, Integer* number) { - // Fail fast if the given string does not begin with a digit; - // this bypasses strtoXXX's "optional leading whitespace and plus - // or minus sign" semantics, which are undesirable here. - if (str.empty() || !isdigit(str[0])) { - return false; - } - errno = 0; - - char* end; - // BiggestConvertible is the largest integer type that system-provided - // string-to-number conversion routines can return. -#if GTEST_OS_WINDOWS && !defined(__GNUC__) - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); -#else - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); -#endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - const bool parse_success = *end == '\0' && errno == 0; - - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. - GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); - - const Integer result = static_cast(parsed); - if (parse_success && static_cast(result) == parsed) { - *number = result; - return true; - } - return false; -} -#endif // GTEST_HAS_DEATH_TEST - -// TestResult contains some private methods that should be hidden from -// Google Test user but are required for testing. This class allow our tests -// to access them. -// -// This class is supplied only for the purpose of testing Google Test's own -// constructs. Do not use it in user tests, either directly or indirectly. -class TestResultAccessor { - public: - static void RecordProperty(TestResult* test_result, - const TestProperty& property) { - test_result->RecordProperty(property); - } - - static void ClearTestPartResults(TestResult* test_result) { - test_result->ClearTestPartResults(); - } - - static const std::vector& test_part_results( - const TestResult& test_result) { - return test_result.test_part_results(); - } -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ -#undef GTEST_IMPLEMENTATION_ - -#if GTEST_OS_WINDOWS -#define vsnprintf _vsnprintf -#endif // GTEST_OS_WINDOWS - -namespace testing { - -using internal::CountIf; -using internal::ForEach; -using internal::GetElementOr; -using internal::Shuffle; - -// Constants. - -// A test whose test case name or test name matches this filter is -// disabled and not run. -static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; - -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't -// match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; - -// A test filter that matches everything. -static const char kUniversalFilter[] = "*"; - -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; - -// The environment variable name for the test shard index. -static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; -// The environment variable name for the total number of test shards. -static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; -// The environment variable name for the test shard status file. -static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; - -namespace internal { - -// The text used in failure messages to indicate the start of the -// stack trace. -const char kStackTraceMarker[] = "\nStack trace:\n"; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -bool g_help_flag = false; - -} // namespace internal - -GTEST_DEFINE_bool_( - also_run_disabled_tests, - internal::BoolFromGTestEnv("also_run_disabled_tests", false), - "Run disabled tests too, in addition to the tests normally being run."); - -GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); - -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", false), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); - -GTEST_DEFINE_string_( - color, - internal::StringFromGTestEnv("color", "auto"), - "Whether to use colors in the output. Valid values: yes, no, " - "and auto. 'auto' means to use colors if the output is " - "being sent to a terminal and the TERM environment variable " - "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); - -GTEST_DEFINE_string_( - filter, - internal::StringFromGTestEnv("filter", kUniversalFilter), - "A colon-separated list of glob (not regex) patterns " - "for filtering the tests to run, optionally followed by a " - "'-' and a : separated list of negative patterns (tests to " - "exclude). A test is run if it matches one of the positive " - "patterns and does not match any of the negative patterns."); - -GTEST_DEFINE_bool_(list_tests, false, - "List all tests without running them."); - -GTEST_DEFINE_string_( - output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " - "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " - "If a directory is specified, output files will be created " - "within that directory, with file-names based on the test " - "executable's name and, if necessary, made unique by adding " - "digits."); - -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); - -GTEST_DEFINE_int32_( - random_seed, - internal::Int32FromGTestEnv("random_seed", 0), - "Random number seed to use when shuffling test orders. Must be in range " - "[1, 99999], or 0 to use a seed based on the current time."); - -GTEST_DEFINE_int32_( - repeat, - internal::Int32FromGTestEnv("repeat", 1), - "How many times to repeat each test. Specify a negative number " - "for repeating forever. Useful for shaking out flaky tests."); - -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); - -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); - -GTEST_DEFINE_int32_( - stack_trace_depth, - internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), - "The maximum number of stack frames to print when an " - "assertion fails. The valid range is 0 through 100, inclusive."); - -GTEST_DEFINE_bool_( - throw_on_failure, - internal::BoolFromGTestEnv("throw_on_failure", false), - "When this flag is specified, a failed assertion will throw an exception " - "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); - -namespace internal { - -// Generates a random number from [0, range), using a Linear -// Congruential Generator (LCG). Crashes if 'range' is 0 or greater -// than kMaxRange. -UInt32 Random::Generate(UInt32 range) { - // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; - - GTEST_CHECK_(range > 0) - << "Cannot generate a number in the range [0, 0)."; - GTEST_CHECK_(range <= kMaxRange) - << "Generation of a number in [0, " << range << ") was requested, " - << "but this can only generate numbers in [0, " << kMaxRange << ")."; - - // Converting via modulus introduces a bit of downward bias, but - // it's simple, and a linear congruential generator isn't too good - // to begin with. - return state_ % range; -} - -// GTestIsInitialized() returns true iff the user has initialized -// Google Test. Useful for catching the user mistake of not initializing -// Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the -// results of calling a given int-returning method on each. -// Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { - int sum = 0; - for (size_t i = 0; i < case_list.size(); i++) { - sum += (case_list[i]->*method)(); - } - return sum; -} - -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); -} - -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); -} - -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); -} - -// AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message) - : data_(new AssertHelperData(type, file, line, message)) { -} - -AssertHelper::~AssertHelper() { - delete data_; -} - -// Message assignment, for assertion streaming support. -void AssertHelper::operator=(const Message& message) const { - UnitTest::GetInstance()-> - AddTestPartResult(data_->type, data_->file, data_->line, - AppendUserMessage(data_->message, message), - UnitTest::GetInstance()->impl() - ->CurrentOsStackTraceExceptTop(1) - // Skips the stack frame for this function itself. - ); // NOLINT -} - -// Mutex for linked pointers. -GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// Application pathname gotten in InitGoogleTest. -String g_executable_path; - -// Returns the current application's name, removing directory path if that -// is present. -FilePath GetCurrentExecutableName() { - FilePath result; - -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); -#else - result.Set(FilePath(g_executable_path)); -#endif // GTEST_OS_WINDOWS - - return result.RemoveDirectoryName(); -} - -// Functions for processing the gtest_output flag. - -// Returns the output format, or "" for normal printed output. -String UnitTestOptions::GetOutputFormat() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return String(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - String(gtest_output_flag) : - String(gtest_output_flag, colon - gtest_output_flag); -} - -// Returns the name of the requested output file, or the default if none -// was explicitly specified. -String UnitTestOptions::GetAbsolutePathToOutputFile() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return String(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return String(internal::FilePath::ConcatPaths( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).ToString() ); - - internal::FilePath output_name(colon + 1); - if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. - output_name = internal::FilePath::ConcatPaths( - internal::FilePath(UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(colon + 1)); - - if (!output_name.IsDirectory()) - return output_name.ToString(); - - internal::FilePath result(internal::FilePath::GenerateUniqueFileName( - output_name, internal::GetCurrentExecutableName(), - GetOutputFormat().c_str())); - return result.ToString(); -} - -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. -// -// This recursive algorithm isn't very efficient, but is clear and -// works well enough for matching test names, which are short. -bool UnitTestOptions::PatternMatchesString(const char *pattern, - const char *str) { - switch (*pattern) { - case '\0': - case ':': // Either ':' or '\0' marks the end of the pattern. - return *str == '\0'; - case '?': // Matches any single character. - return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); - case '*': // Matches any string (possibly empty) of characters. - return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); - default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); - } -} - -bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { - const char *cur_pattern = filter; - for (;;) { - if (PatternMatchesString(cur_pattern, name.c_str())) { - return true; - } - - // Finds the next pattern in the filter. - cur_pattern = strchr(cur_pattern, ':'); - - // Returns if no more pattern can be found. - if (cur_pattern == NULL) { - return false; - } - - // Skips the pattern separater (the ':' character). - cur_pattern++; - } -} - -// TODO(keithray): move String function implementations to gtest-string.cc. - -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, - const String &test_name) { - const String& full_name = String::Format("%s.%s", - test_case_name.c_str(), - test_name.c_str()); - - // Split --gtest_filter at '-', if there is one, to separate into - // positive filter and negative filter portions - const char* const p = GTEST_FLAG(filter).c_str(); - const char* const dash = strchr(p, '-'); - String positive; - String negative; - if (dash == NULL) { - positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter - negative = String(""); - } else { - positive = String(p, dash - p); // Everything up to the dash - negative = String(dash+1); // Everything after the dash - if (positive.empty()) { - // Treat '-test1' as the same as '*-test1' - positive = kUniversalFilter; - } - } - - // A filter is a colon-separated list of patterns. It matches a - // test if any pattern in it matches the test. - return (MatchesFilter(full_name, positive.c_str()) && - !MatchesFilter(full_name, negative.c_str())); -} - -#if GTEST_OS_WINDOWS -// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the -// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. -// This function is useful as an __except condition. -int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle an exception if: - // 1. the user wants it to, AND - // 2. this is not a breakpoint exception. - return (GTEST_FLAG(catch_exceptions) && - exception_code != EXCEPTION_BREAKPOINT) ? - EXCEPTION_EXECUTE_HANDLER : - EXCEPTION_CONTINUE_SEARCH; -} -#endif // GTEST_OS_WINDOWS - -} // namespace internal - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. Intercepts only failures from the current thread. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), - result_(result) { - Init(); -} - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - InterceptMode intercept_mode, TestPartResultArray* result) - : intercept_mode_(intercept_mode), - result_(result) { - Init(); -} - -void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - old_reporter_ = impl->GetGlobalTestPartResultReporter(); - impl->SetGlobalTestPartResultReporter(this); - } else { - old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); - impl->SetTestPartResultReporterForCurrentThread(this); - } -} - -// The d'tor restores the test part result reporter used by Google Test -// before. -ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - impl->SetGlobalTestPartResultReporter(old_reporter_); - } else { - impl->SetTestPartResultReporterForCurrentThread(old_reporter_); - } -} - -// Increments the test part result count and remembers the result. -// This method is from the TestPartResultReporterInterface interface. -void ScopedFakeTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - result_->Append(result); -} - -namespace internal { - -// Returns the type ID of ::testing::Test. We should always call this -// instead of GetTypeId< ::testing::Test>() to get the type ID of -// testing::Test. This is to work around a suspected linker bug when -// using Google Test as a framework on Mac OS X. The bug causes -// GetTypeId< ::testing::Test>() to return different values depending -// on whether the call is from the Google Test framework itself or -// from user test code. GetTestTypeId() is guaranteed to always -// return the same value, as it always calls GetTypeId<>() from the -// gtest.cc, which is within the Google Test framework. -TypeId GetTestTypeId() { - return GetTypeId(); -} - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); - -// This predicate-formatter checks that 'results' contains a test part -// failure of the given type and that the failure message contains the -// given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const char* substr) { - const String expected(type == TestPartResult::kFatalFailure ? - "1 fatal failure" : - "1 non-fatal failure"); - Message msg; - if (results.size() != 1) { - msg << "Expected: " << expected << "\n" - << " Actual: " << results.size() << " failures"; - for (int i = 0; i < results.size(); i++) { - msg << "\n" << results.GetTestPartResult(i); - } - return AssertionFailure(msg); - } - - const TestPartResult& r = results.GetTestPartResult(0); - if (r.type() != type) { - msg << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); - } - - if (strstr(r.message(), substr) == NULL) { - msg << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - return AssertionFailure(msg); - } - - return AssertionSuccess(); -} - -// The constructor of SingleFailureChecker remembers where to look up -// test part results, what type of failure we expect, and what -// substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const char* substr) - : results_(results), - type_(type), - substr_(substr) {} - -// The destructor of SingleFailureChecker verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); -} - -DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultGlobalTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->listeners()->repeater()->OnTestPartResult(result); -} - -DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); -} - -// Returns the global test part result reporter. -TestPartResultReporterInterface* -UnitTestImpl::GetGlobalTestPartResultReporter() { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - return global_test_part_result_repoter_; -} - -// Sets the global test part result reporter. -void UnitTestImpl::SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter) { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - global_test_part_result_repoter_ = reporter; -} - -// Returns the test part result reporter for the current thread. -TestPartResultReporterInterface* -UnitTestImpl::GetTestPartResultReporterForCurrentThread() { - return per_thread_test_part_result_reporter_.get(); -} - -// Sets the test part result reporter for the current thread. -void UnitTestImpl::SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter) { - per_thread_test_part_result_reporter_.set(reporter); -} - -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); -} - -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); -} - -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); -} - -// Gets the number of successful tests. -int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); -} - -// Gets the number of failed tests. -int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); -} - -// Gets the number of disabled tests. -int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); -} - -// Gets the number of all tests. -int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); -} - -// Gets the number of tests that should run. -int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); -} - -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// CurrentOsStackTraceExceptTop(1), Foo() will be included in the -// trace but Bar() and CurrentOsStackTraceExceptTop() won't. -String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return String(""); -} - -// Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; - } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; -#ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -#pragma warning(pop) // Restores the warning state. -#else - _ftime64(&now); -#endif // _MSC_VER - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, NULL); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -#error "Don't know how to get the current time on your system." -#endif -} - -// Utilities - -// class String - -// Returns the input enclosed in double quotes if it's not NULL; -// otherwise returns "(null)". For example, "\"Hello\"" is returned -// for input "Hello". -// -// This is useful for printing a C string in the syntax of a literal. -// -// Known issue: escape sequences are not handled yet. -String String::ShowCStringQuoted(const char* c_str) { - return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); -} - -// Copies at most length characters from str into a newly-allocated -// piece of memory of size length+1. The memory is allocated with new[]. -// A terminating null byte is written to the memory, and a pointer to it -// is returned. If str is NULL, NULL is returned. -static char* CloneString(const char* str, size_t length) { - if (str == NULL) { - return NULL; - } else { - char* const clone = new char[length + 1]; - posix::StrNCpy(clone, str, length); - clone[length] = '\0'; - return clone; - } -} - -// Clones a 0-terminated C string, allocating memory using new. The -// caller is responsible for deleting[] the return value. Returns the -// cloned string, or NULL if the input is NULL. -const char * String::CloneCString(const char* c_str) { - return (c_str == NULL) ? - NULL : CloneString(c_str, strlen(c_str)); -} - -#if GTEST_OS_WINDOWS_MOBILE -// Creates a UTF-16 wide string from the given ANSI string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the wide string, or NULL if the -// input is NULL. -LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; - const int length = strlen(ansi); - const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); - WCHAR* unicode = new WCHAR[unicode_length + 1]; - MultiByteToWideChar(CP_ACP, 0, ansi, length, - unicode, unicode_length); - unicode[unicode_length] = 0; - return unicode; -} - -// Creates an ANSI string from the given wide string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the ANSI string, or NULL if the -// input is NULL. -const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); - char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); - ansi[ansi_length] = 0; - return ansi; -} - -#endif // GTEST_OS_WINDOWS_MOBILE - -// Compares two C strings. Returns true iff they have the same content. -// -// Unlike strcmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - - return strcmp(lhs, rhs) == 0; -} - -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -// Converts an array of wide chars to a narrow string using the UTF-8 -// encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, - Message* msg) { - // TODO(wan): consider allowing a testing::String object to - // contain '\0'. This will make it behave more like std::string, - // and will allow ToUtf8String() to return the correct encoding - // for '\0' s.t. we can get rid of the conditional here (and in - // several other places). - for (size_t i = 0; i != length; ) { // NOLINT - if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); - while (i != length && wstr[i] != L'\0') - i++; - } else { - *msg << '\0'; - i++; - } - } -} - -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -} // namespace internal - -#if GTEST_HAS_STD_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::std::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -namespace internal { - -// Formats a value to be used in a failure message. - -// For a char value, we print it as a C++ char literal and as an -// unsigned integer (both in decimal and in hexadecimal). -String FormatForFailureMessage(char ch) { - const unsigned int ch_as_uint = ch; - // A String object cannot contain '\0', so we print "\\0" when ch is - // '\0'. - return String::Format("'%s' (%u, 0x%X)", - ch ? String::Format("%c", ch).c_str() : "\\0", - ch_as_uint, ch_as_uint); -} - -// For a wchar_t value, we print it as a C++ wchar_t literal and as an -// unsigned integer (both in decimal and in hexidecimal). -String FormatForFailureMessage(wchar_t wchar) { - // The C++ standard doesn't specify the exact size of the wchar_t - // type. It just says that it shall have the same size as another - // integral type, called its underlying type. - // - // Therefore, in order to print a wchar_t value in the numeric form, - // we first convert it to the largest integral type (UInt64) and - // then print the converted value. - // - // We use streaming to print the value as "%llu" doesn't work - // correctly with MSVC 7.1. - const UInt64 wchar_as_uint64 = wchar; - Message msg; - // A String object cannot contain '\0', so we print "\\0" when wchar is - // L'\0'. - char buffer[32]; // CodePointToUtf8 requires a buffer that big. - msg << "L'" - << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") - << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) - << wchar_as_uint64 << ")"; - return msg.GetString(); -} - -} // namespace internal - -// AssertionResult constructors. -// Used in EXPECT_TRUE/FALSE(assertion_result). -AssertionResult::AssertionResult(const AssertionResult& other) - : success_(other.success_), - message_(other.message_.get() != NULL ? - new internal::String(*other.message_) : - static_cast(NULL)) { -} - -// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. -AssertionResult AssertionResult::operator!() const { - AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; - return negation; -} - -// Makes a successful assertion result. -AssertionResult AssertionSuccess() { - return AssertionResult(true); -} - -// Makes a failed assertion result. -AssertionResult AssertionFailure() { - return AssertionResult(false); -} - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << message. -AssertionResult AssertionFailure(const Message& message) { - return AssertionFailure() << message; -} - -namespace internal { - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const String& expected_value, - const String& actual_value, - bool ignoring_case) { - Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; - } - - msg << "\nExpected: " << expected_expression; - if (ignoring_case) { - msg << " (ignoring case)"; - } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; - } - - return AssertionFailure(msg); -} - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { - const char* actual_message = assertion_result.message(); - Message msg; - msg << "Value of: " << expression_text - << "\n Actual: " << actual_predicate_value; - if (actual_message[0] != '\0') - msg << " (" << actual_message << ")"; - msg << "\nExpected: " << expected_predicate_value; - return msg.GetString(); -} - -// Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { - const double diff = fabs(val1 - val2); - if (diff <= abs_error) return AssertionSuccess(); - - // TODO(wan): do not print the value of an expression if it's - // already a literal. - Message msg; - msg << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; - return AssertionFailure(msg); -} - - -// Helper template for implementing FloatLE() and DoubleLE(). -template -AssertionResult FloatingPointLE(const char* expr1, - const char* expr2, - RawType val1, - RawType val2) { - // Returns success if val1 is less than val2, - if (val1 < val2) { - return AssertionSuccess(); - } - - // or if val1 is almost equal to val2. - const FloatingPoint lhs(val1), rhs(val2); - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - // Note that the above two checks will both fail if either val1 or - // val2 is NaN, as the IEEE floating-point standard requires that - // any predicate involving a NaN must return false. - - StrStream val1_ss; - val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val1; - - StrStream val2_ss; - val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val2; - - Message msg; - msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StrStreamToString(&val1_ss) << " vs " - << StrStreamToString(&val2_ss); - - return AssertionFailure(msg); -} - -} // namespace internal - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -namespace internal { - -// The helper function for {ASSERT|EXPECT}_EQ with int or enum -// arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here -// just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - BiggestInt val1, BiggestInt val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - Message msg;\ - msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - return AssertionFailure(msg);\ - }\ -} - -// Implements the helper function for {ASSERT|EXPECT}_NE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(NE, !=) -// Implements the helper function for {ASSERT|EXPECT}_LE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LE, <=) -// Implements the helper function for {ASSERT|EXPECT}_LT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LT, < ) -// Implements the helper function for {ASSERT|EXPECT}_GE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GE, >=) -// Implements the helper function for {ASSERT|EXPECT}_GT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GT, > ) - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), - false); -} - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowCStringQuoted(expected), - String::ShowCStringQuoted(actual), - true); -} - -// The helper function for {ASSERT|EXPECT}_STRNE. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); - } -} - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CaseInsensitiveCStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << ") (ignoring case), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - return AssertionFailure(msg); - } -} - -} // namespace internal - -namespace { - -// Helper functions for implementing IsSubString() and IsNotSubstring(). - -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. - -bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return strstr(haystack, needle) != NULL; -} - -bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return wcsstr(haystack, needle) != NULL; -} - -// StringType here can be either ::std::string or ::std::wstring. -template -bool IsSubstringPred(const StringType& needle, - const StringType& haystack) { - return haystack.find(needle) != StringType::npos; -} - -// This function implements either IsSubstring() or IsNotSubstring(), -// depending on the value of the expected_to_be_substring parameter. -// StringType here can be const char*, const wchar_t*, ::std::string, -// or ::std::wstring. -template -AssertionResult IsSubstringImpl( - bool expected_to_be_substring, - const char* needle_expr, const char* haystack_expr, - const StringType& needle, const StringType& haystack) { - if (IsSubstringPred(needle, haystack) == expected_to_be_substring) - return AssertionSuccess(); - - const bool is_wide_string = sizeof(needle[0]) > 1; - const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure( - Message() - << "Value of: " << needle_expr << "\n" - << " Actual: " << begin_string_quote << needle << "\"\n" - << "Expected: " << (expected_to_be_substring ? "" : "not ") - << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""); -} - -} // namespace - -// IsSubstring() and IsNotSubstring() check whether needle is a -// substring of haystack (NULL is considered a substring of itself -// only), and return an appropriate error message when they fail. - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -#if GTEST_HAS_STD_WSTRING -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -#if GTEST_OS_WINDOWS - -namespace { - -// Helper function for IsHRESULT{SuccessFailure} predicates -AssertionResult HRESULTFailureHelper(const char* expr, - const char* expected, - long hr) { // NOLINT -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't support FormatMessage. - const char error_text[] = ""; -#else - // Looks up the human-readable system message for the HRESULT code - // and since we're not passing any params to FormatMessage, we don't - // want inserts expanded. - const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS; - const DWORD kBufSize = 4096; // String::Format can't exceed this length. - // Gets the system's human readable message string for this HRESULT. - char error_text[kBufSize] = { '\0' }; - DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions - error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts - // Trims tailing white space (FormatMessage leaves a trailing cr-lf) - for (; message_length && isspace(error_text[message_length - 1]); - --message_length) { - error_text[message_length - 1] = '\0'; - } -#endif // GTEST_OS_WINDOWS_MOBILE - - const String error_hex(String::Format("0x%08X ", hr)); - Message msg; - msg << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << error_text << "\n"; - - return ::testing::AssertionFailure(msg); -} - -} // namespace - -AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT - if (SUCCEEDED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "succeeds", hr); -} - -AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT - if (FAILED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "fails", hr); -} - -#endif // GTEST_OS_WINDOWS - -// Utility functions for encoding Unicode text (wide strings) in -// UTF-8. - -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 -// like this: -// -// Code-point length Encoding -// 0 - 7 bits 0xxxxxxx -// 8 - 11 bits 110xxxxx 10xxxxxx -// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx -// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - -// The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; - -// The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; - -// The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; - -// The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; - -// Chops off the n lowest bits from a bit pattern. Returns the n -// lowest bits. As a side effect, the original bit pattern will be -// shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); - *bits >>= n; - return low_bits; -} - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// The output buffer str must containt at least 32 characters. -// The function returns the address of the output buffer. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. -char* CodePointToUtf8(UInt32 code_point, char* str) { - if (code_point <= kMaxCodePoint1) { - str[1] = '\0'; - str[0] = static_cast(code_point); // 0xxxxxxx - } else if (code_point <= kMaxCodePoint2) { - str[2] = '\0'; - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xC0 | code_point); // 110xxxxx - } else if (code_point <= kMaxCodePoint3) { - str[3] = '\0'; - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xE0 | code_point); // 1110xxxx - } else if (code_point <= kMaxCodePoint4) { - str[4] = '\0'; - str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xF0 | code_point); // 11110xxx - } else { - // The longest string String::Format can produce when invoked - // with these parameters is 28 character long (not including - // the terminating nul character). We are asking for 32 character - // buffer just in case. This is also enough for strncpy to - // null-terminate the destination string. - posix::StrNCpy( - str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); - str[31] = '\0'; // Makes sure no change in the format to strncpy leaves - // the result unterminated. - } - return str; -} - -// The following two functions only make sense if the the system -// uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. - -// Determines if the arguments constitute UTF-16 surrogate pair -// and thus should be combined into a single Unicode code point -// using CreateCodePointFromUtf16SurrogatePair. -inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - return sizeof(wchar_t) == 2 && - (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; -} - -// Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); -} - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -String WideStringToUtf8(const wchar_t* str, int num_chars) { - if (num_chars == -1) - num_chars = static_cast(wcslen(str)); - - StrStream stream; - for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; - - if (str[i] == L'\0') { - break; - } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { - unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], - str[i + 1]); - i++; - } else { - unicode_code_point = static_cast(str[i]); - } - - char buffer[32]; // CodePointToUtf8 requires a buffer this big. - stream << CodePointToUtf8(unicode_code_point, buffer); - } - return StrStreamToString(&stream); -} - -// Converts a wide C string to a String using the UTF-8 encoding. -// NULL will be converted to "(null)". -String String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return String("(null)"); - - return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); -} - -// Similar to ShowWideCString(), except that this function encloses -// the converted string in double quotes. -String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { - if (wide_c_str == NULL) return String("(null)"); - - return String::Format("L\"%s\"", - String::ShowWideCString(wide_c_str).c_str()); -} - -// Compares two wide C strings. Returns true iff they have the same -// content. -// -// Unlike wcscmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - - return wcscmp(lhs, rhs) == 0; -} - -// Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - String::ShowWideCStringQuoted(expected), - String::ShowWideCStringQuoted(actual), - false); -} - -// Helper function for *_STRNE on wide strings. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2) { - if (!String::WideCStringEquals(s1, s2)) { - return AssertionSuccess(); - } - - Message msg; - msg << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << String::ShowWideCStringQuoted(s1) - << " vs " << String::ShowWideCStringQuoted(s2); - return AssertionFailure(msg); -} - -// Compares two C strings, ignoring case. Returns true iff they have -// the same content. -// -// Unlike strcasecmp(), this function can handle NULL argument(s). A -// NULL C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; - return posix::StrCaseCmp(lhs, rhs) == 0; -} - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. -bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - -#if GTEST_OS_WINDOWS - return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX - return wcscasecmp(lhs, rhs) == 0; -#else - // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes - // may not define it either. - wint_t left, right; - do { - left = towlower(*lhs++); - right = towlower(*rhs++); - } while (left && left == right); - return left == right; -#endif // OS selector -} - -// Compares this with another String. -// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 -// if this is greater than rhs. -int String::Compare(const String & rhs) const { - const char* const lhs_c_str = c_str(); - const char* const rhs_c_str = rhs.c_str(); - - if (lhs_c_str == NULL) { - return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL - } else if (rhs_c_str == NULL) { - return 1; - } - - const size_t shorter_str_len = - length() <= rhs.length() ? length() : rhs.length(); - for (size_t i = 0; i != shorter_str_len; i++) { - if (lhs_c_str[i] < rhs_c_str[i]) { - return -1; - } else if (lhs_c_str[i] > rhs_c_str[i]) { - return 1; - } - } - return (length() < rhs.length()) ? -1 : - (length() > rhs.length()) ? 1 : 0; -} - -// Returns true iff this String ends with the given suffix. *Any* -// String is considered to end with a NULL or empty suffix. -bool String::EndsWith(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CStringEquals(c_str() + this_len - suffix_len, suffix); -} - -// Returns true iff this String ends with the given suffix, ignoring case. -// Any String is considered to end with a NULL or empty suffix. -bool String::EndsWithCaseInsensitive(const char* suffix) const { - if (suffix == NULL || CStringEquals(suffix, "")) return true; - - if (c_str() == NULL) return false; - - const size_t this_len = strlen(c_str()); - const size_t suffix_len = strlen(suffix); - return (this_len >= suffix_len) && - CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); -} - -// Formats a list of arguments to a String, using the same format -// spec string as for printf. -// -// We do not use the StringPrintf class as it is not universally -// available. -// -// The result is limited to 4096 characters (including the tailing 0). -// If 4096 characters are not enough to format the input, or if -// there's an error, "" is -// returned. -String String::Format(const char * format, ...) { - va_list args; - va_start(args, format); - - char buffer[4096]; - const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); - - // MSVC 8 deprecates vsnprintf(), so we want to suppress warning - // 4996 (deprecated function) there. -#ifdef _MSC_VER // We are using MSVC. -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4996) // Temporarily disables warning 4996. - const int size = vsnprintf(buffer, kBufferSize, format, args); -#pragma warning(pop) // Restores the warning state. -#else // We are not using MSVC. - const int size = vsnprintf(buffer, kBufferSize, format, args); -#endif // _MSC_VER - va_end(args); - - // vsnprintf()'s behavior is not portable. When the buffer is not - // big enough, it returns a negative value in MSVC, and returns the - // needed buffer size on Linux. When there is an output error, it - // always returns a negative value. For simplicity, we lump the two - // error cases together. - if (size < 0 || size >= kBufferSize) { - return String(""); - } else { - return String(buffer, size); - } -} - -// Converts the buffer in a StrStream to a String, converting NUL -// bytes to "\\0" along the way. -String StrStreamToString(StrStream* ss) { - const ::std::string& str = ss->str(); - const char* const start = str.c_str(); - const char* const end = start + str.length(); - - // We need to use a helper StrStream to do this transformation - // because String doesn't support push_back(). - StrStream helper; - for (const char* ch = start; ch != end; ++ch) { - if (*ch == '\0') { - helper << "\\0"; // Replaces NUL with "\\0"; - } else { - helper.put(*ch); - } - } - - return String(helper.str().c_str()); -} - -// Appends the user-supplied message to the Google-Test-generated message. -String AppendUserMessage(const String& gtest_msg, - const Message& user_msg) { - // Appends the user message if it's non-empty. - const String user_msg_string = user_msg.GetString(); - if (user_msg_string.empty()) { - return gtest_msg; - } - - Message msg; - msg << gtest_msg << "\n" << user_msg_string; - - return msg.GetString(); -} - -} // namespace internal - -// class TestResult - -// Creates an empty TestResult. -TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} - -// D'tor. -TestResult::~TestResult() { -} - -// Returns the i-th test part result among all the results. i can -// range from 0 to total_part_count() - 1. If i is not in that range, -// aborts the program. -const TestPartResult& TestResult::GetTestPartResult(int i) const { - if (i < 0 || i >= total_part_count()) - internal::posix::Abort(); - return test_part_results_.at(i); -} - -// Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, aborts the -// program. -const TestProperty& TestResult::GetTestProperty(int i) const { - if (i < 0 || i >= test_property_count()) - internal::posix::Abort(); - return test_properties_.at(i); -} - -// Clears the test part results. -void TestResult::ClearTestPartResults() { - test_part_results_.clear(); -} - -// Adds a test part result to the list. -void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_.push_back(test_part_result); -} - -// Adds a test property to the list. If a property with the same key as the -// supplied property is already represented, the value of this test_property -// replaces the old value for that key. -void TestResult::RecordProperty(const TestProperty& test_property) { - if (!ValidateTestProperty(test_property)) { - return; - } - internal::MutexLock lock(&test_properites_mutex_); - const std::vector::iterator property_with_matching_key = - std::find_if(test_properties_.begin(), test_properties_.end(), - internal::TestPropertyKeyIs(test_property.key())); - if (property_with_matching_key == test_properties_.end()) { - test_properties_.push_back(test_property); - return; - } - property_with_matching_key->SetValue(test_property.value()); -} - -// Adds a failure if the key is a reserved attribute of Google Test -// testcase tags. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const TestProperty& test_property) { - internal::String key(test_property.key()); - if (key == "name" || key == "status" || key == "time" || key == "classname") { - ADD_FAILURE() - << "Reserved key used in RecordProperty(): " - << key - << " ('name', 'status', 'time', and 'classname' are reserved by " - << GTEST_NAME_ << ")"; - return false; - } - return true; -} - -// Clears the object. -void TestResult::Clear() { - test_part_results_.clear(); - test_properties_.clear(); - death_test_count_ = 0; - elapsed_time_ = 0; -} - -// Returns true iff the test failed. -bool TestResult::Failed() const { - for (int i = 0; i < total_part_count(); ++i) { - if (GetTestPartResult(i).failed()) - return true; - } - return false; -} - -// Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult& result) { - return result.fatally_failed(); -} - -// Returns true iff the test fatally failed. -bool TestResult::HasFatalFailure() const { - return CountIf(test_part_results_, TestPartFatallyFailed) > 0; -} - -// Returns true iff the test part non-fatally failed. -static bool TestPartNonfatallyFailed(const TestPartResult& result) { - return result.nonfatally_failed(); -} - -// Returns true iff the test has a non-fatal failure. -bool TestResult::HasNonfatalFailure() const { - return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; -} - -// Gets the number of all test parts. This is the sum of the number -// of successful test parts and the number of failed test parts. -int TestResult::total_part_count() const { - return static_cast(test_part_results_.size()); -} - -// Returns the number of the test properties. -int TestResult::test_property_count() const { - return static_cast(test_properties_.size()); -} - -// class Test - -// Creates a Test object. - -// The c'tor saves the values of all Google Test flags. -Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { -} - -// The d'tor restores the values of all Google Test flags. -Test::~Test() { - delete gtest_flag_saver_; -} - -// Sets up the test fixture. -// -// A sub-class may override this. -void Test::SetUp() { -} - -// Tears down the test fixture. -// -// A sub-class may override this. -void Test::TearDown() { -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, const char* value) { - UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const char* key, int value) { - Message value_message; - value_message << value; - RecordProperty(key, value_message.GetString().c_str()); -} - -namespace internal { - -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const String& message) { - // This function is a friend of UnitTest and as such has access to - // AddTestPartResult. - UnitTest::GetInstance()->AddTestPartResult( - result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. - message, - String()); // No stack trace, either. -} - -} // namespace internal - -#if GTEST_OS_WINDOWS -// We are on Windows. - -// Adds an "exception thrown" fatal failure to the current test. -static void AddExceptionThrownFailure(DWORD exception_code, - const char* location) { - Message message; - message << "Exception thrown with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " in " << location << "."; - - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - message.GetString()); -} - -#endif // GTEST_OS_WINDOWS - -// Google Test requires all tests in the same test case to use the same test -// fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If -// yes, it returns true; otherwise it generates a Google Test failure and -// returns false. -bool Test::HasSameFixtureClass() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); - - // Info about the first test in the current test case. - const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list()[0]->impl(); - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); - const char* const first_test_name = first_test_info->name(); - - // Info about the current test. - const internal::TestInfoImpl* const this_test_info = - impl->current_test_info()->impl(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); - const char* const this_test_name = this_test_info->name(); - - if (this_fixture_id != first_fixture_id) { - // Is the first test defined using TEST? - const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); - // Is this test defined using TEST? - const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); - - if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. - - // Gets the name of the TEST and the name of the TEST_F. Note - // that first_is_TEST and this_is_TEST cannot both be true, as - // the fixture IDs are different for the two tests. - const char* const TEST_name = - first_is_TEST ? first_test_name : this_test_name; - const char* const TEST_F_name = - first_is_TEST ? this_test_name : first_test_name; - - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() - << ",\n" - << "test " << TEST_F_name << " is defined using TEST_F but\n" - << "test " << TEST_name << " is defined using TEST. You probably\n" - << "want to change the TEST to TEST_F or move it to another test\n" - << "case."; - } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" - << "using two different test fixture classes. This can happen if\n" - << "the two classes are from different namespaces or translation\n" - << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; - } - return false; - } - - return true; -} - -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - SetUp(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); - } - - // We will run the test only if SetUp() had no fatal failure. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TestBody(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "the test body"); - } - } - - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - __try { - TearDown(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); - } - -#else // We are on a compiler or platform that doesn't support SEH. - impl->os_stack_trace_getter()->UponLeavingGTest(); - SetUp(); - - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - TestBody(); - } - - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - TearDown(); -#endif // GTEST_HAS_SEH -} - - -// Returns true iff the current test has a fatal failure. -bool Test::HasFatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); -} - -// Returns true iff the current test has a non-fatal failure. -bool Test::HasNonfatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()-> - HasNonfatalFailure(); -} - -// class TestInfo - -// Constructs a TestInfo object. It assumes ownership of the test factory -// object via impl_. -TestInfo::TestInfo(const char* a_test_case_name, - const char* a_name, - const char* a_test_case_comment, - const char* a_comment, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) { - impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, - a_test_case_comment, a_comment, - fixture_class_id, factory); -} - -// Destructs a TestInfo object. -TestInfo::~TestInfo() { - delete impl_; -} - -namespace internal { - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// test_case_comment: a comment on the test case that will be included in -// the test output -// comment: a comment on the test that will be included in the -// test output -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { - TestInfo* const test_info = - new TestInfo(test_case_name, name, test_case_comment, comment, - fixture_class_id, factory); - GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); - return test_info; -} - -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { - Message errors; - errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" - << "to define a test using a fixture class different from the one\n" - << "used earlier. This can happen if the two fixture classes are\n" - << "from different namespaces and have the same name. You should\n" - << "probably rename one of the classes to put the tests into different\n" - << "test cases."; - - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); -} -#endif // GTEST_HAS_PARAM_TEST - -} // namespace internal - -// Returns the test case name. -const char* TestInfo::test_case_name() const { - return impl_->test_case_name(); -} - -// Returns the test name. -const char* TestInfo::name() const { - return impl_->name(); -} - -// Returns the test case comment. -const char* TestInfo::test_case_comment() const { - return impl_->test_case_comment(); -} - -// Returns the test comment. -const char* TestInfo::comment() const { - return impl_->comment(); -} - -// Returns true if this test should run. -bool TestInfo::should_run() const { return impl_->should_run(); } - -// Returns true if this test matches the user-specified filter. -bool TestInfo::matches_filter() const { return impl_->matches_filter(); } - -// Returns the result of the test. -const TestResult* TestInfo::result() const { return impl_->result(); } - -// Increments the number of death tests encountered in this test so -// far. -int TestInfo::increment_death_test_count() { - return impl_->result()->increment_death_test_count(); -} - -namespace { - -// A predicate that checks the test name of a TestInfo against a known -// value. -// -// This is used for implementation of the TestCase class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestNameIs is copyable. -class TestNameIs { - public: - // Constructor. - // - // TestNameIs has NO default constructor. - explicit TestNameIs(const char* name) - : name_(name) {} - - // Returns true iff the test name of test_info matches name_. - bool operator()(const TestInfo * test_info) const { - return test_info && internal::String(test_info->name()).Compare(name_) == 0; - } - - private: - internal::String name_; -}; - -} // namespace - -namespace internal { - -// This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. -// This will be done just once during the program runtime. -void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST - if (!parameterized_tests_registered_) { - parameterized_test_registry_.RegisterTests(); - parameterized_tests_registered_ = true; - } -#endif -} - -// Creates the test object, runs it, records its result, and then -// deletes it. -void TestInfoImpl::Run() { - if (!should_run_) return; - - // Tells UnitTest where to store test result. - UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_info(parent_); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - // Notifies the unit test event listeners that a test is about to start. - repeater->OnTestStart(*parent_); - - const TimeInMillis start = GetTimeInMillis(); - - impl->os_stack_trace_getter()->UponLeavingGTest(); -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. - Test* test = NULL; - - __try { - // Creates the test object. - test = factory_->CreateTest(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - AddExceptionThrownFailure(GetExceptionCode(), - "the test fixture's constructor"); - return; - } -#else // We are on a compiler or platform that doesn't support SEH. - - // TODO(wan): If test->Run() throws, test won't be deleted. This is - // not a problem now as we don't use exceptions. If we were to - // enable exceptions, we should revise the following to be - // exception-safe. - - // Creates the test object. - Test* test = factory_->CreateTest(); -#endif // GTEST_HAS_SEH - - // Runs the test only if the constructor of the test fixture didn't - // generate a fatal failure. - if (!Test::HasFatalFailure()) { - test->Run(); - } - - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - delete test; - test = NULL; - - result_.set_elapsed_time(GetTimeInMillis() - start); - - // Notifies the unit test event listener that a test has just finished. - repeater->OnTestEnd(*parent_); - - // Tells UnitTest to stop associating assertion results to this - // test. - impl->set_current_test_info(NULL); -} - -} // namespace internal - -// class TestCase - -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { - return CountIf(test_info_list_, TestPassed); -} - -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { - return CountIf(test_info_list_, TestFailed); -} - -int TestCase::disabled_test_count() const { - return CountIf(test_info_list_, TestDisabled); -} - -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { - return CountIf(test_info_list_, ShouldRunTest); -} - -// Gets the number of all tests. -int TestCase::total_test_count() const { - return static_cast(test_info_list_.size()); -} - -// Creates a TestCase with the given name. -// -// Arguments: -// -// name: name of the test case -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_comment, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) - : name_(a_name), - comment_(a_comment), - set_up_tc_(set_up_tc), - tear_down_tc_(tear_down_tc), - should_run_(false), - elapsed_time_(0) { -} - -// Destructor of TestCase. -TestCase::~TestCase() { - // Deletes every Test in the collection. - ForEach(test_info_list_, internal::Delete); -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { - test_info_list_.push_back(test_info); - test_indices_.push_back(static_cast(test_indices_.size())); -} - -// Runs every test in this TestCase. -void TestCase::Run() { - if (!should_run_) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - repeater->OnTestCaseStart(*this); - impl->os_stack_trace_getter()->UponLeavingGTest(); - set_up_tc_(); - - const internal::TimeInMillis start = internal::GetTimeInMillis(); - for (int i = 0; i < total_test_count(); i++) { - GetMutableTestInfo(i)->impl()->Run(); - } - elapsed_time_ = internal::GetTimeInMillis() - start; - - impl->os_stack_trace_getter()->UponLeavingGTest(); - tear_down_tc_(); - repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); -} - -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { - ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); -} - -// Returns true iff test passed. -bool TestCase::TestPassed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Passed(); -} - -// Returns true iff test failed. -bool TestCase::TestFailed(const TestInfo * test_info) { - const internal::TestInfoImpl* const impl = test_info->impl(); - return impl->should_run() && impl->result()->Failed(); -} - -// Returns true iff test is disabled. -bool TestCase::TestDisabled(const TestInfo * test_info) { - return test_info->impl()->is_disabled(); -} - -// Returns true if the given test should run. -bool TestCase::ShouldRunTest(const TestInfo *test_info) { - return test_info->impl()->should_run(); -} - -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { - Shuffle(random, &test_indices_); -} - -// Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { - for (size_t i = 0; i < test_indices_.size(); i++) { - test_indices_[i] = static_cast(i); - } -} - -// Formats a countable noun. Depending on its quantity, either the -// singular form or the plural form is used. e.g. -// -// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". -// FormatCountableNoun(5, "book", "books") returns "5 books". -static internal::String FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { - return internal::String::Format("%d %s", count, - count == 1 ? singular_form : plural_form); -} - -// Formats the count of tests. -static internal::String FormatTestCount(int test_count) { - return FormatCountableNoun(test_count, "test", "tests"); -} - -// Formats the count of test cases. -static internal::String FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); -} - -// Converts a TestPartResult::Type enum to human-friendly string -// representation. Both kNonFatalFailure and kFatalFailure are translated -// to "Failure", as the user usually doesn't care about the difference -// between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResult::Type type) { - switch (type) { - case TestPartResult::kSuccess: - return "Success"; - - case TestPartResult::kNonFatalFailure: - case TestPartResult::kFatalFailure: -#ifdef _MSC_VER - return "error: "; -#else - return "Failure\n"; -#endif - } - - return "Unknown result type"; -} - -// Prints a TestPartResult to a String. -static internal::String PrintTestPartResultToString( - const TestPartResult& test_part_result) { - return (Message() - << internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()) - << " " << TestPartResultTypeToString(test_part_result.type()) - << test_part_result.message()).GetString(); -} - -// Prints a TestPartResult. -static void PrintTestPartResult(const TestPartResult& test_part_result) { - const internal::String& result = - PrintTestPartResultToString(test_part_result); - printf("%s\n", result.c_str()); - fflush(stdout); - // If the test program runs in Visual Studio or a debugger, the - // following statements add the test part result message to the Output - // window such that the user can double-click on it to jump to the - // corresponding source code location; otherwise they do nothing. -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - // We don't call OutputDebugString*() on Windows Mobile, as printing - // to stdout is done by OutputDebugString() there already - we don't - // want the same message printed twice. - ::OutputDebugStringA(result.c_str()); - ::OutputDebugStringA("\n"); -#endif -} - -// class PrettyUnitTestResultPrinter - -namespace internal { - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { - switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; - case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; - default: return 0; - } -} - -#else - -// Returns the ANSI color code for the given color. COLOR_DEFAULT is -// an invalid input. -const char* GetAnsiColorCode(GTestColor color) { - switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; - default: return NULL; - }; -} - -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns true iff Google Test should use colors in the output. -bool ShouldUseColor(bool stdout_is_tty) { - const char* const gtest_color = GTEST_FLAG(color).c_str(); - - if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS - // On Windows the TERM variable is usually not set, but the - // console there does support colors. - return stdout_is_tty; -#else - // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::GetEnv("TERM"); - const bool term_supports_color = - String::CStringEquals(term, "xterm") || - String::CStringEquals(term, "xterm-color") || - String::CStringEquals(term, "xterm-256color") || - String::CStringEquals(term, "linux") || - String::CStringEquals(term, "cygwin"); - return stdout_is_tty && term_supports_color; -#endif // GTEST_OS_WINDOWS - } - - return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || - String::CaseInsensitiveCStringEquals(gtest_color, "true") || - String::CaseInsensitiveCStringEquals(gtest_color, "t") || - String::CStringEquals(gtest_color, "1"); - // We take "yes", "true", "t", and "1" as meaning "yes". If the - // value is neither one of these nor "auto", we treat it as "no" to - // be conservative. -} - -// Helpers for printing colored strings to stdout. Note that on Windows, we -// cannot simply emit special characters and have the terminal change colors. -// This routine must actually emit the characters rather than return a string -// that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - const bool use_color = false; -#else - static const bool in_color_mode = - ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); - const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. - - if (!use_color) { - vprintf(fmt, args); - va_end(args); - return; - } - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); - - // Gets the current text color. - CONSOLE_SCREEN_BUFFER_INFO buffer_info; - GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); - const WORD old_color_attrs = buffer_info.wAttributes; - - // We need to flush the stream buffers into the console before each - // SetConsoleTextAttribute call lest it affect the text that is already - // printed but has not yet reached the console. - fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); - vprintf(fmt, args); - - fflush(stdout); - // Restores the text color. - SetConsoleTextAttribute(stdout_handle, old_color_attrs); -#else - printf("\033[0;3%sm", GetAnsiColorCode(color)); - vprintf(fmt, args); - printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - va_end(args); -} - -// This class implements the TestEventListener interface. -// -// Class PrettyUnitTestResultPrinter is copyable. -class PrettyUnitTestResultPrinter : public TestEventListener { - public: - PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); - } - - // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} - - private: - static void PrintFailedTests(const UnitTest& unit_test); - - internal::String test_case_name_; -}; - - // Fired before each iteration of tests starts. -void PrettyUnitTestResultPrinter::OnTestIterationStart( - const UnitTest& unit_test, int iteration) { - if (GTEST_FLAG(repeat) != 1) - printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); - - const char* const filter = GTEST_FLAG(filter).c_str(); - - // Prints the filter if it's not *. This reminds the user that some - // tests may be skipped. - if (!internal::String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); - } - - if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %s of %s.\n", - internal::posix::GetEnv(kTestShardIndex), - internal::posix::GetEnv(kTestTotalShards)); - } - - if (GTEST_FLAG(shuffle)) { - ColoredPrintf(COLOR_YELLOW, - "Note: Randomizing tests' orders with a seed of %d .\n", - unit_test.random_seed()); - } - - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("Running %s from %s.\n", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment set-up.\n"); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - test_case_name_ = test_case.name(); - const internal::String counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s", counts.c_str(), test_case_name_.c_str()); - if (test_case.comment()[0] == '\0') { - printf("\n"); - } else { - printf(", where %s\n", test_case.comment()); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_case_name_.c_str(), test_info.name()); - if (test_info.comment()[0] == '\0') { - printf("\n"); - } else { - printf(", where %s\n", test_info.comment()); - } - fflush(stdout); -} - -// Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { - if (test_info.result()->Passed()) { - ColoredPrintf(COLOR_GREEN, "[ OK ] "); - } else { - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - } - PrintTestName(test_case_name_.c_str(), test_info.name()); - if (GTEST_FLAG(print_time)) { - printf(" (%s ms)\n", internal::StreamableToString( - test_info.result()->elapsed_time()).c_str()); - } else { - printf("\n"); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { - if (!GTEST_FLAG(print_time)) return; - - test_case_name_ = test_case.name(); - const internal::String counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case_name_.c_str(), - internal::StreamableToString(test_case.elapsed_time()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment tear-down\n"); - fflush(stdout); -} - -// Internal helper for printing the list of failed tests. -void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { - const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { - continue; - } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { - continue; - } - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); - if (test_case.comment()[0] != '\0' || - test_info.comment()[0] != '\0') { - printf(", where %s", test_case.comment()); - if (test_case.comment()[0] != '\0' && - test_info.comment()[0] != '\0') { - printf(" and "); - } - } - printf("%s\n", test_info.comment()); - } - } -} - - void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("%s from %s ran.", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - if (GTEST_FLAG(print_time)) { - printf(" (%s ms total)", - internal::StreamableToString(unit_test.elapsed_time()).c_str()); - } - printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); - printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - - int num_failures = unit_test.failed_test_count(); - if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); - } - - int num_disabled = unit_test.disabled_test_count(); - if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { - printf("\n"); // Add a spacer if no FAILURE banner is displayed. - } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, - num_disabled == 1 ? "TEST" : "TESTS"); - } - // Ensure that Google Test output is printed before, e.g., heapchecker output. - fflush(stdout); -} - -// End PrettyUnitTestResultPrinter - -// class TestEventRepeater -// -// This class forwards events to other event listeners. -class TestEventRepeater : public TestEventListener { - public: - TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); - void Append(TestEventListener *listener); - TestEventListener* Release(TestEventListener* listener); - - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled() const { return forwarding_enabled_; } - void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); - - private: - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled_; - // The list of listeners that receive events. - std::vector listeners_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); -}; - -TestEventRepeater::~TestEventRepeater() { - ForEach(listeners_, Delete); -} - -void TestEventRepeater::Append(TestEventListener *listener) { - listeners_.push_back(listener); -} - -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. -TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { - for (size_t i = 0; i < listeners_.size(); ++i) { - if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); - return listener; - } - } - - return NULL; -} - -// Since most methods are very similar, use macros to reduce boilerplate. -// This defines a member that forwards the call to all listeners. -#define GTEST_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (size_t i = 0; i < listeners_.size(); i++) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} -// This defines a member that forwards the call to all listeners in reverse -// order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} - -GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) -GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) -GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) -GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) - -#undef GTEST_REPEATER_METHOD_ -#undef GTEST_REVERSE_REPEATER_METHOD_ - -void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (size_t i = 0; i < listeners_.size(); i++) { - listeners_[i]->OnTestIterationStart(unit_test, iteration); - } - } -} - -void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); - } - } -} - -// End TestEventRepeater - -// This class generates an XML output file. -class XmlUnitTestResultPrinter : public EmptyTestEventListener { - public: - explicit XmlUnitTestResultPrinter(const char* output_file); - - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - - private: - // Is c a whitespace character that is normalized to a space character - // when it appears in an XML attribute value? - static bool IsNormalizableWhitespace(char c) { - return c == 0x9 || c == 0xA || c == 0xD; - } - - // May c appear in a well-formed XML document? - static bool IsValidXmlCharacter(char c) { - return IsNormalizableWhitespace(c) || c >= 0x20; - } - - // Returns an XML-escaped copy of the input string str. If - // is_attribute is true, the text is meant to appear as an attribute - // value, and normalizable whitespace is preserved by replacing it - // with character references. - static String EscapeXml(const char* str, bool is_attribute); - - // Returns the given string with all characters invalid in XML removed. - static String RemoveInvalidXmlCharacters(const char* str); - - // Convenience wrapper around EscapeXml when str is an attribute value. - static String EscapeXmlAttribute(const char* str) { - return EscapeXml(str, true); - } - - // Convenience wrapper around EscapeXml when str is not an attribute value. - static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } - - // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. - static void OutputXmlCDataSection(::std::ostream* stream, const char* data); - - // Streams an XML representation of a TestInfo object. - static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); - - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(FILE* out, const TestCase& test_case); - - // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); - - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the String is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static String TestPropertiesAsXmlAttributes(const TestResult& result); - - // The output file. - const String output_file_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); -}; - -// Creates a new XmlUnitTestResultPrinter. -XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) - : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); - } -} - -// Called after the unit test ends. -void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } - PrintXmlUnitTest(xmlout, unit_test); - fclose(xmlout); -} - -// Returns an XML-escaped copy of the input string str. If is_attribute -// is true, the text is meant to appear as an attribute value, and -// normalizable whitespace is preserved by replacing it with character -// references. -// -// Invalid XML characters in str, if any, are stripped from the output. -// It is expected that most, if not all, of the text processed by this -// module will consist of ordinary English text. -// If this module is ever modified to produce version 1.1 XML output, -// most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. -String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { - Message m; - - if (str != NULL) { - for (const char* src = str; *src; ++src) { - switch (*src) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; - else - m << '"'; - break; - default: - if (IsValidXmlCharacter(*src)) { - if (is_attribute && IsNormalizableWhitespace(*src)) - m << String::Format("&#x%02X;", unsigned(*src)); - else - m << *src; - } - break; - } - } - } - - return m.GetString(); -} - -// Returns the given string with all characters invalid in XML removed. -// Currently invalid characters are dropped from the string. An -// alternative is to replace them with certain characters such as . or ?. -String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { - char* const output = new char[strlen(str) + 1]; - char* appender = output; - for (char ch = *str; ch != '\0'; ch = *++str) - if (IsValidXmlCharacter(ch)) - *appender++ = ch; - *appender = '\0'; - - String ret_value(output); - delete[] output; - return ret_value; -} - -// The following routines generate an XML representation of a UnitTest -// object. -// -// This is how Google Test concepts map to the DTD: -// -// <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object -// <-- corresponds to a TestInfo object -// ... -// ... -// ... -// <-- individual assertion failures -// -// -// - -// Formats the given time in milliseconds as seconds. -std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { - ::std::stringstream ss; - ss << ms/1000.0; - return ss.str(); -} - -// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, - const char* data) { - const char* segment = data; - *stream << ""); - if (next_segment != NULL) { - stream->write( - segment, static_cast(next_segment - segment)); - *stream << "]]>]]>"); - } else { - *stream << segment; - break; - } - } - *stream << "]]>"; -} - -// Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - *stream << " \n"; - *stream << " "; - const String message = RemoveInvalidXmlCharacters(String::Format( - "%s:%d\n%s", - part.file_name(), part.line_number(), - part.message()).c_str()); - OutputXmlCDataSection(stream, message.c_str()); - *stream << "\n"; - } - } - - if (failures == 0) - *stream << " />\n"; - else - *stream << " \n"; -} - -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, - const TestCase& test_case) { - fprintf(out, - " \n", - FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); - for (int i = 0; i < test_case.total_test_count(); ++i) { - StrStream stream; - OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); - fprintf(out, "%s", StrStreamToString(&stream).c_str()); - } - fprintf(out, " \n"); -} - -// Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, - const UnitTest& unit_test) { - fprintf(out, "\n"); - fprintf(out, - "\n"); - for (int i = 0; i < unit_test.total_test_case_count(); ++i) - PrintXmlTestCase(out, *unit_test.GetTestCase(i)); - fprintf(out, "\n"); -} - -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" - << "\"" << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - -// End XmlUnitTestResultPrinter - -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -// L < UnitTest::mutex_ -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -// L < UnitTest::mutex_ -ScopedTrace::~ScopedTrace() { - UnitTest::GetInstance()->PopGTestTrace(); -} - - -// class OsStackTraceGetter - -// Returns the current OS stack trace as a String. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -// L < mutex_ -// We use "L < mutex_" to denote that the function may acquire mutex_. -String OsStackTraceGetter::CurrentStackTrace(int, int) { - return String(""); -} - -// L < mutex_ -void OsStackTraceGetter::UponLeavingGTest() { -} - -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; - -} // namespace internal - -// class TestEventListeners - -TestEventListeners::TestEventListeners() - : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} - -TestEventListeners::~TestEventListeners() { delete repeater_; } - -// Returns the standard listener responsible for the default console -// output. Can be removed from the listeners list to shut down default -// console output. Note that removing this object from the listener list -// with Release transfers its ownership to the user. -void TestEventListeners::Append(TestEventListener* listener) { - repeater_->Append(listener); -} - -// Removes the given event listener from the list and returns it. It then -// becomes the caller's responsibility to delete the listener. Returns -// NULL if the listener is not found in the list. -TestEventListener* TestEventListeners::Release(TestEventListener* listener) { - if (listener == default_result_printer_) - default_result_printer_ = NULL; - else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; - return repeater_->Release(listener); -} - -// Returns repeater that broadcasts the TestEventListener events to all -// subscribers. -TestEventListener* TestEventListeners::repeater() { return repeater_; } - -// Sets the default_result_printer attribute to the provided listener. -// The listener is also added to the listener list and previous -// default_result_printer is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { - if (default_result_printer_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_result_printer_); - default_result_printer_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Sets the default_xml_generator attribute to the provided listener. The -// listener is also added to the listener list and previous -// default_xml_generator is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { - if (default_xml_generator_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_xml_generator_); - default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Controls whether events will be forwarded by the repeater to the -// listeners in the list. -bool TestEventListeners::EventForwardingEnabled() const { - return repeater_->forwarding_enabled(); -} - -void TestEventListeners::SuppressEventForwarding() { - repeater_->set_forwarding_enabled(false); -} - -// class UnitTest - -// Gets the singleton UnitTest object. The first time this method is -// called, a UnitTest object is constructed and returned. Consecutive -// calls will return the same object. -// -// We don't protect this under mutex_ as a user is not supposed to -// call this before main() starts, from which point on the return -// value will never change. -UnitTest * UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - - // CodeGear C++Builder insists on a public destructor for the - // default implementation. Use this implementation to keep good OO - // design with private destructor. - -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) - static UnitTest* const instance = new UnitTest; - return instance; -#else - static UnitTest instance; - return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) -} - -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); -} - -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); -} - -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); -} - -// Gets the number of successful tests. -int UnitTest::successful_test_count() const { - return impl()->successful_test_count(); -} - -// Gets the number of failed tests. -int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } - -// Gets the number of disabled tests. -int UnitTest::disabled_test_count() const { - return impl()->disabled_test_count(); -} - -// Gets the number of all tests. -int UnitTest::total_test_count() const { return impl()->total_test_count(); } - -// Gets the number of tests that should run. -int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } - -// Gets the elapsed time, in milliseconds. -internal::TimeInMillis UnitTest::elapsed_time() const { - return impl()->elapsed_time(); -} - -// Returns true iff the unit test passed (i.e. all test cases passed). -bool UnitTest::Passed() const { return impl()->Passed(); } - -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). -bool UnitTest::Failed() const { return impl()->Failed(); } - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -const TestCase* UnitTest::GetTestCase(int i) const { - return impl()->GetTestCase(i); -} - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); -} - -// Returns the list of event listeners that can be used to track events -// inside Google Test. -TestEventListeners& UnitTest::listeners() { - return *impl()->listeners(); -} - -// Registers and returns a global test environment. When a test -// program is run, all global test environments will be set-up in the -// order they were registered. After all tests in the program have -// finished, all global test environments will be torn-down in the -// *reverse* order they were registered. -// -// The UnitTest object takes ownership of the given environment. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; - } - - impl_->environments().push_back(env); - return env; -} - -#if GTEST_HAS_EXCEPTIONS -// A failed Google Test assertion will throw an exception of this type -// when exceptions are enabled. We derive it from std::runtime_error, -// which is for errors presumably detectable only at run time. Since -// std::runtime_error inherits from std::exception, many testing -// frameworks know how to extract and print the message inside it. -class GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} -}; -#endif - -// Adds a TestPartResult to the current TestResult object. All Google Test -// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call -// this to report their results. The user code should use the -// assertion macros instead of calling this directly. -// L < mutex_ -void UnitTest::AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const internal::String& message, - const internal::String& os_stack_trace) { - Message msg; - msg << message; - - internal::MutexLock lock(&mutex_); - if (impl_->gtest_trace_stack().size() > 0) { - msg << "\n" << GTEST_NAME_ << " trace:"; - - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { - const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; - msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) - << " " << trace.message; - } - } - - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << internal::kStackTraceMarker << os_stack_trace; - } - - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); - impl_->GetTestPartResultReporterForCurrentThread()-> - ReportTestPartResult(result); - - if (result_type != TestPartResult::kSuccess) { - // gtest_break_on_failure takes precedence over - // gtest_throw_on_failure. This allows a user to set the latter - // in the code (perhaps in order to use Google Test assertions - // with another testing framework) and specify the former on the - // command line for debugging. - if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS - // Using DebugBreak on Windows allows gtest to still break into a debugger - // when a failure happens and both the --gtest_break_on_failure and - // the --gtest_catch_exceptions flags are specified. - DebugBreak(); -#else - *static_cast(NULL) = 1; -#endif // GTEST_OS_WINDOWS - } else if (GTEST_FLAG(throw_on_failure)) { -#if GTEST_HAS_EXCEPTIONS - throw GoogleTestFailureException(result); -#else - // We cannot call abort() as it generates a pop-up in debug mode - // that cannot be suppressed in VC 7.1 or below. - exit(1); -#endif - } - } -} - -// Creates and adds a property to the current TestResult. If a property matching -// the supplied value already exists, updates its value instead. -void UnitTest::RecordPropertyForCurrentTest(const char* key, - const char* value) { - const TestProperty test_property(key, value); - impl_->current_test_result()->RecordProperty(test_property); -} - -// Runs all tests in this UnitTest object and prints the result. -// Returns 0 if successful, or 1 otherwise. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -int UnitTest::Run() { -#if GTEST_HAS_SEH - // Catch SEH-style exceptions. - - const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).length() > 0; - - // Either the user wants Google Test to catch exceptions thrown by the - // tests or this is executing in the context of death test child - // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected.. - if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { -#if !GTEST_OS_WINDOWS_MOBILE - // SetErrorMode doesn't exist on CE. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | - SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -#endif // !GTEST_OS_WINDOWS_MOBILE - -#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE - // Death test children can be terminated with _abort(). On Windows, - // _abort() can show a dialog with a warning message. This forces the - // abort message to go to stderr instead. - _set_error_mode(_OUT_TO_STDERR); -#endif - -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE - // In the debug version, Visual Studio pops up a separate dialog - // offering a choice to debug the aborted program. We need to suppress - // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement - // executed. Google Test will notify the user of any unexpected - // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. - if (!GTEST_FLAG(break_on_failure)) - _set_abort_behavior( - 0x0, // Clear the following flags: - _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -#endif - } - - __try { - return impl_->RunAllTests(); - } __except(internal::UnitTestOptions::GTestShouldProcessSEH( - GetExceptionCode())) { - printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); - fflush(stdout); - return 1; - } - -#else // We are on a compiler or platform that doesn't support SEH. - - return impl_->RunAllTests(); -#endif // GTEST_HAS_SEH -} - -// Returns the working directory when the first TEST() or TEST_F() was -// executed. -const char* UnitTest::original_working_dir() const { - return impl_->original_working_dir_.c_str(); -} - -// Returns the TestCase object for the test that's currently running, -// or NULL if no test is running. -// L < mutex_ -const TestCase* UnitTest::current_test_case() const { - internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); -} - -// Returns the TestInfo object for the test that's currently running, -// or NULL if no test is running. -// L < mutex_ -const TestInfo* UnitTest::current_test_info() const { - internal::MutexLock lock(&mutex_); - return impl_->current_test_info(); -} - -// Returns the random seed used at the start of the current test run. -int UnitTest::random_seed() const { return impl_->random_seed(); } - -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of -// value-parameterized tests and instantiate and register them. -// L < mutex_ -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() { - return impl_->parameterized_test_registry(); -} -#endif // GTEST_HAS_PARAM_TEST - -// Creates an empty UnitTest. -UnitTest::UnitTest() { - impl_ = new internal::UnitTestImpl(this); -} - -// Destructor of UnitTest. -UnitTest::~UnitTest() { - delete impl_; -} - -// Pushes a trace defined by SCOPED_TRACE() on to the per-thread -// Google Test trace stack. -// L < mutex_ -void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().push_back(trace); -} - -// Pops a trace from the per-thread Google Test trace stack. -// L < mutex_ -void UnitTest::PopGTestTrace() { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().pop_back(); -} - -namespace internal { - -UnitTestImpl::UnitTestImpl(UnitTest* parent) - : parent_(parent), -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER - global_test_part_result_repoter_( - &default_global_test_part_result_reporter_), - per_thread_test_part_result_reporter_( - &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST - parameterized_test_registry_(), - parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), - ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), - post_flag_parse_init_performed_(false), - random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. -#if GTEST_HAS_DEATH_TEST - elapsed_time_(0), - internal_run_death_test_flag_(NULL), - death_test_factory_(new DefaultDeathTestFactory) { -#else - elapsed_time_(0) { -#endif // GTEST_HAS_DEATH_TEST - listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); -} - -UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); - - // Deletes every Environment. - ForEach(environments_, internal::Delete); - - delete os_stack_trace_getter_; -} - -#if GTEST_HAS_DEATH_TEST -// Disables event forwarding if the control is currently in a death test -// subprocess. Must not be called before InitGoogleTest. -void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) - listeners()->SuppressEventForwarding(); -} -#endif // GTEST_HAS_DEATH_TEST - -// Initializes event listeners performing XML output as specified by -// UnitTestOptions. Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureXmlOutput() { - const String& output_format = UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( - UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } -} - -// Performs initialization dependent upon flag values obtained in -// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to -// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest -// this function is also called from RunAllTests. Since this function can be -// called more than once, it has to be idempotent. -void UnitTestImpl::PostFlagParsingInit() { - // Ensures that this function does not execute more than once. - if (!post_flag_parse_init_performed_) { - post_flag_parse_init_performed_ = true; - -#if GTEST_HAS_DEATH_TEST - InitDeathTestSubprocessControlInfo(); - SuppressTestEventsIfInSubprocess(); -#endif // GTEST_HAS_DEATH_TEST - - // Registers parameterized tests. This makes parameterized tests - // available to the UnitTest reflection API without running - // RUN_ALL_TESTS. - RegisterParameterizedTests(); - - // Configures listeners for XML output. This makes it possible for users - // to shut down the default XML output before invoking RUN_ALL_TESTS. - ConfigureXmlOutput(); - } -} - -// A predicate that checks the name of a TestCase against a known -// value. -// -// This is used for implementation of the UnitTest class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestCaseNameIs is copyable. -class TestCaseNameIs { - public: - // Constructor. - explicit TestCaseNameIs(const String& name) - : name_(name) {} - - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; - } - - private: - String name_; -}; - -// Finds and returns a TestCase with the given name. If one doesn't -// exist, creates one and returns it. It's the CALLER'S -// RESPONSIBILITY to ensure that this function is only called WHEN THE -// TESTS ARE NOT SHUFFLED. -// -// Arguments: -// -// test_case_name: name of the test case -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* comment, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; - - // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't - // been shuffled. Otherwise we may end up running a death test - // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); - } else { - // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); - } - - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; -} - -// Helpers for setting up / tearing down the given environment. They -// are for use in the ForEach() function. -static void SetUpEnvironment(Environment* env) { env->SetUp(); } -static void TearDownEnvironment(Environment* env) { env->TearDown(); } - -// Runs all tests in this UnitTest object, prints the result, and -// returns 0 if all tests are successful, or 1 otherwise. If any -// exception is thrown during a test on Windows, this test is -// considered to be failed, but the rest of the tests will still be -// run. (We disable exceptions on Linux and Mac OS X, so the issue -// doesn't apply there.) -// When parameterized tests are enabled, it expands and registers -// parameterized tests first in RegisterParameterizedTests(). -// All other functions called from RunAllTests() may safely assume that -// parameterized tests are ready to be counted and run. -int UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return 1; - } - - // Do not run any test if the --help flag was specified. - if (g_help_flag) - return 0; - - // Repeats the call to the post-flag parsing initialization in case the - // user didn't call InitGoogleTest. - PostFlagParsingInit(); - - // Even if sharding is not on, test runners may want to use the - // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding - // protocol. - internal::WriteToShardStatusFileIfNeeded(); - - // True iff we are in a subprocess for running a thread-safe-style - // death test. - bool in_subprocess_for_death_test = false; - -#if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); -#endif // GTEST_HAS_DEATH_TEST - - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, - in_subprocess_for_death_test); - - // Compares the full test names with the filter to decide which - // tests to run. - const bool has_tests_to_run = FilterTests(should_shard - ? HONOR_SHARDING_PROTOCOL - : IGNORE_SHARDING_PROTOCOL) > 0; - - // Lists the tests and exits if the --gtest_list_tests flag was specified. - if (GTEST_FLAG(list_tests)) { - // This must be called *after* FilterTests() has been called. - ListTestsMatchingFilter(); - return 0; - } - - random_seed_ = GTEST_FLAG(shuffle) ? - GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - - // True iff at least one test has failed. - bool failed = false; - - TestEventListener* repeater = listeners()->repeater(); - - repeater->OnTestProgramStart(*parent_); - - // How many times to repeat the tests? We don't want to repeat them - // when we are inside the subprocess of a death test. - const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); - // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { - ClearResult(); - - const TimeInMillis start = GetTimeInMillis(); - - // Shuffles test cases and tests if requested. - if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); - // This should be done before calling OnTestIterationStart(), - // such that a test event listener can see the actual test order - // in the event. - ShuffleTests(); - } - - // Tells the unit test event listeners that the tests are about to start. - repeater->OnTestIterationStart(*parent_, i); - - // Runs each test case if there is at least one test to run. - if (has_tests_to_run) { - // Sets up all environments beforehand. - repeater->OnEnvironmentsSetUpStart(*parent_); - ForEach(environments_, SetUpEnvironment); - repeater->OnEnvironmentsSetUpEnd(*parent_); - - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); - test_index++) { - GetMutableTestCase(test_index)->Run(); - } - } - - // Tears down all environments in reverse order afterwards. - repeater->OnEnvironmentsTearDownStart(*parent_); - std::for_each(environments_.rbegin(), environments_.rend(), - TearDownEnvironment); - repeater->OnEnvironmentsTearDownEnd(*parent_); - } - - elapsed_time_ = GetTimeInMillis() - start; - - // Tells the unit test event listener that the tests have just finished. - repeater->OnTestIterationEnd(*parent_, i); - - // Gets the result and clears it. - if (!Passed()) { - failed = true; - } - - // Restores the original test order after the iteration. This - // allows the user to quickly repro a failure that happens in the - // N-th iteration without repeating the first (N - 1) iterations. - // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in - // case the user somehow changes the value of the flag somewhere - // (it's always safe to unshuffle the tests). - UnshuffleTests(); - - if (GTEST_FLAG(shuffle)) { - // Picks a new random seed for each iteration. - random_seed_ = GetNextRandomSeed(random_seed_); - } - } - - repeater->OnTestProgramEnd(*parent_); - - // Returns 0 if all tests passed, or 1 other wise. - return failed ? 1 : 0; -} - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { - FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { - ColoredPrintf(COLOR_RED, - "Could not write to the test shard status file \"%s\" " - "specified by the %s environment variable.\n", - test_shard_file, kTestShardStatusFile); - fflush(stdout); - exit(EXIT_FAILURE); - } - fclose(file); - } -} - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (i.e., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_env, - const char* shard_index_env, - bool in_subprocess_for_death_test) { - if (in_subprocess_for_death_test) { - return false; - } - - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); - - if (total_shards == -1 && shard_index == -1) { - return false; - } else if (total_shards == -1 && shard_index != -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestShardIndex << " = " << shard_index - << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (total_shards != -1 && shard_index == -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestTotalShards << " = " << total_shards - << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (shard_index < 0 || shard_index >= total_shards) { - const Message msg = Message() - << "Invalid environment variables: we require 0 <= " - << kTestShardIndex << " < " << kTestTotalShards - << ", but you have " << kTestShardIndex << "=" << shard_index - << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } - - return total_shards > 1; -} - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error -// and aborts. -Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { - const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { - return default_val; - } - - Int32 result; - if (!ParseInt32(Message() << "The value of environment variable " << var, - str_val, &result)) { - exit(EXIT_FAILURE); - } - return result; -} - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { - return (test_id % total_shards) == shard_index; -} - -// Compares the name of each test with the user-specified filter to -// decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. -// If shard_tests == true, further filters tests based on sharding -// variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. -int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; - - // num_runnable_tests are the number of tests that will - // run across all shards (i.e., match filter and are not disabled). - // num_selected_tests are the number of tests to be run on - // this shard. - int num_runnable_tests = 0; - int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const String &test_case_name = test_case->name(); - test_case->set_should_run(false); - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; - const String test_name(test_info->name()); - // A test is disabled if test case name or test name matches - // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); - test_info->impl()->set_is_disabled(is_disabled); - - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); - test_info->impl()->set_matches_filter(matches_filter); - - const bool is_runnable = - (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && - matches_filter; - - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); - - num_runnable_tests += is_runnable; - num_selected_tests += is_selected; - - test_info->impl()->set_should_run(is_selected); - test_case->set_should_run(test_case->should_run() || is_selected); - } - } - return num_selected_tests; -} - -// Prints the names of the tests matching the user-specified filter flag. -void UnitTestImpl::ListTestsMatchingFilter() { - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; - if (test_info->matches_filter()) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.\n", test_case->name()); - } - printf(" %s\n", test_info->name()); - } - } - } - fflush(stdout); -} - -// Sets the OS stack trace getter. -// -// Does nothing if the input and the current OS stack trace getter are -// the same; otherwise, deletes the old getter and makes the input the -// current getter. -void UnitTestImpl::set_os_stack_trace_getter( - OsStackTraceGetterInterface* getter) { - if (os_stack_trace_getter_ != getter) { - delete os_stack_trace_getter_; - os_stack_trace_getter_ = getter; - } -} - -// Returns the current OS stack trace getter if it is not NULL; -// otherwise, creates an OsStackTraceGetter, makes it the current -// getter, and returns it. -OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { - os_stack_trace_getter_ = new OsStackTraceGetter; - } - - return os_stack_trace_getter_; -} - -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. -TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - current_test_info_->impl()->result() : &ad_hoc_test_result_; -} - -// Shuffles all test cases, and the tests within each test case, -// making sure that death tests are still run first. -void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); - - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); - - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); - } -} - -// Restores the test cases and tests to their order before the first shuffle. -void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); - } -} - -// TestInfoImpl constructor. The new instance assumes ownership of the test -// factory object. -TestInfoImpl::TestInfoImpl(TestInfo* parent, - const char* a_test_case_name, - const char* a_name, - const char* a_test_case_comment, - const char* a_comment, - TypeId a_fixture_class_id, - internal::TestFactoryBase* factory) : - parent_(parent), - test_case_name_(String(a_test_case_name)), - name_(String(a_name)), - test_case_comment_(String(a_test_case_comment)), - comment_(String(a_comment)), - fixture_class_id_(a_fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory) { -} - -// TestInfoImpl destructor. -TestInfoImpl::~TestInfoImpl() { - delete factory_; -} - -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, - int skip_count) { - // We pass skip_count + 1 to skip this wrapper function in addition - // to what the user really wants to skip. - return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); -} - -// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable -// code warnings. -namespace { -class ClassUniqueToAlwaysTrue {}; -} - -bool IsTrue(bool condition) { return condition; } - -bool AlwaysTrue() { -#if GTEST_HAS_EXCEPTIONS - // This condition is always false so AlwaysTrue() never actually throws, - // but it makes the compiler think that it may throw. - if (IsTrue(false)) - throw ClassUniqueToAlwaysTrue(); -#endif // GTEST_HAS_EXCEPTIONS - return true; -} - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { - const size_t prefix_len = strlen(prefix); - if (strncmp(*pstr, prefix, prefix_len) == 0) { - *pstr += prefix_len; - return true; - } - return false; -} - -// Parses a string as a command line flag. The string should have -// the format "--flag=value". When def_optional is true, the "=value" -// part can be omitted. -// -// Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { - // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; - - // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. - const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); - const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; - - // Skips the flag name. - const char* flag_end = str + flag_len; - - // When def_optional is true, it's OK to not have a "=value" part. - if (def_optional && (flag_end[0] == '\0')) { - return flag_end; - } - - // If def_optional is true and there are more characters after the - // flag name, or if def_optional is false, there must be a '=' after - // the flag name. - if (flag_end[0] != '=') return NULL; - - // Returns the string after "=". - return flag_end + 1; -} - -// Parses a string for a bool flag, in the form of either -// "--flag=value" or "--flag". -// -// In the former case, the value is taken as true as long as it does -// not start with '0', 'f', or 'F'. -// -// In the latter case, the value is taken as true. -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, true); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Converts the string value to a bool. - *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); - return true; -} - -// Parses a string for an Int32 flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - return ParseInt32(Message() << "The value of flag --" << flag, - value_str, value); -} - -// Parses a string for a string flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, String* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - *value = value_str; - return true; -} - -// Determines whether a string has a prefix that Google Test uses for its -// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. -// If Google Test detects that a command line flag has its prefix but is not -// recognized, it will print its help message. Flags starting with -// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test -// internal flags and do not trigger the help message. -static bool HasGoogleTestFlagPrefix(const char* str) { - return (SkipPrefix("--", &str) || - SkipPrefix("-", &str) || - SkipPrefix("/", &str)) && - !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && - (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || - SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); -} - -// Prints a string containing code-encoded text. The following escape -// sequences can be used in the string to control the text color: -// -// @@ prints a single '@' character. -// @R changes the color to red. -// @G changes the color to green. -// @Y changes the color to yellow. -// @D changes to the default terminal text color. -// -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. -static void PrintColorEncoded(const char* str) { - GTestColor color = COLOR_DEFAULT; // The current color. - - // Conceptually, we split the string into segments divided by escape - // sequences. Then we print one segment at a time. At the end of - // each iteration, the str pointer advances to the beginning of the - // next segment. - for (;;) { - const char* p = strchr(str, '@'); - if (p == NULL) { - ColoredPrintf(color, "%s", str); - return; - } - - ColoredPrintf(color, "%s", String(str, p - str).c_str()); - - const char ch = p[1]; - str = p + 2; - if (ch == '@') { - ColoredPrintf(color, "@"); - } else if (ch == 'D') { - color = COLOR_DEFAULT; - } else if (ch == 'R') { - color = COLOR_RED; - } else if (ch == 'G') { - color = COLOR_GREEN; - } else if (ch == 'Y') { - color = COLOR_YELLOW; - } else { - --str; - } - } -} - -static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" - "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -"\n" -"Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" -#if GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" -" Suppress pop-ups caused by exceptions.\n" -#endif // GTEST_OS_WINDOWS -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " - "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ - "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. The type parameter CharType can be -// instantiated to either char or wchar_t. -template -void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { - for (int i = 1; i < *argc; i++) { - const String arg_string = StreamableToString(argv[i]); - const char* const arg = arg_string.c_str(); - - using internal::ParseBoolFlag; - using internal::ParseInt32Flag; - using internal::ParseStringFlag; - - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note - // that argv has (*argc + 1) elements, the last one always being - // NULL. The following loop moves the trailing NULL element as - // well. - for (int j = i; j != *argc; j++) { - argv[j] = argv[j + 1]; - } - - // Decrements the argument count. - (*argc)--; - - // We also need to decrement the iterator as we just removed - // an element. - i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; - } - } - - if (g_help_flag) { - // We print the help here instead of in RUN_ALL_TESTS(), as the - // latter may not be called at all if the user is using Google - // Test with another testing framework. - PrintColorEncoded(kColorEncodedHelpMessage); - } -} - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} - -// The internal implementation of InitGoogleTest(). -// -// The type parameter CharType can be instantiated to either char or -// wchar_t. -template -void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; - - if (*argc <= 0) return; - - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - g_argvs.clear(); - for (int i = 0; i != *argc; i++) { - g_argvs.push_back(StreamableToString(argv[i])); - } -#endif // GTEST_HAS_DEATH_TEST - - ParseGoogleTestFlagsOnly(argc, argv); - GetUnitTestImpl()->PostFlagParsingInit(); -} - -} // namespace internal - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -void InitGoogleTest(int* argc, char** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -void InitGoogleTest(int* argc, wchar_t** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -} // namespace testing -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) -// -// This file implements death tests. - - -#if GTEST_HAS_DEATH_TEST - -#if GTEST_OS_MAC -#include -#endif // GTEST_OS_MAC - -#include -#include -#include -#include - -#if GTEST_OS_WINDOWS -#include -#else -#include -#include -#endif // GTEST_OS_WINDOWS - -#endif // GTEST_HAS_DEATH_TEST - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -// Constants. - -// The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; - -GTEST_DEFINE_string_( - death_test_style, - internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), - "Indicates how to run a death test in a forked child process: " - "\"threadsafe\" (child process re-executes the test binary " - "from the beginning, running only the specific death test) or " - "\"fast\" (child process runs the death test immediately " - "after forking)."); - -GTEST_DEFINE_bool_( - death_test_use_fork, - internal::BoolFromGTestEnv("death_test_use_fork", false), - "Instructs to use fork()/_exit() instead of clone() in death tests. " - "Ignored and always uses fork() on POSIX systems where clone() is not " - "implemented. Useful when running under valgrind or similar tools if " - "those do not support clone(). Valgrind 3.3.1 will just fail if " - "it sees an unsupported combination of clone() flags. " - "It is not recommended to use this flag w/o valgrind though it will " - "work in 99% of the cases. Once valgrind is fixed, this flag will " - "most likely be removed."); - -namespace internal { -GTEST_DEFINE_string_( - internal_run_death_test, "", - "Indicates the file, line number, temporal index of " - "the single death test to run, and a file descriptor to " - "which a success code may be sent, all separated by " - "colons. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " - "death test. FOR INTERNAL USE ONLY."); -} // namespace internal - -#if GTEST_HAS_DEATH_TEST - -// ExitedWithCode constructor. -ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { -} - -// ExitedWithCode function-call operator. -bool ExitedWithCode::operator()(int exit_status) const { -#if GTEST_OS_WINDOWS - return exit_status == exit_code_; -#else - return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -#endif // GTEST_OS_WINDOWS -} - -#if !GTEST_OS_WINDOWS -// KilledBySignal constructor. -KilledBySignal::KilledBySignal(int signum) : signum_(signum) { -} - -// KilledBySignal function-call operator. -bool KilledBySignal::operator()(int exit_status) const { - return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; -} -#endif // !GTEST_OS_WINDOWS - -namespace internal { - -// Utilities needed for death tests. - -// Generates a textual description of a given exit code, in the format -// specified by wait(2). -static String ExitSummary(int exit_code) { - Message m; -#if GTEST_OS_WINDOWS - m << "Exited with exit status " << exit_code; -#else - if (WIFEXITED(exit_code)) { - m << "Exited with exit status " << WEXITSTATUS(exit_code); - } else if (WIFSIGNALED(exit_code)) { - m << "Terminated by signal " << WTERMSIG(exit_code); - } -#ifdef WCOREDUMP - if (WCOREDUMP(exit_code)) { - m << " (core dumped)"; - } -#endif -#endif // GTEST_OS_WINDOWS - return m.GetString(); -} - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -bool ExitedUnsuccessfully(int exit_status) { - return !ExitedWithCode(0)(exit_status); -} - -#if !GTEST_OS_WINDOWS -// Generates a textual failure message when a death test finds more than -// one thread running, or cannot determine the number of threads, prior -// to executing the given statement. It is the responsibility of the -// caller not to pass a thread_count of 1. -static String DeathTestThreadWarning(size_t thread_count) { - Message msg; - msg << "Death tests use fork(), which is unsafe particularly" - << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) - msg << "couldn't detect the number of threads."; - else - msg << "detected " << thread_count << " threads."; - return msg.GetString(); -} -#endif // !GTEST_OS_WINDOWS - -// Flag characters for reporting a death test that did not die. -static const char kDeathTestLived = 'L'; -static const char kDeathTestReturned = 'R'; -static const char kDeathTestInternalError = 'I'; - -// An enumeration describing all of the possible ways that a death test -// can conclude. DIED means that the process died while executing the -// test code; LIVED means that process lived beyond the end of the test -// code; and RETURNED means that the test statement attempted a "return," -// which is not allowed. IN_PROGRESS means the test has not yet -// concluded. -enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; - -// Routine for aborting the program which is safe to call from an -// exec-style death test child process, in which case the error -// message is propagated back to the parent process. Otherwise, the -// message is simply printed to stderr. In either case, the program -// then exits with status 1. -void DeathTestAbort(const String& message) { - // On a POSIX system, this function may be called from a threadsafe-style - // death test child process, which operates on a very small stack. Use - // the heap for any additional non-minuscule memory requirements. - const InternalRunDeathTestFlag* const flag = - GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { - FILE* parent = posix::FDOpen(flag->write_fd(), "w"); - fputc(kDeathTestInternalError, parent); - fprintf(parent, "%s", message.c_str()); - fflush(parent); - _exit(1); - } else { - fprintf(stderr, "%s", message.c_str()); - fflush(stderr); - abort(); - } -} - -// A replacement for CHECK that calls DeathTestAbort if the assertion -// fails. -#define GTEST_DEATH_TEST_CHECK_(expression) \ - do { \ - if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s", \ - __FILE__, __LINE__, #expression)); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for -// evaluating any system call that fulfills two conditions: it must return -// -1 on failure, and set errno to EINTR when it is interrupted and -// should be tried again. The macro expands to a loop that repeatedly -// evaluates the expression as long as it evaluates to -1 and sets -// errno to EINTR. If the expression evaluates to -1 but errno is -// something other than EINTR, DeathTestAbort is called. -#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ - do { \ - int gtest_retval; \ - do { \ - gtest_retval = (expression); \ - } while (gtest_retval == -1 && errno == EINTR); \ - if (gtest_retval == -1) { \ - DeathTestAbort(::testing::internal::String::Format( \ - "CHECK failed: File %s, line %d: %s != -1", \ - __FILE__, __LINE__, #expression)); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// Returns the message describing the last system error in errno. -String GetLastErrnoDescription() { - return String(errno == 0 ? "" : posix::StrError(errno)); -} - -// This is called from a death test parent process to read a failure -// message from the death test child process and log it with the FATAL -// severity. On Windows, the message is read from a pipe handle. On other -// platforms, it is read from a file descriptor. -static void FailFromInternalError(int fd) { - Message error; - char buffer[256]; - int num_read; - - do { - while ((num_read = posix::Read(fd, buffer, 255)) > 0) { - buffer[num_read] = '\0'; - error << buffer; - } - } while (num_read == -1 && errno == EINTR); - - if (num_read == 0) { - GTEST_LOG_(FATAL) << error.GetString(); - } else { - const int last_error = errno; - GTEST_LOG_(FATAL) << "Error while reading death test internal: " - << GetLastErrnoDescription() << " [" << last_error << "]"; - } -} - -// Death test constructor. Increments the running death test count -// for the current test. -DeathTest::DeathTest() { - TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { - DeathTestAbort("Cannot run a death test outside of a TEST or " - "TEST_F construct"); - } -} - -// Creates and returns a death test by dispatching to the current -// death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { - return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); -} - -const char* DeathTest::LastMessage() { - return last_death_test_message_.c_str(); -} - -void DeathTest::set_last_death_test_message(const String& message) { - last_death_test_message_ = message; -} - -String DeathTest::last_death_test_message_; - -// Provides cross platform implementation for some death functionality. -class DeathTestImpl : public DeathTest { - protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) - : statement_(a_statement), - regex_(a_regex), - spawned_(false), - status_(-1), - outcome_(IN_PROGRESS), - read_fd_(-1), - write_fd_(-1) {} - - // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); - - const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } - bool spawned() const { return spawned_; } - void set_spawned(bool is_spawned) { spawned_ = is_spawned; } - int status() const { return status_; } - void set_status(int a_status) { status_ = a_status; } - DeathTestOutcome outcome() const { return outcome_; } - void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } - int read_fd() const { return read_fd_; } - void set_read_fd(int fd) { read_fd_ = fd; } - int write_fd() const { return write_fd_; } - void set_write_fd(int fd) { write_fd_ = fd; } - - // Called in the parent process only. Reads the result code of the death - // test child process via a pipe, interprets it to set the outcome_ - // member, and closes read_fd_. Outputs diagnostics and terminates in - // case of unexpected codes. - void ReadAndInterpretStatusByte(); - - private: - // The textual content of the code this object is testing. This class - // doesn't own this string and should not attempt to delete it. - const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; - // True if the death test child process has been successfully spawned. - bool spawned_; - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; - // Descriptor to the read end of the pipe to the child process. It is - // always -1 in the child process. The child keeps its write end of the - // pipe in write_fd_. - int read_fd_; - // Descriptor to the child's write end of the pipe to the parent process. - // It is always -1 in the parent process. The parent keeps its end of the - // pipe in read_fd_. - int write_fd_; -}; - -// Called in the parent process only. Reads the result code of the death -// test child process via a pipe, interprets it to set the outcome_ -// member, and closes read_fd_. Outputs diagnostics and terminates in -// case of unexpected codes. -void DeathTestImpl::ReadAndInterpretStatusByte() { - char flag; - int bytes_read; - - // The read() here blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before - // the child process has exited. - do { - bytes_read = posix::Read(read_fd(), &flag, 1); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_fd()); // Does not return. - break; - default: - GTEST_LOG_(FATAL) << "Death test child process reported " - << "unexpected status byte (" - << static_cast(flag) << ")"; - } - } else { - GTEST_LOG_(FATAL) << "Read from death test child process failed: " - << GetLastErrnoDescription(); - } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); - set_read_fd(-1); -} - -// Signals that the death test code which should have exited, didn't. -// Should be called only in a death test child process. -// Writes a status byte to the child's status file descriptor, then -// calls _exit(1). -void DeathTestImpl::Abort(AbortReason reason) { - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} - -// Assesses the success or failure of a death test, using both private -// members which have previously been set, and one argument: -// -// Private data members: -// outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, or RETURNED. The death test fails -// in the latter two cases. -// status: The exit status of the child process. On *nix, it is in the -// in the format specified by wait(2). On Windows, this is the -// value supplied to the ExitProcess() API or a numeric code -// of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. -// -// Argument: -// status_ok: true if exit_status is acceptable in the context of -// this particular death test, which fails if it is false -// -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is -// reported. Also sets the last death test message string. -bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; - - const String error_message = GetCapturedStderr(); - - bool success = false; - Message buffer; - - buffer << "Death test: " << statement() << "\n"; - switch (outcome()) { - case LIVED: - buffer << " Result: failed to die.\n" - << " Error msg: " << error_message; - break; - case RETURNED: - buffer << " Result: illegal return in test statement.\n" - << " Error msg: " << error_message; - break; - case DIED: - if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { - success = true; - } else { - buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg: " << error_message; - } - } else { - buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n"; - } - break; - case IN_PROGRESS: - default: - GTEST_LOG_(FATAL) - << "DeathTest::Passed somehow called before conclusion of test"; - } - - DeathTest::set_last_death_test_message(buffer.GetString()); - return success; -} - -#if GTEST_OS_WINDOWS -// WindowsDeathTest implements death tests on Windows. Due to the -// specifics of starting new processes on Windows, death tests there are -// always threadsafe, and Google Test considers the -// --gtest_death_test_style=fast setting to be equivalent to -// --gtest_death_test_style=threadsafe there. -// -// A few implementation notes: Like the Linux version, the Windows -// implementation uses pipes for child-to-parent communication. But due to -// the specifics of pipes on Windows, some extra steps are required: -// -// 1. The parent creates a communication pipe and stores handles to both -// ends of it. -// 2. The parent starts the child and provides it with the information -// necessary to acquire the handle to the write end of the pipe. -// 3. The child acquires the write end of the pipe and signals the parent -// using a Windows event. -// 4. Now the parent can release the write end of the pipe on its side. If -// this is done before step 3, the object's reference count goes down to -// 0 and it is destroyed, preventing the child from acquiring it. The -// parent now has to release it, or read operations on the read end of -// the pipe will not return when the child terminates. -// 5. The parent reads child's output through the pipe (outcome code and -// any possible error messages) from the pipe, and its stderr and then -// determines whether to fail the test. -// -// Note: to distinguish Win32 API calls from the local method and function -// calls, the former are explicitly resolved in the global namespace. -// -class WindowsDeathTest : public DeathTestImpl { - public: - WindowsDeathTest(const char* statement, - const RE* regex, - const char* file, - int line) - : DeathTestImpl(statement, regex), file_(file), line_(line) {} - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); - - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; - // Handle to the write end of the pipe to the child process. - AutoHandle write_handle_; - // Child process handle. - AutoHandle child_handle_; - // Event the child process uses to signal the parent that it has - // acquired the handle to the write end of the pipe. After seeing this - // event the parent can release its own handles to make sure its - // ReadFile() calls return when the child terminates. - AutoHandle event_handle_; -}; - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int WindowsDeathTest::Wait() { - if (!spawned()) - return 0; - - // Wait until the child either signals that it has acquired the write end - // of the pipe or it dies. - const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; - switch (::WaitForMultipleObjects(2, - wait_handles, - FALSE, // Waits for any of the handles. - INFINITE)) { - case WAIT_OBJECT_0: - case WAIT_OBJECT_0 + 1: - break; - default: - GTEST_DEATH_TEST_CHECK_(false); // Should not get here. - } - - // The child has acquired the write end of the pipe or exited. - // We release the handle on our side and continue. - write_handle_.Reset(); - event_handle_.Reset(); - - ReadAndInterpretStatusByte(); - - // Waits for the child process to exit if it haven't already. This - // returns immediately if the child has already exited, regardless of - // whether previous calls to WaitForMultipleObjects synchronized on this - // handle or not. - GTEST_DEATH_TEST_CHECK_( - WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), - INFINITE)); - DWORD status; - GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) - != FALSE); - child_handle_.Reset(); - set_status(static_cast(status)); - return this->status(); -} - -// The AssumeRole process for a Windows death test. It creates a child -// process with the same executable as the current process to run the -// death test. The child process is given the --gtest_filter and -// --gtest_internal_run_death_test flags such that it knows to run the -// current death test only. -DeathTest::TestRole WindowsDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - // ParseInternalRunDeathTestFlag() has performed all the necessary - // processing. - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - // WindowsDeathTest uses an anonymous pipe to communicate results of - // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_( - ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, - 0) // Default buffer size. - != FALSE); - set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), - O_RDONLY)); - write_handle_.Reset(write_handle); - event_handle_.Reset(::CreateEvent( - &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const String filter_flag = String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), - info->name()); - const String internal_flag = String::Format( - "--%s%s=%s|%d|%d|%u|%Iu|%Iu", - GTEST_FLAG_PREFIX_, - kInternalRunDeathTestFlag, - file_, line_, - death_test_index, - static_cast(::GetCurrentProcessId()), - // size_t has the same with as pointers on both 32-bit and 64-bit - // Windows platforms. - // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - reinterpret_cast(write_handle), - reinterpret_cast(event_handle_.Get())); - - char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); - - String command_line = String::Format("%s %s \"%s\"", - ::GetCommandLineA(), - filter_flag.c_str(), - internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // Flush the log buffers since the log streams are shared with the child. - FlushInfoLog(); - - // The child process will share the standard handles with the parent. - STARTUPINFOA startup_info; - memset(&startup_info, 0, sizeof(STARTUPINFO)); - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); - startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); - - PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); - child_handle_.Reset(process_info.hProcess); - ::CloseHandle(process_info.hThread); - set_spawned(true); - return OVERSEE_TEST; -} -#else // We are not on Windows. - -// ForkingDeathTest provides implementations for most of the abstract -// methods of the DeathTest interface. Only the AssumeRole method is -// left undefined. -class ForkingDeathTest : public DeathTestImpl { - public: - ForkingDeathTest(const char* statement, const RE* regex); - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - - protected: - void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } - - private: - // PID of child process during death test; 0 in the child process itself. - pid_t child_pid_; -}; - -// Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int ForkingDeathTest::Wait() { - if (!spawned()) - return 0; - - ReadAndInterpretStatusByte(); - - int status_value; - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); - set_status(status_value); - return status_value; -} - -// A concrete death test class that forks, then immediately runs the test -// in the child process. -class NoExecDeathTest : public ForkingDeathTest { - public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); -}; - -// The AssumeRole process for a fork-and-run death test. It implements a -// straightforward fork, with a simple pipe to transmit the status byte. -DeathTest::TestRole NoExecDeathTest::AssumeRole() { - const size_t thread_count = GetThreadCount(); - if (thread_count != 1) { - GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - - DeathTest::set_last_death_test_message(""); - CaptureStderr(); - // When we fork the process below, the log file buffers are copied, but the - // file descriptors are shared. We flush all log files here so that closing - // the file descriptors in the child process doesn't throw off the - // synchronization between descriptors and buffers in the parent process. - // This is as close to the fork as possible to avoid a race condition in case - // there are multiple threads running before the death test, and another - // thread writes to the log file. - FlushInfoLog(); - - const pid_t child_pid = fork(); - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - set_child_pid(child_pid); - if (child_pid == 0) { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); - set_write_fd(pipe_fd[1]); - // Redirects all logging to stderr in the child process to prevent - // concurrent writes to the log files. We capture stderr in the parent - // process and append the child process' output to a log. - LogToStderr(); - // Event forwarding to the listeners of event listener API mush be shut - // down in death test subprocesses. - GetUnitTestImpl()->listeners()->SuppressEventForwarding(); - return EXECUTE_TEST; - } else { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; - } -} - -// A concrete death test class that forks and re-executes the main -// program from the beginning, with command-line flags set that cause -// only this specific death test to be run. -class ExecDeathTest : public ForkingDeathTest { - public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; -}; - -// Utility class for accumulating command-line arguments. -class Arguments { - public: - Arguments() { - args_.push_back(NULL); - } - - ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); - ++i) { - free(*i); - } - } - void AddArgument(const char* argument) { - args_.insert(args_.end() - 1, posix::StrDup(argument)); - } - - template - void AddArguments(const ::std::vector& arguments) { - for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { - args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); - } - } - char* const* Argv() { - return &args_[0]; - } - private: - std::vector args_; -}; - -// A struct that encompasses the arguments to the child process of a -// threadsafe-style death test process. -struct ExecDeathTestArgs { - char* const* argv; // Command-line arguments for the child's call to exec - int close_fd; // File descriptor to close; the read end of a pipe -}; - -#if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -#else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. -extern "C" char** environ; -inline char** GetEnviron() { return environ; } -#endif // GTEST_OS_MAC - -// The main function for a threadsafe-style death test child process. -// This function is called in a clone()-ed process and thus must avoid -// any potentially unsafe operations like malloc or libc functions. -static int ExecDeathTestChildMain(void* child_arg) { - ExecDeathTestArgs* const args = static_cast(child_arg); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); - - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", - original_dir, - GetLastErrnoDescription().c_str())); - return EXIT_FAILURE; - } - - // We can safely call execve() as it's a direct system call. We - // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must - // invoke the test program via a valid path that contains at least - // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", - args->argv[0], - original_dir, - GetLastErrnoDescription().c_str())); - return EXIT_FAILURE; -} - -// Two utility routines that together determine the direction the stack -// grows. -// This could be accomplished more elegantly by a single recursive -// function, but we want to guard against the unlikely possibility of -// a smart compiler optimizing the recursion away. -bool StackLowerThanAddress(const void* ptr) { - int dummy; - return &dummy < ptr; -} - -bool StackGrowsDown() { - int dummy; - return StackLowerThanAddress(&dummy); -} - -// A threadsafe implementation of fork(2) for threadsafe-style death tests -// that uses clone(2). It dies with an error message if anything goes -// wrong. -static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { - ExecDeathTestArgs args = { argv, close_fd }; - pid_t child_pid = -1; - -#if GTEST_HAS_CLONE - const bool use_fork = GTEST_FLAG(death_test_use_fork); - - if (!use_fork) { - static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); - // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); - void* const stack_top = - static_cast(stack) + (stack_grows_down ? stack_size : 0); - - child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); - - GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); - } -#else - const bool use_fork = true; -#endif // GTEST_HAS_CLONE - - if (use_fork && (child_pid = fork()) == 0) { - ExecDeathTestChildMain(&args); - _exit(0); - } - - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - return child_pid; -} - -// The AssumeRole process for a fork-and-exec death test. It re-executes the -// main program from the beginning, setting the --gtest_filter -// and --gtest_internal_run_death_test flags to cause only the current -// death test to be re-run. -DeathTest::TestRole ExecDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - // Clear the close-on-exec flag on the write end of the pipe, lest - // it be closed when the child process does an exec: - GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - - const String filter_flag = - String::Format("--%s%s=%s.%s", - GTEST_FLAG_PREFIX_, kFilterFlag, - info->test_case_name(), info->name()); - const String internal_flag = - String::Format("--%s%s=%s|%d|%d|%d", - GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, - file_, line_, death_test_index, pipe_fd[1]); - Arguments args; - args.AddArguments(GetArgvs()); - args.AddArgument(filter_flag.c_str()); - args.AddArgument(internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // See the comment in NoExecDeathTest::AssumeRole for why the next line - // is necessary. - FlushInfoLog(); - - const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_child_pid(child_pid); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; -} - -#endif // !GTEST_OS_WINDOWS - -// Creates a concrete DeathTest-derived class that depends on the -// --gtest_death_test_style flag, and sets the pointer pointed to -// by the "test" argument to its address. If the test should be -// skipped, sets that pointer to NULL. Returns true, unless the -// flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, - const char* file, int line, - DeathTest** test) { - UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const int death_test_index = impl->current_test_info() - ->increment_death_test_count(); - - if (flag != NULL) { - if (death_test_index > flag->index()) { - DeathTest::set_last_death_test_message(String::Format( - "Death test count (%d) somehow exceeded expected maximum (%d)", - death_test_index, flag->index())); - return false; - } - - if (!(flag->file() == file && flag->line() == line && - flag->index() == death_test_index)) { - *test = NULL; - return true; - } - } - -#if GTEST_OS_WINDOWS - if (GTEST_FLAG(death_test_style) == "threadsafe" || - GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); - } -#else - if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); - } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); - } -#endif // GTEST_OS_WINDOWS - else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message(String::Format( - "Unknown death test style \"%s\" encountered", - GTEST_FLAG(death_test_style).c_str())); - return false; - } - - return true; -} - -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - -#if GTEST_OS_WINDOWS -// Recreates the pipe and event handles from the provided parameters, -// signals the event, and returns a file descriptor wrapped around the pipe -// handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t write_handle_as_size_t, - size_t event_handle_as_size_t) { - AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, - FALSE, // Non-inheritable. - parent_process_id)); - if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { - DeathTestAbort(String::Format("Unable to open parent process %u", - parent_process_id)); - } - - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. - GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - - const HANDLE write_handle = - reinterpret_cast(write_handle_as_size_t); - HANDLE dup_write_handle; - - // The newly initialized handle is accessible only in in the parent - // process. To obtain one accessible within the child, we need to use - // DuplicateHandle. - if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, - ::GetCurrentProcess(), &dup_write_handle, - 0x0, // Requested privileges ignored since - // DUPLICATE_SAME_ACCESS is used. - FALSE, // Request non-inheritable handler. - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the pipe handle %Iu from the parent process %u", - write_handle_as_size_t, parent_process_id)); - } - - const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); - HANDLE dup_event_handle; - - if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, - ::GetCurrentProcess(), &dup_event_handle, - 0x0, - FALSE, - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort(String::Format( - "Unable to duplicate the event handle %Iu from the parent process %u", - event_handle_as_size_t, parent_process_id)); - } - - const int write_fd = - ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); - if (write_fd == -1) { - DeathTestAbort(String::Format( - "Unable to convert pipe handle %Iu to a file descriptor", - write_handle_as_size_t)); - } - - // Signals the parent that the write end of the pipe has been acquired - // so the parent can release its own write end. - ::SetEvent(dup_event_handle); - - return write_fd; -} -#endif // GTEST_OS_WINDOWS - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; - - // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we - // can use it here. - int line = -1; - int index = -1; - ::std::vector< ::std::string> fields; - SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); - int write_fd = -1; - -#if GTEST_OS_WINDOWS - unsigned int parent_process_id = 0; - size_t write_handle_as_size_t = 0; - size_t event_handle_as_size_t = 0; - - if (fields.size() != 6 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) - || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); - } - write_fd = GetStatusFileDescriptor(parent_process_id, - write_handle_as_size_t, - event_handle_as_size_t); -#else - if (fields.size() != 4 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort(String::Format( - "Bad --gtest_internal_run_death_test flag: %s", - GTEST_FLAG(internal_run_death_test).c_str())); - } -#endif // GTEST_OS_WINDOWS - return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); -} - -} // namespace internal - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: keith.ray@gmail.com (Keith Ray) - - -#include - -#if GTEST_OS_WINDOWS_MOBILE -#include -#elif GTEST_OS_WINDOWS -#include -#include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -#include -#else -#include -#include // Some Linux distributions define PATH_MAX here. -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_WINDOWS -#define GTEST_PATH_MAX_ _MAX_PATH -#elif defined(PATH_MAX) -#define GTEST_PATH_MAX_ PATH_MAX -#elif defined(_XOPEN_PATH_MAX) -#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX -#else -#define GTEST_PATH_MAX_ _POSIX_PATH_MAX -#endif // GTEST_OS_WINDOWS - - -namespace testing { -namespace internal { - -#if GTEST_OS_WINDOWS -// On Windows, '\\' is the standard path separator, but many tools and the -// Windows API also accept '/' as an alternate path separator. Unless otherwise -// noted, a file path can contain either kind of path separators, or a mixture -// of them. -const char kPathSeparator = '\\'; -const char kAlternatePathSeparator = '/'; -const char kPathSeparatorString[] = "\\"; -const char kAlternatePathSeparatorString[] = "/"; -#if GTEST_OS_WINDOWS_MOBILE -// Windows CE doesn't have a current directory. You should not use -// the current directory in tests on Windows CE, but this at least -// provides a reasonable fallback. -const char kCurrentDirectoryString[] = "\\"; -// Windows CE doesn't define INVALID_FILE_ATTRIBUTES -const DWORD kInvalidFileAttributes = 0xffffffff; -#else -const char kCurrentDirectoryString[] = ".\\"; -#endif // GTEST_OS_WINDOWS_MOBILE -#else -const char kPathSeparator = '/'; -const char kPathSeparatorString[] = "/"; -const char kCurrentDirectoryString[] = "./"; -#endif // GTEST_OS_WINDOWS - -// Returns whether the given character is a valid path separator. -static bool IsPathSeparator(char c) { -#if GTEST_HAS_ALT_PATH_SEP_ - return (c == kPathSeparator) || (c == kAlternatePathSeparator); -#else - return c == kPathSeparator; -#endif -} - -// Returns the current working directory, or "" if unsuccessful. -FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't have a current directory, so we just return - // something reasonable. - return FilePath(kCurrentDirectoryString); -#elif GTEST_OS_WINDOWS - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#else - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns a copy of the FilePath with the case-insensitive extension removed. -// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns -// FilePath("dir/file"). If a case-insensitive extension is not -// found, returns a copy of the original FilePath. -FilePath FilePath::RemoveExtension(const char* extension) const { - String dot_extension(String::Format(".%s", extension)); - if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { - return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); - } - return *this; -} - -// Returns a pointer to the last occurence of a valid path separator in -// the FilePath. On Windows, for example, both '/' and '\' are valid path -// separators. Returns NULL if no path separator was found. -const char* FilePath::FindLastPathSeparator() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); -#if GTEST_HAS_ALT_PATH_SEP_ - const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); - // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { - return last_alt_sep; - } -#endif - return last_sep; -} - -// Returns a copy of the FilePath with the directory part removed. -// Example: FilePath("path/to/file").RemoveDirectoryName() returns -// FilePath("file"). If there is no directory part ("just_a_file"), it returns -// the FilePath unmodified. If there is no file part ("just_a_dir/") it -// returns an empty FilePath (""). -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = FindLastPathSeparator(); - return last_sep ? FilePath(String(last_sep + 1)) : *this; -} - -// RemoveFileName returns the directory path with the filename removed. -// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". -// If the FilePath is "a_file" or "/a_file", RemoveFileName returns -// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does -// not have a file, like "just/a/dir/", it returns the FilePath unmodified. -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveFileName() const { - const char* const last_sep = FindLastPathSeparator(); - String dir; - if (last_sep) { - dir = String(c_str(), last_sep + 1 - c_str()); - } else { - dir = kCurrentDirectoryString; - } - return FilePath(dir); -} - -// Helper functions for naming files in a directory for xml output. - -// Given directory = "dir", base_name = "test", number = 0, -// extension = "xml", returns "dir/test.xml". If number is greater -// than zero (e.g., 12), returns "dir/test_12.xml". -// On Windows platform, uses \ as the separator rather than /. -FilePath FilePath::MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension) { - String file; - if (number == 0) { - file = String::Format("%s.%s", base_name.c_str(), extension); - } else { - file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); - } - return ConcatPaths(directory, FilePath(file)); -} - -// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". -// On Windows, uses \ as the separator rather than /. -FilePath FilePath::ConcatPaths(const FilePath& directory, - const FilePath& relative_path) { - if (directory.IsEmpty()) - return relative_path; - const FilePath dir(directory.RemoveTrailingPathSeparator()); - return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, - relative_path.c_str())); -} - -// Returns true if pathname describes something findable in the file-system, -// either a file, directory, or whatever. -bool FilePath::FileOrDirectoryExists() const { -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - return attributes != kInvalidFileAttributes; -#else - posix::StatStruct file_stat; - return posix::Stat(pathname_.c_str(), &file_stat) == 0; -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns true if pathname describes a directory in the file-system -// that exists. -bool FilePath::DirectoryExists() const { - bool result = false; -#if GTEST_OS_WINDOWS - // Don't strip off trailing separator if path is a root directory on - // Windows (like "C:\\"). - const FilePath& path(IsRootDirectory() ? *this : - RemoveTrailingPathSeparator()); -#else - const FilePath& path(*this); -#endif - -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - if ((attributes != kInvalidFileAttributes) && - (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = true; - } -#else - posix::StatStruct file_stat; - result = posix::Stat(path.c_str(), &file_stat) == 0 && - posix::IsDir(file_stat); -#endif // GTEST_OS_WINDOWS_MOBILE - - return result; -} - -// Returns true if pathname describes a root directory. (Windows has one -// root directory per disk drive.) -bool FilePath::IsRootDirectory() const { -#if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. - return pathname_.length() == 3 && IsAbsolutePath(); -#else - return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); -#endif -} - -// Returns true if pathname describes an absolute path. -bool FilePath::IsAbsolutePath() const { - const char* const name = pathname_.c_str(); -#if GTEST_OS_WINDOWS - return pathname_.length() >= 3 && - ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && - name[1] == ':' && - IsPathSeparator(name[2]); -#else - return IsPathSeparator(name[0]); -#endif -} - -// Returns a pathname for a file that does not currently exist. The pathname -// will be directory/base_name.extension or -// directory/base_name_.extension if directory/base_name.extension -// already exists. The number will be incremented until a pathname is found -// that does not already exist. -// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. -// There could be a race condition if two or more processes are calling this -// function at the same time -- they could both pick the same filename. -FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension) { - FilePath full_pathname; - int number = 0; - do { - full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); - } while (full_pathname.FileOrDirectoryExists()); - return full_pathname; -} - -// Returns true if FilePath ends with a path separator, which indicates that -// it is intended to represent a directory. Returns false otherwise. -// This does NOT check that a directory (or file) actually exists. -bool FilePath::IsDirectory() const { - return !pathname_.empty() && - IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); -} - -// Create directories so that path exists. Returns true if successful or if -// the directories already exist; returns false if unable to create directories -// for any reason. -bool FilePath::CreateDirectoriesRecursively() const { - if (!this->IsDirectory()) { - return false; - } - - if (pathname_.length() == 0 || this->DirectoryExists()) { - return true; - } - - const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); - return parent.CreateDirectoriesRecursively() && this->CreateFolder(); -} - -// Create the directory so that path exists. Returns true if successful or -// if the directory already exists; returns false if unable to create the -// directory for any reason, including if the parent directory does not -// exist. Not named "CreateDirectory" because that's a macro on Windows. -bool FilePath::CreateFolder() const { -#if GTEST_OS_WINDOWS_MOBILE - FilePath removed_sep(this->RemoveTrailingPathSeparator()); - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; - delete [] unicode; -#elif GTEST_OS_WINDOWS - int result = _mkdir(pathname_.c_str()); -#else - int result = mkdir(pathname_.c_str(), 0777); -#endif // GTEST_OS_WINDOWS_MOBILE - - if (result == -1) { - return this->DirectoryExists(); // An error is OK if the directory exists. - } - return true; // No error. -} - -// If input name has a trailing separator character, remove it and return the -// name, otherwise return the name string unmodified. -// On Windows platform, uses \ as the separator, other platforms use /. -FilePath FilePath::RemoveTrailingPathSeparator() const { - return IsDirectory() - ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) - : *this; -} - -// Removes any redundant separators that might be in the pathname. -// For example, "bar///foo" becomes "bar/foo". Does not eliminate other -// redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). -void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { - pathname_ = ""; - return; - } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.length() + 1); - - while (*src != '\0') { - *dest_ptr = *src; - if (!IsPathSeparator(*src)) { - src++; - } else { -#if GTEST_HAS_ALT_PATH_SEP_ - if (*dest_ptr == kAlternatePathSeparator) { - *dest_ptr = kPathSeparator; - } -#endif - while (IsPathSeparator(*src)) - src++; - } - dest_ptr++; - } - *dest_ptr = '\0'; - pathname_ = dest; - delete[] dest; -} - -} // namespace internal -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - - -#include -#include -#include - -#if GTEST_OS_WINDOWS_MOBILE -#include // For TerminateProcess() -#elif GTEST_OS_WINDOWS -#include -#include -#else -#include -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_MAC -#include -#include -#include -#endif // GTEST_OS_MAC - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { -namespace internal { - -#if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC and C++Builder do not provide a definition of STDERR_FILENO. -const int kStdOutFileno = 1; -const int kStdErrFileno = 2; -#else -const int kStdOutFileno = STDOUT_FILENO; -const int kStdErrFileno = STDERR_FILENO; -#endif // _MSC_VER - -#if GTEST_OS_MAC - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const task_t task = mach_task_self(); - mach_msg_type_number_t thread_count; - thread_act_array_t thread_list; - const kern_return_t status = task_threads(task, &thread_list, &thread_count); - if (status == KERN_SUCCESS) { - // task_threads allocates resources in thread_list and we need to free them - // to avoid leaks. - vm_deallocate(task, - reinterpret_cast(thread_list), - sizeof(thread_t) * thread_count); - return static_cast(thread_count); - } else { - return 0; - } -} - -#else - -size_t GetThreadCount() { - // There's no portable way to detect the number of threads, so we just - // return 0 to indicate that we cannot detect it. - return 0; -} - -#endif // GTEST_OS_MAC - -#if GTEST_USES_POSIX_RE - -// Implements RE. Currently only needed for death tests. - -RE::~RE() { - if (is_valid_) { - // regfree'ing an invalid regex might crash because the content - // of the regex is undefined. Since the regex's are essentially - // the same, one cannot be valid (or invalid) without the other - // being so too. - regfree(&partial_regex_); - regfree(&full_regex_); - } - free(const_cast(pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.full_regex_, str, 1, &match, 0) == 0; -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = posix::StrDup(regex); - - // Reserves enough bytes to hold the regular expression used for a - // full match. - const size_t full_regex_len = strlen(regex) + 10; - char* const full_pattern = new char[full_regex_len]; - - snprintf(full_pattern, full_regex_len, "^(%s)$", regex); - is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; - // We want to call regcomp(&partial_regex_, ...) even if the - // previous expression returns false. Otherwise partial_regex_ may - // not be properly initialized can may cause trouble when it's - // freed. - // - // Some implementation of POSIX regex (e.g. on at least some - // versions of Cygwin) doesn't accept the empty string as a valid - // regex. We change it to an equivalent form "()" to be safe. - if (is_valid_) { - const char* const partial_regex = (*regex == '\0') ? "()" : regex; - is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; - } - EXPECT_TRUE(is_valid_) - << "Regular expression \"" << regex - << "\" is not a valid POSIX Extended regular expression."; - - delete[] full_pattern; -} - -#elif GTEST_USES_SIMPLE_RE - -// Returns true iff ch appears anywhere in str (excluding the -// terminating '\0' character). -bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; -} - -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the -// current locale. -bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsPunct(char ch) { - return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); -} -bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsWordChar(char ch) { - return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_'; -} - -// Returns true iff "\\c" is a supported escape sequence. -bool IsValidEscape(char c) { - return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); -} - -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. -bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { - if (escaped) { // "\\p" where p is pattern_char. - switch (pattern_char) { - case 'd': return IsDigit(ch); - case 'D': return !IsDigit(ch); - case 'f': return ch == '\f'; - case 'n': return ch == '\n'; - case 'r': return ch == '\r'; - case 's': return IsWhiteSpace(ch); - case 'S': return !IsWhiteSpace(ch); - case 't': return ch == '\t'; - case 'v': return ch == '\v'; - case 'w': return IsWordChar(ch); - case 'W': return !IsWordChar(ch); - } - return IsPunct(pattern_char) && pattern_char == ch; - } - - return (pattern_char == '.' && ch != '\n') || pattern_char == ch; -} - -// Helper function used by ValidateRegex() to format error messages. -String FormatRegexSyntaxError(const char* regex, int index) { - return (Message() << "Syntax error at index " << index - << " in simple regular expression \"" << regex << "\": ").GetString(); -} - -// Generates non-fatal failures and returns false if regex is invalid; -// otherwise returns true. -bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. - ADD_FAILURE() << "NULL is not a valid simple regular expression."; - return false; - } - - bool is_valid = true; - - // True iff ?, *, or + can follow the previous atom. - bool prev_repeatable = false; - for (int i = 0; regex[i]; i++) { - if (regex[i] == '\\') { // An escape sequence - i++; - if (regex[i] == '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "'\\' cannot appear at the end."; - return false; - } - - if (!IsValidEscape(regex[i])) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "invalid escape sequence \"\\" << regex[i] << "\"."; - is_valid = false; - } - prev_repeatable = true; - } else { // Not an escape sequence. - const char ch = regex[i]; - - if (ch == '^' && i > 0) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'^' can only appear at the beginning."; - is_valid = false; - } else if (ch == '$' && regex[i + 1] != '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'$' can only appear at the end."; - is_valid = false; - } else if (IsInSet(ch, "()[]{}|")) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' is unsupported."; - is_valid = false; - } else if (IsRepeat(ch) && !prev_repeatable) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' can only follow a repeatable token."; - is_valid = false; - } - - prev_repeatable = !IsInSet(ch, "^$?*+"); - } - } - - return is_valid; -} - -// Matches a repeated regex atom followed by a valid simple regular -// expression. The regex atom is defined as c if escaped is false, -// or \c otherwise. repeat is the repetition meta character (?, *, -// or +). The behavior is undefined if str contains too many -// characters to be indexable by size_t, in which case the test will -// probably time out anyway. We are fine with this limitation as -// std::string has it too. -bool MatchRepetitionAndRegexAtHead( - bool escaped, char c, char repeat, const char* regex, - const char* str) { - const size_t min_count = (repeat == '+') ? 1 : 0; - const size_t max_count = (repeat == '?') ? 1 : - static_cast(-1) - 1; - // We cannot call numeric_limits::max() as it conflicts with the - // max() macro on Windows. - - for (size_t i = 0; i <= max_count; ++i) { - // We know that the atom matches each of the first i characters in str. - if (i >= min_count && MatchRegexAtHead(regex, str + i)) { - // We have enough matches at the head, and the tail matches too. - // Since we only care about *whether* the pattern matches str - // (as opposed to *how* it matches), there is no need to find a - // greedy match. - return true; - } - if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) - return false; - } - return false; -} - -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the -// result is undefined. -bool MatchRegexAtHead(const char* regex, const char* str) { - if (*regex == '\0') // An empty regex matches a prefix of anything. - return true; - - // "$" only matches the end of a string. Note that regex being - // valid guarantees that there's nothing after "$" in it. - if (*regex == '$') - return *str == '\0'; - - // Is the first thing in regex an escape sequence? - const bool escaped = *regex == '\\'; - if (escaped) - ++regex; - if (IsRepeat(regex[1])) { - // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so - // here's an indirect recursion. It terminates as the regex gets - // shorter in each recursion. - return MatchRepetitionAndRegexAtHead( - escaped, regex[0], regex[1], regex + 2, str); - } else { - // regex isn't empty, isn't "$", and doesn't start with a - // repetition. We match the first atom of regex with the first - // character of str and recurse. - return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && - MatchRegexAtHead(regex + 1, str + 1); - } -} - -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. -// -// The algorithm is recursive, but the recursion depth doesn't exceed -// the regex length, so we won't need to worry about running out of -// stack space normally. In rare cases the time complexity can be -// exponential with respect to the regex length + the string length, -// but usually it's must faster (often close to linear). -bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; - - if (*regex == '^') - return MatchRegexAtHead(regex + 1, str); - - // A successful match can be anywhere in str. - do { - if (MatchRegexAtHead(regex, str)) - return true; - } while (*str++ != '\0'); - return false; -} - -// Implements the RE class. - -RE::~RE() { - free(const_cast(pattern_)); - free(const_cast(full_pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { - pattern_ = posix::StrDup(regex); - } - - is_valid_ = ValidateRegex(regex); - if (!is_valid_) { - // No need to calculate the full pattern when the regex is invalid. - return; - } - - const size_t len = strlen(regex); - // Reserves enough bytes to hold the regular expression used for a - // full match: we need space to prepend a '^', append a '$', and - // terminate the string with '\0'. - char* buffer = static_cast(malloc(len + 3)); - full_pattern_ = buffer; - - if (*regex != '^') - *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. - - // We don't use snprintf or strncpy, as they trigger a warning when - // compiled with VC++ 8.0. - memcpy(buffer, regex, len); - buffer += len; - - if (len == 0 || regex[len - 1] != '$') - *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. - - *buffer = '\0'; -} - -#endif // GTEST_USES_POSIX_RE - - -GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) - : severity_(severity) { - const char* const marker = - severity == GTEST_INFO ? "[ INFO ]" : - severity == GTEST_WARNING ? "[WARNING]" : - severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - GetStream() << ::std::endl << marker << " " - << FormatFileLocation(file, line).c_str() << ": "; -} - -// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. -GTestLog::~GTestLog() { - GetStream() << ::std::endl; - if (severity_ == GTEST_FATAL) { - fflush(stderr); - posix::Abort(); - } -} -// Disable Microsoft deprecation warnings for POSIX functions called from -// this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) -#endif // _MSC_VER - -#if GTEST_HAS_STREAM_REDIRECTION_ - -// Object that captures an output stream (stdout/stderr). -class CapturedStream { - public: - // The ctor redirects the stream to a temporary file. - CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { -#if GTEST_OS_WINDOWS - char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT - char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT - - ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - const UINT success = ::GetTempFileNameA(temp_dir_path, - "gtest_redir", - 0, // Generate unique file name. - temp_file_path); - GTEST_CHECK_(success != 0) - << "Unable to create a temporary file in " << temp_dir_path; - const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); - GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " - << temp_file_path; - filename_ = temp_file_path; -#else - // There's no guarantee that a test has write access to the - // current directory, so we create the temporary file in the /tmp - // directory instead. - char name_template[] = "/tmp/captured_stream.XXXXXX"; - const int captured_fd = mkstemp(name_template); - filename_ = name_template; -#endif // GTEST_OS_WINDOWS - fflush(NULL); - dup2(captured_fd, fd_); - close(captured_fd); - } - - ~CapturedStream() { - remove(filename_.c_str()); - } - - String GetCapturedString() { - if (uncaptured_fd_ != -1) { - // Restores the original stream. - fflush(NULL); - dup2(uncaptured_fd_, fd_); - close(uncaptured_fd_); - uncaptured_fd_ = -1; - } - - FILE* const file = posix::FOpen(filename_.c_str(), "r"); - const String content = ReadEntireFile(file); - posix::FClose(file); - return content; - } - - private: - // Reads the entire content of a file as a String. - static String ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - - const int fd_; // A stream to capture. - int uncaptured_fd_; - // Name of the temporary file holding the stderr output. - ::std::string filename_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); -}; - -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -String CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const String content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; - -// Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { - GTEST_LOG_(FATAL) << "Only one " << stream_name - << " capturer can exist at a time."; - } - *stream = new CapturedStream(fd); -} - -// Stops capturing the output stream and returns the captured string. -String GetCapturedStream(CapturedStream** captured_stream) { - const String content = (*captured_stream)->GetCapturedString(); - - delete *captured_stream; - *captured_stream = NULL; - - return content; -} - -// Starts capturing stdout. -void CaptureStdout() { - CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); -} - -// Starts capturing stderr. -void CaptureStderr() { - CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); -} - -// Stops capturing stdout and returns the captured string. -String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } - -// Stops capturing stderr and returns the captured string. -String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } - -#endif // GTEST_HAS_STREAM_REDIRECTION_ - -#if GTEST_HAS_DEATH_TEST - -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; - -// Returns the command line as a vector of strings. -const ::std::vector& GetArgvs() { return g_argvs; } - -#endif // GTEST_HAS_DEATH_TEST - -#if GTEST_OS_WINDOWS_MOBILE -namespace posix { -void Abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -} // namespace posix -#endif // GTEST_OS_WINDOWS_MOBILE - -// Returns the name of the environment variable corresponding to the -// given flag. For example, FlagToEnvVar("foo") will return -// "GTEST_FOO" in the open-source version. -static String FlagToEnvVar(const char* flag) { - const String full_flag = - (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); - - Message env_var; - for (size_t i = 0; i != full_flag.length(); i++) { - env_var << static_cast(toupper(full_flag.c_str()[i])); - } - - return env_var.GetString(); -} - -// Parses 'str' for a 32-bit signed integer. If successful, writes -// the result to *value and returns true; otherwise leaves *value -// unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { - // Parses the environment variable as a decimal integer. - char* end = NULL; - const long long_value = strtol(str, &end, 10); // NOLINT - - // Has strtol() consumed all characters in the string? - if (*end != '\0') { - // No - an invalid character was encountered. - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value \"" << str << "\".\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); - if (long_value == LONG_MAX || long_value == LONG_MIN || - // The parsed value overflows as a long. (strtol() returns - // LONG_MAX or LONG_MIN when the input overflows.) - result != long_value - // The parsed value overflows as an Int32. - ) { - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value " << str << ", which overflows.\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - *value = result; - return true; -} - -// Reads and returns the Boolean environment variable corresponding to -// the given flag; if it's not set, returns default_value. -// -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; -} - -// Reads and returns a 32-bit integer stored in the environment -// variable corresponding to the given flag; if it isn't set or -// doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { - // The environment variable is not set. - return default_value; - } - - Int32 result = default_value; - if (!ParseInt32(Message() << "Environment variable " << env_var, - string_value, &result)) { - printf("The default value %s is used.\n", - (Message() << default_value).GetString().c_str()); - fflush(stdout); - return default_value; - } - - return result; -} - -// Reads and returns the string environment variable corresponding to -// the given flag; if it's not set, returns default_value. -const char* StringFromGTestEnv(const char* flag, const char* default_value) { - const String env_var = FlagToEnvVar(flag); - const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; -} - -} // namespace internal -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -using internal::GetUnitTestImpl; - -// Gets the summary of the failure message by omitting the stack trace -// in it. -internal::String TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? internal::String(message) : - internal::String(message, stack_trace - message); -} - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; -} - -// Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { - array_.push_back(result); -} - -// Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { - if (index < 0 || index >= size()) { - printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::Abort(); - } - - return array_[index]; -} - -// Returns the number of TestPartResult objects in the array. -int TestPartResultArray::size() const { - return static_cast(array_.size()); -} - -namespace internal { - -HasNewFatalFailureHelper::HasNewFatalFailureHelper() - : has_new_fatal_failure_(false), - original_reporter_(GetUnitTestImpl()-> - GetTestPartResultReporterForCurrentThread()) { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); -} - -HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( - original_reporter_); -} - -void HasNewFatalFailureHelper::ReportTestPartResult( - const TestPartResult& result) { - if (result.fatally_failed()) - has_new_fatal_failure_ = true; - original_reporter_->ReportTestPartResult(result); -} - -} // namespace internal - -} // namespace testing -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - - -namespace testing { -namespace internal { - -#if GTEST_HAS_TYPED_TEST_P - -// Skips to the first non-space char in str. Returns an empty string if str -// contains only whitespace characters. -static const char* SkipSpaces(const char* str) { - while (isspace(*str)) - str++; - return str; -} - -// Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or -// aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; - registered_ = true; - - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); - - Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const String name = GetPrefixUntilComma(names); - if (tests.count(name) != 0) { - errors << "Test " << name << " is listed more than once.\n"; - continue; - } - - bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (name == *it) { - found = true; - break; - } - } - - if (found) { - tests.insert(name); - } else { - errors << "No test named " << name - << " can be found in this test case.\n"; - } - } - - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; - } - } - - const String& errors_str = errors.GetString(); - if (errors_str != "") { - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors_str.c_str()); - fflush(stderr); - posix::Abort(); - } - - return registered_tests; -} - -#endif // GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing diff --git a/Fwk/AppFwk/cafTests/gtest/gtest.h b/Fwk/AppFwk/cafTests/gtest/gtest.h deleted file mode 100644 index c0a1902e25..0000000000 --- a/Fwk/AppFwk/cafTests/gtest/gtest.h +++ /dev/null @@ -1,18007 +0,0 @@ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for Google Test. It should be -// included by any test program that uses Google Test. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! -// -// Acknowledgment: Google Test borrowed the idea of automatic test -// registration from Barthelemy Dagenais' (barthelemy@prologique.com) -// easyUnit framework. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_H_ - -#include -#include - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares functions and macros used internally by -// Google Test. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: wan@google.com (Zhanyong Wan) -// -// Low-level types and utilities for porting Google Test to various -// platforms. They are subject to change without notice. DO NOT USE -// THEM IN USER CODE. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - -// The user can define the following macros in the build script to -// control Google Test's behavior. If the user doesn't define a macro -// in this list, Google Test will define it. -// -// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) -// is/isn't available. -// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions -// are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). -// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that -// is/isn't available. -// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't -// enabled. -// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that -// std::wstring does/doesn't work (Google Test can -// be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. -// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the -// compiler supports Microsoft's "Structured -// Exception Handling". -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LINKED_AS_SHARED_LIBRARY -// - Define to 1 when compiling tests that use -// Google Test as a shared library (known as -// DLL on Windows). -// GTEST_CREATE_SHARED_LIBRARY -// - Define to 1 when compiling Google Test itself -// as a shared library. - -// This header defines the following utilities: -// -// Macros indicating the current platform (defined to 1 if compiled on -// the given platform; otherwise undefined): -// GTEST_OS_AIX - IBM AIX -// GTEST_OS_CYGWIN - Cygwin -// GTEST_OS_LINUX - Linux -// GTEST_OS_MAC - Mac OS X -// GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian -// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) -// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop -// GTEST_OS_WINDOWS_MINGW - MinGW -// GTEST_OS_WINDOWS_MOBILE - Windows Mobile -// GTEST_OS_ZOS - z/OS -// -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the -// most stable support. Since core members of the Google Test project -// don't have access to other platforms, support for them may be less -// stable. If you notice any problems on your platform, please notify -// googletestframework@googlegroups.com (patches for fixing them are -// even more welcome!). -// -// Note that it is possible that none of the GTEST_OS_* macros are defined. -// -// Macros indicating available Google Test features (defined to 1 if -// the corresponding feature is supported; otherwise undefined): -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) -// GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests -// GTEST_HAS_TYPED_TEST - typed tests -// GTEST_HAS_TYPED_TEST_P - type-parameterized tests -// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. -// GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). -// -// Macros for basic C++ coding: -// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. -// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a -// variable don't have to be used. -// GTEST_DISALLOW_ASSIGN_ - disables operator=. -// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. -// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. -// -// Synchronization: -// Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above -// synchronization primitives have real implementations -// and Google Test is thread-safe; or 0 otherwise. -// -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// -// Smart pointers: -// scoped_ptr - as in TR2. -// -// Regular expressions: -// RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax. Not available on -// Windows. -// -// Logging: -// GTEST_LOG_() - logs messages at the specified severity level. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. -// -// Stdout and stderr capturing: -// CaptureStdout() - starts capturing stdout. -// GetCapturedStdout() - stops capturing stdout and returns the captured -// string. -// CaptureStderr() - starts capturing stderr. -// GetCapturedStderr() - stops capturing stderr and returns the captured -// string. -// -// Integer types: -// TypeWithSize - maps an integer to a int type. -// Int32, UInt32, Int64, UInt64, TimeInMillis -// - integers of known sizes. -// BiggestInt - the biggest signed integer type. -// -// Command-line utilities: -// GTEST_FLAG() - references a flag. -// GTEST_DECLARE_*() - declares a flag. -// GTEST_DEFINE_*() - defines a flag. -// GetArgvs() - returns the command line as a vector of strings. -// -// Environment variable utilities: -// GetEnv() - gets the value of an environment variable. -// BoolFromGTestEnv() - parses a bool environment variable. -// Int32FromGTestEnv() - parses an Int32 environment variable. -// StringFromGTestEnv() - parses a string environment variable. - -#include // For ptrdiff_t -#include -#include -#include -#ifndef _WIN32_WCE -#include -#endif // !_WIN32_WCE - -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" - -// Determines the version of gcc that is used to compile this. -#ifdef __GNUC__ -// 40302 means version 4.3.2. -#define GTEST_GCC_VER_ \ - (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) -#endif // __GNUC__ - -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -#define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -#define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -#define GTEST_OS_WINDOWS 1 -#ifdef _WIN32_WCE -#define GTEST_OS_WINDOWS_MOBILE 1 -#elif defined(__MINGW__) || defined(__MINGW32__) -#define GTEST_OS_WINDOWS_MINGW 1 -#else -#define GTEST_OS_WINDOWS_DESKTOP 1 -#endif // _WIN32_WCE -#elif defined __APPLE__ -#define GTEST_OS_MAC 1 -#elif defined __linux__ -#define GTEST_OS_LINUX 1 -#elif defined __MVS__ -#define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -#define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -#define GTEST_OS_AIX 1 -#endif // __CYGWIN__ - -#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \ - GTEST_OS_SOLARIS || GTEST_OS_AIX - -// On some platforms, needs someone to define size_t, and -// won't compile otherwise. We can #include it here as we already -// included , which is guaranteed to define size_t through -// . -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#define GTEST_USES_POSIX_RE 1 - -#elif GTEST_OS_WINDOWS - -#if !GTEST_OS_WINDOWS_MOBILE -#include // NOLINT -#include // NOLINT -#endif - -// is not available on Windows. Use our own simple regex -// implementation instead. -#define GTEST_USES_SIMPLE_RE 1 - -#else - -// may not be available on this platform. Use our own -// simple regex implementation instead. -#define GTEST_USES_SIMPLE_RE 1 - -#endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || - // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX - -#ifndef GTEST_HAS_EXCEPTIONS -// The user didn't tell us whether exceptions are enabled, so we need -// to figure it out. -#if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS -// macro to enable exceptions, so we'll do the same. -// Assumes that exceptions are enabled by default. -#ifndef _HAS_EXCEPTIONS -#define _HAS_EXCEPTIONS 1 -#endif // _HAS_EXCEPTIONS -#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS -#elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. -#define GTEST_HAS_EXCEPTIONS 1 -#elif defined(__SUNPRO_CC) -// Sun Pro CC supports exceptions. However, there is no compile-time way of -// detecting whether they are enabled or not. Therefore, we assume that -// they are enabled unless the user tells us otherwise. -#define GTEST_HAS_EXCEPTIONS 1 -#elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. -#define GTEST_HAS_EXCEPTIONS 1 -#else -// For other compilers, we assume exceptions are disabled to be -// conservative. -#define GTEST_HAS_EXCEPTIONS 0 -#endif // defined(_MSC_VER) || defined(__BORLANDC__) -#endif // GTEST_HAS_EXCEPTIONS - -#if !defined(GTEST_HAS_STD_STRING) -// Even though we don't use this macro any longer, we keep it in case -// some clients still depend on it. -#define GTEST_HAS_STD_STRING 1 -#elif !GTEST_HAS_STD_STRING -// The user told us that ::std::string isn't available. -#error "Google Test cannot be used where ::std::string isn't available." -#endif // !defined(GTEST_HAS_STD_STRING) - -#ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - -#define GTEST_HAS_GLOBAL_STRING 0 - -#endif // GTEST_HAS_GLOBAL_STRING - -#ifndef GTEST_HAS_STD_WSTRING -// The user didn't tell us whether ::std::wstring is available, so we need -// to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring -// is available. - -// Cygwin 1.5 and below doesn't support ::std::wstring. -// Cygwin 1.7 might add wstring support; this should be updated when clear. -// Solaris' libc++ doesn't support it either. -#define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) - -#endif // GTEST_HAS_STD_WSTRING - -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -#define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Determines whether RTTI is available. -#ifndef GTEST_HAS_RTTI -// The user didn't tell us whether RTTI is enabled, so we need to -// figure it out. - -#ifdef _MSC_VER - -#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. -#define GTEST_HAS_RTTI 1 -#else -#define GTEST_HAS_RTTI 0 -#endif - -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) - -#ifdef __GXX_RTTI -#define GTEST_HAS_RTTI 1 -#else -#define GTEST_HAS_RTTI 0 -#endif // __GXX_RTTI - -// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if -// both the typeid and dynamic_cast features are present. -#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) - -#ifdef __RTTI_ALL__ -#define GTEST_HAS_RTTI 1 -#else -#define GTEST_HAS_RTTI 0 -#endif - -#else - -// For all other compilers, we assume RTTI is enabled. -#define GTEST_HAS_RTTI 1 - -#endif // _MSC_VER - -#endif // GTEST_HAS_RTTI - -// It's this header's responsibility to #include when RTTI -// is enabled. -#if GTEST_HAS_RTTI -#include -#endif - -// Determines whether Google Test can use the pthreads library. -#ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we assume pthreads support is -// available on Linux and Mac. -// -// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 -// to your compiler flags. -#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) -#endif // GTEST_HAS_PTHREAD - -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -// The user didn't tell us not to do it, so we assume it's OK. -#define GTEST_HAS_TR1_TUPLE 1 -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, GCC 4.0.0+ and MSVC -// 2010 are the only mainstream compilers that come with a TR1 tuple -// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by -// defining __GNUC__ and friends, but cannot compile GCC's tuple -// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB -// Feature Pack download, which we cannot assume the user has. -#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ - || _MSC_VER >= 1600 -#define GTEST_USE_OWN_TR1_TUPLE 0 -#else -#define GTEST_USE_OWN_TR1_TUPLE 1 -#endif - -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. -#if GTEST_HAS_TR1_TUPLE - -#if GTEST_USE_OWN_TR1_TUPLE -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! - -// Copyright 2009 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -// Implements a subset of TR1 tuple needed by Google Test and Google Mock. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ - -#include // For ::std::pair. - -// The compiler used in Symbian has a bug that prevents us from declaring the -// tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be -// private as public. -// Sun Studio versions < 12 also have the above bug. -#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) -#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: -#else -#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ - template friend class tuple; \ - private: -#endif - -// GTEST_n_TUPLE_(T) is the type of an n-tuple. -#define GTEST_0_TUPLE_(T) tuple<> -#define GTEST_1_TUPLE_(T) tuple -#define GTEST_2_TUPLE_(T) tuple -#define GTEST_3_TUPLE_(T) tuple -#define GTEST_4_TUPLE_(T) tuple -#define GTEST_5_TUPLE_(T) tuple -#define GTEST_6_TUPLE_(T) tuple -#define GTEST_7_TUPLE_(T) tuple -#define GTEST_8_TUPLE_(T) tuple -#define GTEST_9_TUPLE_(T) tuple -#define GTEST_10_TUPLE_(T) tuple - -// GTEST_n_TYPENAMES_(T) declares a list of n typenames. -#define GTEST_0_TYPENAMES_(T) -#define GTEST_1_TYPENAMES_(T) typename T##0 -#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 -#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 -#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3 -#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4 -#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5 -#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6 -#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 -#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8 -#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8, typename T##9 - -// In theory, defining stuff in the ::std namespace is undefined -// behavior. We can do this as we are playing the role of a standard -// library vendor. -namespace std { -namespace tr1 { - -template -class tuple; - -// Anything in namespace gtest_internal is Google Test's INTERNAL -// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. -namespace gtest_internal { - -// ByRef::type is T if T is a reference; otherwise it's const T&. -template -struct ByRef { typedef const T& type; }; // NOLINT -template -struct ByRef { typedef T& type; }; // NOLINT - -// A handy wrapper for ByRef. -#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type - -// AddRef::type is T if T is a reference; otherwise it's T&. This -// is the same as tr1::add_reference::type. -template -struct AddRef { typedef T& type; }; // NOLINT -template -struct AddRef { typedef T& type; }; // NOLINT - -// A handy wrapper for AddRef. -#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type - -// A helper for implementing get(). -template class Get; - -// A helper for implementing tuple_element. kIndexValid is true -// iff k < the number of fields in tuple type T. -template -struct TupleElement; - -template -struct TupleElement { typedef T0 type; }; - -template -struct TupleElement { typedef T1 type; }; - -template -struct TupleElement { typedef T2 type; }; - -template -struct TupleElement { typedef T3 type; }; - -template -struct TupleElement { typedef T4 type; }; - -template -struct TupleElement { typedef T5 type; }; - -template -struct TupleElement { typedef T6 type; }; - -template -struct TupleElement { typedef T7 type; }; - -template -struct TupleElement { typedef T8 type; }; - -template -struct TupleElement { typedef T9 type; }; - -} // namespace gtest_internal - -template <> -class tuple<> { - public: - tuple() {} - tuple(const tuple& /* t */) {} - tuple& operator=(const tuple& /* t */) { return *this; } -}; - -template -class GTEST_1_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} - - tuple(const tuple& t) : f0_(t.f0_) {} - - template - tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_1_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { - f0_ = t.f0_; - return *this; - } - - T0 f0_; -}; - -template -class GTEST_2_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), - f1_(f1) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} - - template - tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} - template - tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_2_TUPLE_(U)& t) { - return CopyFrom(t); - } - template - tuple& operator=(const ::std::pair& p) { - f0_ = p.first; - f1_ = p.second; - return *this; - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - return *this; - } - - T0 f0_; - T1 f1_; -}; - -template -class GTEST_3_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - template - tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_3_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; -}; - -template -class GTEST_4_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} - - template - tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_4_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; -}; - -template -class GTEST_5_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, - GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_) {} - - template - tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_5_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; -}; - -template -class GTEST_6_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_) {} - - template - tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_6_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; -}; - -template -class GTEST_7_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - template - tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_7_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; -}; - -template -class GTEST_8_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, - GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - template - tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_8_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; -}; - -template -class GTEST_9_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - template - tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_9_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; -}; - -template -class tuple { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), - f9_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} - - template - tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), - f9_(t.f9_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_10_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - f9_ = t.f9_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; - T9 f9_; -}; - -// 6.1.3.2 Tuple creation functions. - -// Known limitations: we don't support passing an -// std::tr1::reference_wrapper to make_tuple(). And we don't -// implement tie(). - -inline tuple<> make_tuple() { return tuple<>(); } - -template -inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { - return GTEST_1_TUPLE_(T)(f0); -} - -template -inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { - return GTEST_2_TUPLE_(T)(f0, f1); -} - -template -inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { - return GTEST_3_TUPLE_(T)(f0, f1, f2); -} - -template -inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3) { - return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); -} - -template -inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4) { - return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); -} - -template -inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5) { - return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); -} - -template -inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6) { - return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); -} - -template -inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { - return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); -} - -template -inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8) { - return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); -} - -template -inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8, const T9& f9) { - return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); -} - -// 6.1.3.3 Tuple helper classes. - -template struct tuple_size; - -template -struct tuple_size { static const int value = 0; }; - -template -struct tuple_size { static const int value = 1; }; - -template -struct tuple_size { static const int value = 2; }; - -template -struct tuple_size { static const int value = 3; }; - -template -struct tuple_size { static const int value = 4; }; - -template -struct tuple_size { static const int value = 5; }; - -template -struct tuple_size { static const int value = 6; }; - -template -struct tuple_size { static const int value = 7; }; - -template -struct tuple_size { static const int value = 8; }; - -template -struct tuple_size { static const int value = 9; }; - -template -struct tuple_size { static const int value = 10; }; - -template -struct tuple_element { - typedef typename gtest_internal::TupleElement< - k < (tuple_size::value), k, Tuple>::type type; -}; - -#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type - -// 6.1.3.4 Element access. - -namespace gtest_internal { - -template <> -class Get<0> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - Field(Tuple& t) { return t.f0_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - ConstField(const Tuple& t) { return t.f0_; } -}; - -template <> -class Get<1> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - Field(Tuple& t) { return t.f1_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - ConstField(const Tuple& t) { return t.f1_; } -}; - -template <> -class Get<2> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - Field(Tuple& t) { return t.f2_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - ConstField(const Tuple& t) { return t.f2_; } -}; - -template <> -class Get<3> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - Field(Tuple& t) { return t.f3_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - ConstField(const Tuple& t) { return t.f3_; } -}; - -template <> -class Get<4> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - Field(Tuple& t) { return t.f4_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - ConstField(const Tuple& t) { return t.f4_; } -}; - -template <> -class Get<5> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - Field(Tuple& t) { return t.f5_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - ConstField(const Tuple& t) { return t.f5_; } -}; - -template <> -class Get<6> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - Field(Tuple& t) { return t.f6_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - ConstField(const Tuple& t) { return t.f6_; } -}; - -template <> -class Get<7> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - Field(Tuple& t) { return t.f7_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - ConstField(const Tuple& t) { return t.f7_; } -}; - -template <> -class Get<8> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - Field(Tuple& t) { return t.f8_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - ConstField(const Tuple& t) { return t.f8_; } -}; - -template <> -class Get<9> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - Field(Tuple& t) { return t.f9_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - ConstField(const Tuple& t) { return t.f9_; } -}; - -} // namespace gtest_internal - -template -GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::Field(t); -} - -template -GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(const GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::ConstField(t); -} - -// 6.1.3.5 Relational operators - -// We only implement == and !=, as we don't have a need for the rest yet. - -namespace gtest_internal { - -// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the -// first k fields of t1 equals the first k fields of t2. -// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if -// k1 != k2. -template -struct SameSizeTuplePrefixComparator; - -template <> -struct SameSizeTuplePrefixComparator<0, 0> { - template - static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { - return true; - } -}; - -template -struct SameSizeTuplePrefixComparator { - template - static bool Eq(const Tuple1& t1, const Tuple2& t2) { - return SameSizeTuplePrefixComparator::Eq(t1, t2) && - ::std::tr1::get(t1) == ::std::tr1::get(t2); - } -}; - -} // namespace gtest_internal - -template -inline bool operator==(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { - return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); -} - -template -inline bool operator!=(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { return !(t == u); } - -// 6.1.4 Pairs. -// Unimplemented. - -} // namespace tr1 -} // namespace std - -#undef GTEST_0_TUPLE_ -#undef GTEST_1_TUPLE_ -#undef GTEST_2_TUPLE_ -#undef GTEST_3_TUPLE_ -#undef GTEST_4_TUPLE_ -#undef GTEST_5_TUPLE_ -#undef GTEST_6_TUPLE_ -#undef GTEST_7_TUPLE_ -#undef GTEST_8_TUPLE_ -#undef GTEST_9_TUPLE_ -#undef GTEST_10_TUPLE_ - -#undef GTEST_0_TYPENAMES_ -#undef GTEST_1_TYPENAMES_ -#undef GTEST_2_TYPENAMES_ -#undef GTEST_3_TYPENAMES_ -#undef GTEST_4_TYPENAMES_ -#undef GTEST_5_TYPENAMES_ -#undef GTEST_6_TYPENAMES_ -#undef GTEST_7_TYPENAMES_ -#undef GTEST_8_TYPENAMES_ -#undef GTEST_9_TYPENAMES_ -#undef GTEST_10_TYPENAMES_ - -#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ -#undef GTEST_BY_REF_ -#undef GTEST_ADD_REF_ -#undef GTEST_TUPLE_ELEMENT_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -#ifdef BOOST_HAS_TR1_TUPLE -#undef BOOST_HAS_TR1_TUPLE -#endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -#include - -#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent -// from being included. -#define _TR1_FUNCTIONAL 1 -#include -#undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. -#else -#include // NOLINT -#endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -#else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -#include // NOLINT -#endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether clone(2) is supported. -// Usually it will only be available on Linux, excluding -// Linux on the Itanium architecture. -// Also see http://linux.die.net/man/2/clone. -#ifndef GTEST_HAS_CLONE -// The user didn't tell us, so we need to figure it out. - -#if GTEST_OS_LINUX && !defined(__ia64__) -#define GTEST_HAS_CLONE 1 -#else -#define GTEST_HAS_CLONE 0 -#endif // GTEST_OS_LINUX && !defined(__ia64__) - -#endif // GTEST_HAS_CLONE - -// Determines whether to support stream redirection. This is used to test -// output correctness and to implement death tests. -#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN -#define GTEST_HAS_STREAM_REDIRECTION_ 1 -#endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN - -// Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config -// pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX) -#define GTEST_HAS_DEATH_TEST 1 -#include // NOLINT -#endif - -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - -// Determines whether to support type-driven tests. - -// Typed tests need and variadic macros, which GCC, VC++ 8.0, -// Sun Pro CC, and IBM Visual Age support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ - defined(__IBMCPP__) -#define GTEST_HAS_TYPED_TEST 1 -#define GTEST_HAS_TYPED_TEST_P 1 -#endif - -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) -#define GTEST_HAS_COMBINE 1 -#endif - -// Determines whether the system compiler uses UTF-16 for encoding wide strings. -#define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) - -// Defines some utility macros. - -// The GNU compiler emits a warning if nested "if" statements are followed by -// an "else" statement and braces are not used to explicitly disambiguate the -// "else" binding. This leads to problems with code like: -// -// if (gate) -// ASSERT_*(condition) << "Some message"; -// -// The "switch (0) case 0:" idiom is used to suppress this. -#ifdef __INTEL_COMPILER -#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ -#else -#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT -#endif - -// Use this annotation at the end of a struct/class definition to -// prevent the compiler from optimizing away instances that are never -// used. This is useful when all interesting logic happens inside the -// c'tor and / or d'tor. Example: -// -// struct Foo { -// Foo() { ... } -// } GTEST_ATTRIBUTE_UNUSED_; -// -// Also use it after a variable or parameter declaration to tell the -// compiler the variable/parameter does not have to be used. -#if defined(__GNUC__) && !defined(COMPILER_ICC) -#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else -#define GTEST_ATTRIBUTE_UNUSED_ -#endif - -// A macro to disallow operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) - -// A macro to disallow copy constructor and operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ - GTEST_DISALLOW_ASSIGN_(type) - -// Tell the compiler to warn about unused return values for functions declared -// with this macro. The macro should be used on function declarations -// following the argument list: -// -// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) -#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) -#else -#define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC - -// Determine whether the compiler supports Microsoft's Structured Exception -// Handling. This is supported by several Windows compilers but generally -// does not exist on any other system. -#ifndef GTEST_HAS_SEH -// The user didn't tell us, so we need to figure it out. - -#if defined(_MSC_VER) || defined(__BORLANDC__) -// These two compilers are known to support SEH. -#define GTEST_HAS_SEH 1 -#else -// Assume no SEH. -#define GTEST_HAS_SEH 0 -#endif - -#endif // GTEST_HAS_SEH - -#ifdef _MSC_VER - -#if GTEST_LINKED_AS_SHARED_LIBRARY -#define GTEST_API_ __declspec(dllimport) -#elif GTEST_CREATE_SHARED_LIBRARY -#define GTEST_API_ __declspec(dllexport) -#endif - -#endif // _MSC_VER - -#ifndef GTEST_API_ -#define GTEST_API_ -#endif - -namespace testing { - -class Message; - -namespace internal { - -class String; - -typedef ::std::stringstream StrStream; - -// A helper for suppressing warnings on constant condition. It just -// returns 'condition'. -GTEST_API_ bool IsTrue(bool condition); - -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - -// Defines RE. - -// A simple C++ wrapper for . It uses the POSIX Extended -// Regular Expression syntax. -class GTEST_API_ RE { - public: - // A copy constructor is required by the Standard to initialize object - // references from r-values. - RE(const RE& other) { Init(other.pattern()); } - - // Constructs an RE from a string. - RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT - -#if GTEST_HAS_GLOBAL_STRING - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT -#endif // GTEST_HAS_GLOBAL_STRING - - RE(const char* regex) { Init(regex); } // NOLINT - ~RE(); - - // Returns the string representation of the regex. - const char* pattern() const { return pattern_; } - - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re - // matches a substring of str (including str itself). - // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work - // when str contains NUL characters. - static bool FullMatch(const ::std::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::std::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#if GTEST_HAS_GLOBAL_STRING - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } -#endif // GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const char* str, const RE& re); - static bool PartialMatch(const char* str, const RE& re); - - private: - void Init(const char* regex); - - // We use a const char* instead of a string, as Google Test may be used - // where string is not available. We also do not use Google Test's own - // String type here, in order to simplify dependencies between the - // files. - const char* pattern_; - bool is_valid_; -#if GTEST_USES_POSIX_RE - regex_t full_regex_; // For FullMatch(). - regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE - const char* full_pattern_; // For FullMatch(); -#endif - - GTEST_DISALLOW_ASSIGN_(RE); -}; - -// Defines logging utilities: -// GTEST_LOG_(severity) - logs messages at the specified severity level. The -// message itself is streamed into the macro. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. - -enum GTestLogSeverity { - GTEST_INFO, - GTEST_WARNING, - GTEST_ERROR, - GTEST_FATAL -}; - -// Formats log entry severity, provides a stream object for streaming the -// log message, and terminates the message with a newline when going out of -// scope. -class GTEST_API_ GTestLog { - public: - GTestLog(GTestLogSeverity severity, const char* file, int line); - - // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. - ~GTestLog(); - - ::std::ostream& GetStream() { return ::std::cerr; } - - private: - const GTestLogSeverity severity_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); -}; - -#define GTEST_LOG_(severity) \ - ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ - __FILE__, __LINE__).GetStream() - -inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } - -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GTEST_CHECK_(boolean_condition); -// or -// GTEST_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " - -// An all-mode assert to verify that the given POSIX-style function -// call returns 0 (indicating success). Known limitation: this -// doesn't expand to a balanced 'if' statement, so enclose the macro -// in {} if you need to use it as the only statement in an 'if' -// branch. -#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ - if (const int gtest_error = (posix_call)) \ - GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ - << gtest_error - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Downcasts the pointer of type Base to Derived. -// Derived must be a subclass of Base. The parameter MUST -// point to a class of type Derived, not any subclass of it. -// When RTTI is available, the function performs a runtime -// check to enforce this. -template -Derived* CheckedDowncastToActualType(Base* base) { -#if GTEST_HAS_RTTI - GTEST_CHECK_(typeid(*base) == typeid(Derived)); - return dynamic_cast(base); // NOLINT -#else - return static_cast(base); // Poor man's downcast. -#endif -} - -#if GTEST_HAS_STREAM_REDIRECTION_ - -// Defines the stderr capturer: -// CaptureStdout - starts capturing stdout. -// GetCapturedStdout - stops capturing stdout and returns the captured string. -// CaptureStderr - starts capturing stderr. -// GetCapturedStderr - stops capturing stderr and returns the captured string. -// -GTEST_API_ void CaptureStdout(); -GTEST_API_ String GetCapturedStdout(); -GTEST_API_ void CaptureStderr(); -GTEST_API_ String GetCapturedStderr(); - -#endif // GTEST_HAS_STREAM_REDIRECTION_ - - -#if GTEST_HAS_DEATH_TEST - -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; - -// GTEST_HAS_DEATH_TEST implies we have ::std::string. -const ::std::vector& GetArgvs(); - -#endif // GTEST_HAS_DEATH_TEST - -// Defines synchronization primitives. - -#if GTEST_HAS_PTHREAD - -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. -inline void SleepMilliseconds(int n) { - const timespec time = { - 0, // 0 seconds. - n * 1000L * 1000L, // And n ms. - }; - nanosleep(&time, NULL); -} - -// Allows a controller thread to pause execution of newly created -// threads until notified. Instances of this class must be created -// and destroyed in the controller thread. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. -class Notification { - public: - Notification() : notified_(false) {} - - // Notifies all threads created with this notification to start. Must - // be called from the controller thread. - void Notify() { notified_ = true; } - - // Blocks until the controller thread notifies. Must be called from a test - // thread. - void WaitForNotification() { - while(!notified_) { - SleepMilliseconds(10); - } - } - - private: - volatile bool notified_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); -}; - -// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. -// Consequently, it cannot select a correct instantiation of ThreadWithParam -// in order to call its Run(). Introducing ThreadWithParamBase as a -// non-templated base class for ThreadWithParam allows us to bypass this -// problem. -class ThreadWithParamBase { - public: - virtual ~ThreadWithParamBase() {} - virtual void Run() = 0; -}; - -// pthread_create() accepts a pointer to a function type with the C linkage. -// According to the Standard (7.5/1), function types with different linkages -// are different even if they are otherwise identical. Some compilers (for -// example, SunStudio) treat them as different types. Since class methods -// cannot be defined with C-linkage we need to define a free C-function to -// pass into pthread_create(). -extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { - static_cast(thread)->Run(); - return NULL; -} - -// Helper class for testing Google Test's multi-threading constructs. -// To use it, write: -// -// void ThreadFunc(int param) { /* Do things with param */ } -// Notification thread_can_start; -// ... -// // The thread_can_start parameter is optional; you can supply NULL. -// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); -// thread_can_start.Notify(); -// -// These classes are only for testing Google Test's own constructs. Do -// not use them in user tests, either directly or indirectly. -template -class ThreadWithParam : public ThreadWithParamBase { - public: - typedef void (*UserThreadFunc)(T); - - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) - : func_(func), - param_(param), - thread_can_start_(thread_can_start), - finished_(false) { - ThreadWithParamBase* const base = this; - // The thread can be created only after all fields except thread_ - // have been initialized. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); - } - ~ThreadWithParam() { Join(); } - - void Join() { - if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); - finished_ = true; - } - } - - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); - func_(param_); - } - - private: - const UserThreadFunc func_; // User-supplied thread function. - const T param_; // User-supplied parameter to the thread function. - // When non-NULL, used to block execution until the controller thread - // notifies. - Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. - pthread_t thread_; // The native thread object. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); -}; - -// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is -// true. -#include - -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: -// -// Mutex mutex; -// ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: -// -// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); -// -// You can forward declare a static mutex like this: -// -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); -// -// To create a dynamic mutex, just define an object of type Mutex. -class MutexBase { - public: - // Acquires this mutex. - void Lock() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); - owner_ = pthread_self(); - } - - // Releases this mutex. - void Unlock() { - // We don't protect writing to owner_ here, as it's the caller's - // responsibility to ensure that the current thread holds the - // mutex when this is called. - owner_ = 0; - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); - } - - // Does nothing if the current thread holds the mutex. Otherwise, crashes - // with high probability. - void AssertHeld() const { - GTEST_CHECK_(owner_ == pthread_self()) - << "The current thread is not holding the mutex @" << this; - } - - // A static mutex may be used before main() is entered. It may even - // be used before the dynamic initialization stage. Therefore we - // must be able to initialize a static mutex object at link time. - // This means MutexBase has to be a POD and its member variables - // have to be public. - public: - pthread_mutex_t mutex_; // The underlying pthread mutex. - pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. -}; - -// Forward-declares a static mutex. -#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex - -// Defines and statically (i.e. at link time) initializes a static mutex. -#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } - -// The Mutex class can only be used for mutexes created at runtime. It -// shares its API with MutexBase otherwise. -class Mutex : public MutexBase { - public: - Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - owner_ = 0; - } - ~Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); -}; - -// We cannot name this class MutexLock as the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. -class GTestMutexLock { - public: - explicit GTestMutexLock(MutexBase* mutex) - : mutex_(mutex) { mutex_->Lock(); } - - ~GTestMutexLock() { mutex_->Unlock(); } - - private: - MutexBase* const mutex_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); -}; - -typedef GTestMutexLock MutexLock; - -// Helpers for ThreadLocal. - -// pthread_key_create() requires DeleteThreadLocalValue() to have -// C-linkage. Therefore it cannot be templatized to access -// ThreadLocal. Hence the need for class -// ThreadLocalValueHolderBase. -class ThreadLocalValueHolderBase { - public: - virtual ~ThreadLocalValueHolderBase() {} -}; - -// Called by pthread to delete thread-local data stored by -// pthread_setspecific(). -extern "C" inline void DeleteThreadLocalValue(void* value_holder) { - delete static_cast(value_holder); -} - -// Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. -template -class ThreadLocal { - public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} - - ~ThreadLocal() { - // Destroys the managed object for the current thread, if any. - DeleteThreadLocalValue(pthread_getspecific(key_)); - - // Releases resources associated with the key. This will *not* - // delete managed objects for other threads. - GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); - } - - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } - - private: - // Holds a value of type T. - class ValueHolder : public ThreadLocalValueHolderBase { - public: - explicit ValueHolder(const T& value) : value_(value) {} - - T* pointer() { return &value_; } - - private: - T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); - }; - - static pthread_key_t CreateKey() { - pthread_key_t key; - // When a thread exits, DeleteThreadLocalValue() will be called on - // the object managed for that thread. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_key_create(&key, &DeleteThreadLocalValue)); - return key; - } - - T* GetOrCreateValue() const { - ThreadLocalValueHolderBase* const holder = - static_cast(pthread_getspecific(key_)); - if (holder != NULL) { - return CheckedDowncastToActualType(holder)->pointer(); - } - - ValueHolder* const new_holder = new ValueHolder(default_); - ThreadLocalValueHolderBase* const holder_base = new_holder; - GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); - return new_holder->pointer(); - } - - // A key pthreads uses for looking up per-thread values. - const pthread_key_t key_; - const T default_; // The default value for each thread. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); -}; - -#define GTEST_IS_THREADSAFE 1 - -#else // GTEST_HAS_PTHREAD - -// A dummy implementation of synchronization primitives (mutex, lock, -// and thread-local variable). Necessary for compiling Google Test where -// mutex is not supported - using Google Test in multiple threads is not -// supported on such platforms. - -class Mutex { - public: - Mutex() {} - void AssertHeld() const {} -}; - -#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::Mutex mutex - -#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex - -class GTestMutexLock { - public: - explicit GTestMutexLock(Mutex*) {} // NOLINT -}; - -typedef GTestMutexLock MutexLock; - -template -class ThreadLocal { - public: - ThreadLocal() : value_() {} - explicit ThreadLocal(const T& value) : value_(value) {} - T* pointer() { return &value_; } - const T* pointer() const { return &value_; } - const T& get() const { return value_; } - void set(const T& value) { value_ = value; } - private: - T value_; -}; - -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -#define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -GTEST_API_ size_t GetThreadCount(); - -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -#define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -#define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -#define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -#if GTEST_OS_WINDOWS -#define GTEST_PATH_SEP_ "\\" -#define GTEST_HAS_ALT_PATH_SEP_ 1 -// The biggest signed integer type the compiler supports. -typedef __int64 BiggestInt; -#else -#define GTEST_PATH_SEP_ "/" -#define GTEST_HAS_ALT_PATH_SEP_ 0 -typedef long long BiggestInt; // NOLINT -#endif // GTEST_OS_WINDOWS - -// The testing::internal::posix namespace holds wrappers for common -// POSIX functions. These wrappers hide the differences between -// Windows/MSVC and POSIX systems. Since some compilers define these -// standard functions as macros, the wrapper cannot have the same name -// as the wrapped function. - -namespace posix { - -// Functions with a different name on Windows. - -#if GTEST_OS_WINDOWS - -typedef struct _stat StatStruct; - -#ifdef __BORLANDC__ -inline int IsATTY(int fd) { return isatty(fd); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -#else // !__BORLANDC__ -#if GTEST_OS_WINDOWS_MOBILE -inline int IsATTY(int /* fd */) { return 0; } -#else -inline int IsATTY(int fd) { return _isatty(fd); } -#endif // GTEST_OS_WINDOWS_MOBILE -inline int StrCaseCmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return _strdup(src); } -#endif // __BORLANDC__ - -#if GTEST_OS_WINDOWS_MOBILE -inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } -// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this -// time and thus not defined there. -#else -inline int FileNo(FILE* file) { return _fileno(file); } -inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } -inline int RmDir(const char* dir) { return _rmdir(dir); } -inline bool IsDir(const StatStruct& st) { - return (_S_IFDIR & st.st_mode) != 0; -} -#endif // GTEST_OS_WINDOWS_MOBILE - -#else - -typedef struct stat StatStruct; - -inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } -inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return strcasecmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -inline int RmDir(const char* dir) { return rmdir(dir); } -inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } - -#endif // GTEST_OS_WINDOWS - -// Functions deprecated by MSVC 8.0. - -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -#pragma warning(push) -#pragma warning(disable:4996) -#endif - -inline const char* StrNCpy(char* dest, const char* src, size_t n) { - return strncpy(dest, src, n); -} - -// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and -// StrError() aren't needed on Windows CE at this time and thus not -// defined there. - -#if !GTEST_OS_WINDOWS_MOBILE -inline int ChDir(const char* dir) { return chdir(dir); } -#endif -inline FILE* FOpen(const char* path, const char* mode) { - return fopen(path, mode); -} -#if !GTEST_OS_WINDOWS_MOBILE -inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { - return freopen(path, mode, stream); -} -inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } -#endif -inline int FClose(FILE* fp) { return fclose(fp); } -#if !GTEST_OS_WINDOWS_MOBILE -inline int Read(int fd, void* buf, unsigned int count) { - return static_cast(read(fd, buf, count)); -} -inline int Write(int fd, const void* buf, unsigned int count) { - return static_cast(write(fd, buf, count)); -} -inline int Close(int fd) { return close(fd); } -inline const char* StrError(int errnum) { return strerror(errnum); } -#endif -inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE - // We are on Windows CE, which has no environment variables. - return NULL; -#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) - // Environment variables which we programmatically clear will be set to the - // empty string rather than unset (NULL). Handle that case. - const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; -#else - return getenv(name); -#endif -} - -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif - -#if GTEST_OS_WINDOWS_MOBILE -// Windows CE has no C library. The abort() function is used in -// several places in Google Test. This implementation provides a reasonable -// imitation of standard behaviour. -void Abort(); -#else -inline void Abort() { abort(); } -#endif // GTEST_OS_WINDOWS_MOBILE - -} // namespace posix - -// The maximum number a BiggestInt can represent. This definition -// works no matter BiggestInt is represented in one's complement or -// two's complement. -// -// We cannot rely on numeric_limits in STL, as __int64 and long long -// are not part of standard C++ and numeric_limits doesn't need to be -// defined for them. -const BiggestInt kMaxBiggestInt = - ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); - -// This template class serves as a compile-time function from size to -// type. It maps a size in bytes to a primitive type with that -// size. e.g. -// -// TypeWithSize<4>::UInt -// -// is typedef-ed to be unsigned int (unsigned integer made up of 4 -// bytes). -// -// Such functionality should belong to STL, but I cannot find it -// there. -// -// Google Test uses this class in the implementation of floating-point -// comparison. -// -// For now it only handles UInt (unsigned int) as that's all Google Test -// needs. Other types can be easily added in the future if need -// arises. -template -class TypeWithSize { - public: - // This prevents the user from using TypeWithSize with incorrect - // values of N. - typedef void UInt; -}; - -// The specialization for size 4. -template <> -class TypeWithSize<4> { - public: - // unsigned int has size 4 in both gcc and MSVC. - // - // As base/basictypes.h doesn't compile on Windows, we cannot use - // uint32, uint64, and etc here. - typedef int Int; - typedef unsigned int UInt; -}; - -// The specialization for size 8. -template <> -class TypeWithSize<8> { - public: -#if GTEST_OS_WINDOWS - typedef __int64 Int; - typedef unsigned __int64 UInt; -#else - typedef long long Int; // NOLINT - typedef unsigned long long UInt; // NOLINT -#endif // GTEST_OS_WINDOWS -}; - -// Integer types of known sizes. -typedef TypeWithSize<4>::Int Int32; -typedef TypeWithSize<4>::UInt UInt32; -typedef TypeWithSize<8>::Int Int64; -typedef TypeWithSize<8>::UInt UInt64; -typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. - -// Utilities for command line flags and environment variables. - -// Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name - -// Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ - GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ - GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) - -// Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ - GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) - -// Parses 'str' for a 32-bit signed integer. If successful, writes the result -// to *value and returns true; otherwise leaves *value unchanged and returns -// false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. -bool ParseInt32(const Message& src_text, const char* str, Int32* value); - -// Parses a bool/Int32/string from the environment variable -// corresponding to the given Google Test flag. -bool BoolFromGTestEnv(const char* flag, bool default_val); -GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); -const char* StringFromGTestEnv(const char* flag, const char* default_val); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - -#if GTEST_OS_LINUX -#include -#include -#include -#include -#endif // GTEST_OS_LINUX - -#include -#include -#include -#include -#include - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares the String class and functions used internally by -// Google Test. They are subject to change without notice. They should not used -// by code external to Google Test. -// -// This header file is #included by . -// It should not be #included by other files. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ - -#ifdef __BORLANDC__ -// string.h is not guaranteed to provide strcpy on C++ Builder. -#include -#endif - -#include - -#include - -namespace testing { -namespace internal { - -// String - a UTF-8 string class. -// -// For historic reasons, we don't use std::string. -// -// TODO(wan@google.com): replace this class with std::string or -// implement it in terms of the latter. -// -// Note that String can represent both NULL and the empty string, -// while std::string cannot represent NULL. -// -// NULL and the empty string are considered different. NULL is less -// than anything (including the empty string) except itself. -// -// This class only provides minimum functionality necessary for -// implementing Google Test. We do not intend to implement a full-fledged -// string class here. -// -// Since the purpose of this class is to provide a substitute for -// std::string on platforms where it cannot be used, we define a copy -// constructor and assignment operators such that we don't need -// conditional compilation in a lot of places. -// -// In order to make the representation efficient, the d'tor of String -// is not virtual. Therefore DO NOT INHERIT FROM String. -class GTEST_API_ String { - public: - // Static utility methods - - // Returns the input enclosed in double quotes if it's not NULL; - // otherwise returns "(null)". For example, "\"Hello\"" is returned - // for input "Hello". - // - // This is useful for printing a C string in the syntax of a literal. - // - // Known issue: escape sequences are not handled yet. - static String ShowCStringQuoted(const char* c_str); - - // Clones a 0-terminated C string, allocating memory using new. The - // caller is responsible for deleting the return value using - // delete[]. Returns the cloned string, or NULL if the input is - // NULL. - // - // This is different from strdup() in string.h, which allocates - // memory using malloc(). - static const char* CloneCString(const char* c_str); - -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be - // able to pass strings to Win32 APIs on CE we need to convert them - // to 'Unicode', UTF-16. - - // Creates a UTF-16 wide string from the given ANSI string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the wide string, or NULL if the - // input is NULL. - // - // The wide string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static LPCWSTR AnsiToUtf16(const char* c_str); - - // Creates an ANSI string from the given wide string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the ANSI string, or NULL if the - // input is NULL. - // - // The returned string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static const char* Utf16ToAnsi(LPCWSTR utf16_str); -#endif - - // Compares two C strings. Returns true iff they have the same content. - // - // Unlike strcmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CStringEquals(const char* lhs, const char* rhs); - - // Converts a wide C string to a String using the UTF-8 encoding. - // NULL will be converted to "(null)". If an error occurred during - // the conversion, "(failed to convert from wide string)" is - // returned. - static String ShowWideCString(const wchar_t* wide_c_str); - - // Similar to ShowWideCString(), except that this function encloses - // the converted string in double quotes. - static String ShowWideCStringQuoted(const wchar_t* wide_c_str); - - // Compares two wide C strings. Returns true iff they have the same - // content. - // - // Unlike wcscmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike strcasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CaseInsensitiveCStringEquals(const char* lhs, - const char* rhs); - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. - static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs); - - // Formats a list of arguments to a String, using the same format - // spec string as for printf. - // - // We do not use the StringPrintf class as it is not universally - // available. - // - // The result is limited to 4096 characters (including the tailing - // 0). If 4096 characters are not enough to format the input, - // "" is returned. - static String Format(const char* format, ...); - - // C'tors - - // The default c'tor constructs a NULL string. - String() : c_str_(NULL), length_(0) {} - - // Constructs a String by cloning a 0-terminated C string. - String(const char* a_c_str) { // NOLINT - if (a_c_str == NULL) { - c_str_ = NULL; - length_ = 0; - } else { - ConstructNonNull(a_c_str, strlen(a_c_str)); - } - } - - // Constructs a String by copying a given number of chars from a - // buffer. E.g. String("hello", 3) creates the string "hel", - // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", - // and String(NULL, 1) results in access violation. - String(const char* buffer, size_t a_length) { - ConstructNonNull(buffer, a_length); - } - - // The copy c'tor creates a new copy of the string. The two - // String objects do not share content. - String(const String& str) : c_str_(NULL), length_(0) { *this = str; } - - // D'tor. String is intended to be a final class, so the d'tor - // doesn't need to be virtual. - ~String() { delete[] c_str_; } - - // Allows a String to be implicitly converted to an ::std::string or - // ::string, and vice versa. Converting a String containing a NULL - // pointer to ::std::string or ::string is undefined behavior. - // Converting a ::std::string or ::string containing an embedded NUL - // character to a String will result in the prefix up to the first - // NUL character. - String(const ::std::string& str) { - ConstructNonNull(str.c_str(), str.length()); - } - - operator ::std::string() const { return ::std::string(c_str(), length()); } - -#if GTEST_HAS_GLOBAL_STRING - String(const ::string& str) { - ConstructNonNull(str.c_str(), str.length()); - } - - operator ::string() const { return ::string(c_str(), length()); } -#endif // GTEST_HAS_GLOBAL_STRING - - // Returns true iff this is an empty string (i.e. ""). - bool empty() const { return (c_str() != NULL) && (length() == 0); } - - // Compares this with another String. - // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 - // if this is greater than rhs. - int Compare(const String& rhs) const; - - // Returns true iff this String equals the given C string. A NULL - // string and a non-NULL string are considered not equal. - bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } - - // Returns true iff this String is less than the given String. A - // NULL string is considered less than "". - bool operator<(const String& rhs) const { return Compare(rhs) < 0; } - - // Returns true iff this String doesn't equal the given C string. A NULL - // string and a non-NULL string are considered not equal. - bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } - - // Returns true iff this String ends with the given suffix. *Any* - // String is considered to end with a NULL or empty suffix. - bool EndsWith(const char* suffix) const; - - // Returns true iff this String ends with the given suffix, not considering - // case. Any String is considered to end with a NULL or empty suffix. - bool EndsWithCaseInsensitive(const char* suffix) const; - - // Returns the length of the encapsulated string, or 0 if the - // string is NULL. - size_t length() const { return length_; } - - // Gets the 0-terminated C string this String object represents. - // The String object still owns the string. Therefore the caller - // should NOT delete the return value. - const char* c_str() const { return c_str_; } - - // Assigns a C string to this object. Self-assignment works. - const String& operator=(const char* a_c_str) { - return *this = String(a_c_str); - } - - // Assigns a String object to this object. Self-assignment works. - const String& operator=(const String& rhs) { - if (this != &rhs) { - delete[] c_str_; - if (rhs.c_str() == NULL) { - c_str_ = NULL; - length_ = 0; - } else { - ConstructNonNull(rhs.c_str(), rhs.length()); - } - } - - return *this; - } - - private: - // Constructs a non-NULL String from the given content. This - // function can only be called when data_ has not been allocated. - // ConstructNonNull(NULL, 0) results in an empty string (""). - // ConstructNonNull(NULL, non_zero) is undefined behavior. - void ConstructNonNull(const char* buffer, size_t a_length) { - char* const str = new char[a_length + 1]; - memcpy(str, buffer, a_length); - str[a_length] = '\0'; - c_str_ = str; - length_ = a_length; - } - - const char* c_str_; - size_t length_; -}; // class String - -// Streams a String to an ostream. Each '\0' character in the String -// is replaced with "\\0". -inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { - if (str.c_str() == NULL) { - os << "(null)"; - } else { - const char* const c_str = str.c_str(); - for (size_t i = 0; i != str.length(); i++) { - if (c_str[i] == '\0') { - os << "\\0"; - } else { - os << c_str[i]; - } - } - } - return os; -} - -// Gets the content of the StrStream's buffer as a String. Each '\0' -// character in the buffer is replaced with "\\0". -GTEST_API_ String StrStreamToString(StrStream* stream); - -// Converts a streamable value to a String. A NULL pointer is -// converted to "(null)". When the input value is a ::string, -// ::std::string, ::wstring, or ::std::wstring object, each NUL -// character in it is replaced with "\\0". - -// Declared here but defined in gtest.h, so that it has access -// to the definition of the Message class, required by the ARM -// compiler. -template -String StreamableToString(const T& streamable); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: keith.ray@gmail.com (Keith Ray) -// -// Google Test filepath utilities -// -// This header file declares classes and functions used internally by -// Google Test. They are subject to change without notice. -// -// This file is #included in . -// Do not include this header file separately! - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ - - -namespace testing { -namespace internal { - -// FilePath - a class for file and directory pathname manipulation which -// handles platform-specific conventions (like the pathname separator). -// Used for helper functions for naming files in a directory for xml output. -// Except for Set methods, all methods are const or static, which provides an -// "immutable value object" -- useful for peace of mind. -// A FilePath with a value ending in a path separator ("like/this/") represents -// a directory, otherwise it is assumed to represent a file. In either case, -// it may or may not represent an actual file or directory in the file system. -// Names are NOT checked for syntax correctness -- no checking for illegal -// characters, malformed paths, etc. - -class GTEST_API_ FilePath { - public: - FilePath() : pathname_("") { } - FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } - - explicit FilePath(const char* pathname) : pathname_(pathname) { - Normalize(); - } - - explicit FilePath(const String& pathname) : pathname_(pathname) { - Normalize(); - } - - FilePath& operator=(const FilePath& rhs) { - Set(rhs); - return *this; - } - - void Set(const FilePath& rhs) { - pathname_ = rhs.pathname_; - } - - String ToString() const { return pathname_; } - const char* c_str() const { return pathname_.c_str(); } - - // Returns the current working directory, or "" if unsuccessful. - static FilePath GetCurrentDir(); - - // Given directory = "dir", base_name = "test", number = 0, - // extension = "xml", returns "dir/test.xml". If number is greater - // than zero (e.g., 12), returns "dir/test_12.xml". - // On Windows platform, uses \ as the separator rather than /. - static FilePath MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension); - - // Given directory = "dir", relative_path = "test.xml", - // returns "dir/test.xml". - // On Windows, uses \ as the separator rather than /. - static FilePath ConcatPaths(const FilePath& directory, - const FilePath& relative_path); - - // Returns a pathname for a file that does not currently exist. The pathname - // will be directory/base_name.extension or - // directory/base_name_.extension if directory/base_name.extension - // already exists. The number will be incremented until a pathname is found - // that does not already exist. - // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. - // There could be a race condition if two or more processes are calling this - // function at the same time -- they could both pick the same filename. - static FilePath GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension); - - // Returns true iff the path is NULL or "". - bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } - - // If input name has a trailing separator character, removes it and returns - // the name, otherwise return the name string unmodified. - // On Windows platform, uses \ as the separator, other platforms use /. - FilePath RemoveTrailingPathSeparator() const; - - // Returns a copy of the FilePath with the directory part removed. - // Example: FilePath("path/to/file").RemoveDirectoryName() returns - // FilePath("file"). If there is no directory part ("just_a_file"), it returns - // the FilePath unmodified. If there is no file part ("just_a_dir/") it - // returns an empty FilePath (""). - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveDirectoryName() const; - - // RemoveFileName returns the directory path with the filename removed. - // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". - // If the FilePath is "a_file" or "/a_file", RemoveFileName returns - // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does - // not have a file, like "just/a/dir/", it returns the FilePath unmodified. - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveFileName() const; - - // Returns a copy of the FilePath with the case-insensitive extension removed. - // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns - // FilePath("dir/file"). If a case-insensitive extension is not - // found, returns a copy of the original FilePath. - FilePath RemoveExtension(const char* extension) const; - - // Creates directories so that path exists. Returns true if successful or if - // the directories already exist; returns false if unable to create - // directories for any reason. Will also return false if the FilePath does - // not represent a directory (that is, it doesn't end with a path separator). - bool CreateDirectoriesRecursively() const; - - // Create the directory so that path exists. Returns true if successful or - // if the directory already exists; returns false if unable to create the - // directory for any reason, including if the parent directory does not - // exist. Not named "CreateDirectory" because that's a macro on Windows. - bool CreateFolder() const; - - // Returns true if FilePath describes something in the file-system, - // either a file, directory, or whatever, and that something exists. - bool FileOrDirectoryExists() const; - - // Returns true if pathname describes a directory in the file-system - // that exists. - bool DirectoryExists() const; - - // Returns true if FilePath ends with a path separator, which indicates that - // it is intended to represent a directory. Returns false otherwise. - // This does NOT check that a directory (or file) actually exists. - bool IsDirectory() const; - - // Returns true if pathname describes a root directory. (Windows has one - // root directory per disk drive.) - bool IsRootDirectory() const; - - // Returns true if pathname describes an absolute path. - bool IsAbsolutePath() const; - - private: - // Replaces multiple consecutive separators with a single separator. - // For example, "bar///foo" becomes "bar/foo". Does not eliminate other - // redundancies that might be in a pathname involving "." or "..". - // - // A pathname with multiple consecutive separators may occur either through - // user error or as a result of some scripts or APIs that generate a pathname - // with a trailing separator. On other platforms the same API or script - // may NOT generate a pathname with a trailing "/". Then elsewhere that - // pathname may have another "/" and pathname components added to it, - // without checking for the separator already being there. - // The script language and operating system may allow paths like "foo//bar" - // but some of the functions in FilePath will not handle that correctly. In - // particular, RemoveTrailingPathSeparator() only removes one separator, and - // it is called in CreateDirectoriesRecursively() assuming that it will change - // a pathname from directory syntax (trailing separator) to filename syntax. - // - // On Windows this method also replaces the alternate path separator '/' with - // the primary path separator '\\', so that for example "bar\\/\\foo" becomes - // "bar\\foo". - - void Normalize(); - - // Returns a pointer to the last occurence of a valid path separator in - // the FilePath. On Windows, for example, both '/' and '\' are valid path - // separators. Returns NULL if no path separator was found. - const char* FindLastPathSeparator() const; - - String pathname_; -}; // class FilePath - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -// This file was GENERATED by command: -// pump.py gtest-type-util.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -// Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. -// Please contact googletestframework@googlegroups.com if you need -// more. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// #ifdef __GNUC__ is too general here. It is possible to use gcc without using -// libstdc++ (which is where cxxabi.h comes from). -#ifdef __GLIBCXX__ -#include -#endif // __GLIBCXX__ - -namespace testing { -namespace internal { - -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - -// GetTypeName() returns a human-readable name of type T. -template -String GetTypeName() { -#if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -#ifdef __GLIBCXX__ - int status = 0; - // gcc's implementation of typeid(T).name() mangles the type name, - // so we have to demangle it. - char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); - const String name_str(status == 0 ? readable_name : name); - free(readable_name); - return name_str; -#else - return name; -#endif // __GLIBCXX__ - -#else - return ""; -#endif // GTEST_HAS_RTTI -} - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. -struct None {}; - -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; -template -struct Types2 { - typedef T1 Head; - typedef Types1 Tail; -}; - -template -struct Types3 { - typedef T1 Head; - typedef Types2 Tail; -}; - -template -struct Types4 { - typedef T1 Head; - typedef Types3 Tail; -}; - -template -struct Types5 { - typedef T1 Head; - typedef Types4 Tail; -}; - -template -struct Types6 { - typedef T1 Head; - typedef Types5 Tail; -}; - -template -struct Types7 { - typedef T1 Head; - typedef Types6 Tail; -}; - -template -struct Types8 { - typedef T1 Head; - typedef Types7 Tail; -}; - -template -struct Types9 { - typedef T1 Head; - typedef Types8 Tail; -}; - -template -struct Types10 { - typedef T1 Head; - typedef Types9 Tail; -}; - -template -struct Types11 { - typedef T1 Head; - typedef Types10 Tail; -}; - -template -struct Types12 { - typedef T1 Head; - typedef Types11 Tail; -}; - -template -struct Types13 { - typedef T1 Head; - typedef Types12 Tail; -}; - -template -struct Types14 { - typedef T1 Head; - typedef Types13 Tail; -}; - -template -struct Types15 { - typedef T1 Head; - typedef Types14 Tail; -}; - -template -struct Types16 { - typedef T1 Head; - typedef Types15 Tail; -}; - -template -struct Types17 { - typedef T1 Head; - typedef Types16 Tail; -}; - -template -struct Types18 { - typedef T1 Head; - typedef Types17 Tail; -}; - -template -struct Types19 { - typedef T1 Head; - typedef Types18 Tail; -}; - -template -struct Types20 { - typedef T1 Head; - typedef Types19 Tail; -}; - -template -struct Types21 { - typedef T1 Head; - typedef Types20 Tail; -}; - -template -struct Types22 { - typedef T1 Head; - typedef Types21 Tail; -}; - -template -struct Types23 { - typedef T1 Head; - typedef Types22 Tail; -}; - -template -struct Types24 { - typedef T1 Head; - typedef Types23 Tail; -}; - -template -struct Types25 { - typedef T1 Head; - typedef Types24 Tail; -}; - -template -struct Types26 { - typedef T1 Head; - typedef Types25 Tail; -}; - -template -struct Types27 { - typedef T1 Head; - typedef Types26 Tail; -}; - -template -struct Types28 { - typedef T1 Head; - typedef Types27 Tail; -}; - -template -struct Types29 { - typedef T1 Head; - typedef Types28 Tail; -}; - -template -struct Types30 { - typedef T1 Head; - typedef Types29 Tail; -}; - -template -struct Types31 { - typedef T1 Head; - typedef Types30 Tail; -}; - -template -struct Types32 { - typedef T1 Head; - typedef Types31 Tail; -}; - -template -struct Types33 { - typedef T1 Head; - typedef Types32 Tail; -}; - -template -struct Types34 { - typedef T1 Head; - typedef Types33 Tail; -}; - -template -struct Types35 { - typedef T1 Head; - typedef Types34 Tail; -}; - -template -struct Types36 { - typedef T1 Head; - typedef Types35 Tail; -}; - -template -struct Types37 { - typedef T1 Head; - typedef Types36 Tail; -}; - -template -struct Types38 { - typedef T1 Head; - typedef Types37 Tail; -}; - -template -struct Types39 { - typedef T1 Head; - typedef Types38 Tail; -}; - -template -struct Types40 { - typedef T1 Head; - typedef Types39 Tail; -}; - -template -struct Types41 { - typedef T1 Head; - typedef Types40 Tail; -}; - -template -struct Types42 { - typedef T1 Head; - typedef Types41 Tail; -}; - -template -struct Types43 { - typedef T1 Head; - typedef Types42 Tail; -}; - -template -struct Types44 { - typedef T1 Head; - typedef Types43 Tail; -}; - -template -struct Types45 { - typedef T1 Head; - typedef Types44 Tail; -}; - -template -struct Types46 { - typedef T1 Head; - typedef Types45 Tail; -}; - -template -struct Types47 { - typedef T1 Head; - typedef Types46 Tail; -}; - -template -struct Types48 { - typedef T1 Head; - typedef Types47 Tail; -}; - -template -struct Types49 { - typedef T1 Head; - typedef Types48 Tail; -}; - -template -struct Types50 { - typedef T1 Head; - typedef Types49 Tail; -}; - - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. -template -struct Types { - typedef internal::Types50 type; -}; - -template <> -struct Types { - typedef internal::Types0 type; -}; -template -struct Types { - typedef internal::Types1 type; -}; -template -struct Types { - typedef internal::Types2 type; -}; -template -struct Types { - typedef internal::Types3 type; -}; -template -struct Types { - typedef internal::Types4 type; -}; -template -struct Types { - typedef internal::Types5 type; -}; -template -struct Types { - typedef internal::Types6 type; -}; -template -struct Types { - typedef internal::Types7 type; -}; -template -struct Types { - typedef internal::Types8 type; -}; -template -struct Types { - typedef internal::Types9 type; -}; -template -struct Types { - typedef internal::Types10 type; -}; -template -struct Types { - typedef internal::Types11 type; -}; -template -struct Types { - typedef internal::Types12 type; -}; -template -struct Types { - typedef internal::Types13 type; -}; -template -struct Types { - typedef internal::Types14 type; -}; -template -struct Types { - typedef internal::Types15 type; -}; -template -struct Types { - typedef internal::Types16 type; -}; -template -struct Types { - typedef internal::Types17 type; -}; -template -struct Types { - typedef internal::Types18 type; -}; -template -struct Types { - typedef internal::Types19 type; -}; -template -struct Types { - typedef internal::Types20 type; -}; -template -struct Types { - typedef internal::Types21 type; -}; -template -struct Types { - typedef internal::Types22 type; -}; -template -struct Types { - typedef internal::Types23 type; -}; -template -struct Types { - typedef internal::Types24 type; -}; -template -struct Types { - typedef internal::Types25 type; -}; -template -struct Types { - typedef internal::Types26 type; -}; -template -struct Types { - typedef internal::Types27 type; -}; -template -struct Types { - typedef internal::Types28 type; -}; -template -struct Types { - typedef internal::Types29 type; -}; -template -struct Types { - typedef internal::Types30 type; -}; -template -struct Types { - typedef internal::Types31 type; -}; -template -struct Types { - typedef internal::Types32 type; -}; -template -struct Types { - typedef internal::Types33 type; -}; -template -struct Types { - typedef internal::Types34 type; -}; -template -struct Types { - typedef internal::Types35 type; -}; -template -struct Types { - typedef internal::Types36 type; -}; -template -struct Types { - typedef internal::Types37 type; -}; -template -struct Types { - typedef internal::Types38 type; -}; -template -struct Types { - typedef internal::Types39 type; -}; -template -struct Types { - typedef internal::Types40 type; -}; -template -struct Types { - typedef internal::Types41 type; -}; -template -struct Types { - typedef internal::Types42 type; -}; -template -struct Types { - typedef internal::Types43 type; -}; -template -struct Types { - typedef internal::Types44 type; -}; -template -struct Types { - typedef internal::Types45 type; -}; -template -struct Types { - typedef internal::Types46 type; -}; -template -struct Types { - typedef internal::Types47 type; -}; -template -struct Types { - typedef internal::Types48 type; -}; -template -struct Types { - typedef internal::Types49 type; -}; - -namespace internal { - -#define GTEST_TEMPLATE_ template class - -// The template "selector" struct TemplateSel is used to -// represent Tmpl, which must be a class template with one type -// parameter, as a type. TemplateSel::Bind::type is defined -// as the type Tmpl. This allows us to actually instantiate the -// template "selected" by TemplateSel. -// -// This trick is necessary for simulating typedef for class templates, -// which C++ doesn't support directly. -template -struct TemplateSel { - template - struct Bind { - typedef Tmpl type; - }; -}; - -#define GTEST_BIND_(TmplSel, T) \ - TmplSel::template Bind::type - -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; - -// Template lists of length 1, 2, 3, and so on. - -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; -}; -template -struct Templates2 { - typedef TemplateSel Head; - typedef Templates1 Tail; -}; - -template -struct Templates3 { - typedef TemplateSel Head; - typedef Templates2 Tail; -}; - -template -struct Templates4 { - typedef TemplateSel Head; - typedef Templates3 Tail; -}; - -template -struct Templates5 { - typedef TemplateSel Head; - typedef Templates4 Tail; -}; - -template -struct Templates6 { - typedef TemplateSel Head; - typedef Templates5 Tail; -}; - -template -struct Templates7 { - typedef TemplateSel Head; - typedef Templates6 Tail; -}; - -template -struct Templates8 { - typedef TemplateSel Head; - typedef Templates7 Tail; -}; - -template -struct Templates9 { - typedef TemplateSel Head; - typedef Templates8 Tail; -}; - -template -struct Templates10 { - typedef TemplateSel Head; - typedef Templates9 Tail; -}; - -template -struct Templates11 { - typedef TemplateSel Head; - typedef Templates10 Tail; -}; - -template -struct Templates12 { - typedef TemplateSel Head; - typedef Templates11 Tail; -}; - -template -struct Templates13 { - typedef TemplateSel Head; - typedef Templates12 Tail; -}; - -template -struct Templates14 { - typedef TemplateSel Head; - typedef Templates13 Tail; -}; - -template -struct Templates15 { - typedef TemplateSel Head; - typedef Templates14 Tail; -}; - -template -struct Templates16 { - typedef TemplateSel Head; - typedef Templates15 Tail; -}; - -template -struct Templates17 { - typedef TemplateSel Head; - typedef Templates16 Tail; -}; - -template -struct Templates18 { - typedef TemplateSel Head; - typedef Templates17 Tail; -}; - -template -struct Templates19 { - typedef TemplateSel Head; - typedef Templates18 Tail; -}; - -template -struct Templates20 { - typedef TemplateSel Head; - typedef Templates19 Tail; -}; - -template -struct Templates21 { - typedef TemplateSel Head; - typedef Templates20 Tail; -}; - -template -struct Templates22 { - typedef TemplateSel Head; - typedef Templates21 Tail; -}; - -template -struct Templates23 { - typedef TemplateSel Head; - typedef Templates22 Tail; -}; - -template -struct Templates24 { - typedef TemplateSel Head; - typedef Templates23 Tail; -}; - -template -struct Templates25 { - typedef TemplateSel Head; - typedef Templates24 Tail; -}; - -template -struct Templates26 { - typedef TemplateSel Head; - typedef Templates25 Tail; -}; - -template -struct Templates27 { - typedef TemplateSel Head; - typedef Templates26 Tail; -}; - -template -struct Templates28 { - typedef TemplateSel Head; - typedef Templates27 Tail; -}; - -template -struct Templates29 { - typedef TemplateSel Head; - typedef Templates28 Tail; -}; - -template -struct Templates30 { - typedef TemplateSel Head; - typedef Templates29 Tail; -}; - -template -struct Templates31 { - typedef TemplateSel Head; - typedef Templates30 Tail; -}; - -template -struct Templates32 { - typedef TemplateSel Head; - typedef Templates31 Tail; -}; - -template -struct Templates33 { - typedef TemplateSel Head; - typedef Templates32 Tail; -}; - -template -struct Templates34 { - typedef TemplateSel Head; - typedef Templates33 Tail; -}; - -template -struct Templates35 { - typedef TemplateSel Head; - typedef Templates34 Tail; -}; - -template -struct Templates36 { - typedef TemplateSel Head; - typedef Templates35 Tail; -}; - -template -struct Templates37 { - typedef TemplateSel Head; - typedef Templates36 Tail; -}; - -template -struct Templates38 { - typedef TemplateSel Head; - typedef Templates37 Tail; -}; - -template -struct Templates39 { - typedef TemplateSel Head; - typedef Templates38 Tail; -}; - -template -struct Templates40 { - typedef TemplateSel Head; - typedef Templates39 Tail; -}; - -template -struct Templates41 { - typedef TemplateSel Head; - typedef Templates40 Tail; -}; - -template -struct Templates42 { - typedef TemplateSel Head; - typedef Templates41 Tail; -}; - -template -struct Templates43 { - typedef TemplateSel Head; - typedef Templates42 Tail; -}; - -template -struct Templates44 { - typedef TemplateSel Head; - typedef Templates43 Tail; -}; - -template -struct Templates45 { - typedef TemplateSel Head; - typedef Templates44 Tail; -}; - -template -struct Templates46 { - typedef TemplateSel Head; - typedef Templates45 Tail; -}; - -template -struct Templates47 { - typedef TemplateSel Head; - typedef Templates46 Tail; -}; - -template -struct Templates48 { - typedef TemplateSel Head; - typedef Templates47 Tail; -}; - -template -struct Templates49 { - typedef TemplateSel Head; - typedef Templates48 Tail; -}; - -template -struct Templates50 { - typedef TemplateSel Head; - typedef Templates49 Tail; -}; - - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. -template -struct Templates { - typedef Templates50 type; -}; - -template <> -struct Templates { - typedef Templates0 type; -}; -template -struct Templates { - typedef Templates1 type; -}; -template -struct Templates { - typedef Templates2 type; -}; -template -struct Templates { - typedef Templates3 type; -}; -template -struct Templates { - typedef Templates4 type; -}; -template -struct Templates { - typedef Templates5 type; -}; -template -struct Templates { - typedef Templates6 type; -}; -template -struct Templates { - typedef Templates7 type; -}; -template -struct Templates { - typedef Templates8 type; -}; -template -struct Templates { - typedef Templates9 type; -}; -template -struct Templates { - typedef Templates10 type; -}; -template -struct Templates { - typedef Templates11 type; -}; -template -struct Templates { - typedef Templates12 type; -}; -template -struct Templates { - typedef Templates13 type; -}; -template -struct Templates { - typedef Templates14 type; -}; -template -struct Templates { - typedef Templates15 type; -}; -template -struct Templates { - typedef Templates16 type; -}; -template -struct Templates { - typedef Templates17 type; -}; -template -struct Templates { - typedef Templates18 type; -}; -template -struct Templates { - typedef Templates19 type; -}; -template -struct Templates { - typedef Templates20 type; -}; -template -struct Templates { - typedef Templates21 type; -}; -template -struct Templates { - typedef Templates22 type; -}; -template -struct Templates { - typedef Templates23 type; -}; -template -struct Templates { - typedef Templates24 type; -}; -template -struct Templates { - typedef Templates25 type; -}; -template -struct Templates { - typedef Templates26 type; -}; -template -struct Templates { - typedef Templates27 type; -}; -template -struct Templates { - typedef Templates28 type; -}; -template -struct Templates { - typedef Templates29 type; -}; -template -struct Templates { - typedef Templates30 type; -}; -template -struct Templates { - typedef Templates31 type; -}; -template -struct Templates { - typedef Templates32 type; -}; -template -struct Templates { - typedef Templates33 type; -}; -template -struct Templates { - typedef Templates34 type; -}; -template -struct Templates { - typedef Templates35 type; -}; -template -struct Templates { - typedef Templates36 type; -}; -template -struct Templates { - typedef Templates37 type; -}; -template -struct Templates { - typedef Templates38 type; -}; -template -struct Templates { - typedef Templates39 type; -}; -template -struct Templates { - typedef Templates40 type; -}; -template -struct Templates { - typedef Templates41 type; -}; -template -struct Templates { - typedef Templates42 type; -}; -template -struct Templates { - typedef Templates43 type; -}; -template -struct Templates { - typedef Templates44 type; -}; -template -struct Templates { - typedef Templates45 type; -}; -template -struct Templates { - typedef Templates46 type; -}; -template -struct Templates { - typedef Templates47 type; -}; -template -struct Templates { - typedef Templates48 type; -}; -template -struct Templates { - typedef Templates49 type; -}; - -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). - -template -struct TypeList { typedef Types1 type; }; - -template -struct TypeList > { - typedef typename Types::type type; -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - -// Due to C++ preprocessor weirdness, we need double indirection to -// concatenate two tokens when one of them is __LINE__. Writing -// -// foo ## __LINE__ -// -// will result in the token foo__LINE__, instead of foo followed by -// the current line number. For more details, see -// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 -#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) -#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar - -// Google Test defines the testing::Message class to allow construction of -// test messages via the << operator. The idea is that anything -// streamable to std::ostream can be streamed to a testing::Message. -// This allows a user to use his own types in Google Test assertions by -// overloading the << operator. -// -// util/gtl/stl_logging-inl.h overloads << for STL containers. These -// overloads cannot be defined in the std namespace, as that will be -// undefined behavior. Therefore, they are defined in the global -// namespace instead. -// -// C++'s symbol lookup rule (i.e. Koenig lookup) says that these -// overloads are visible in either the std namespace or the global -// namespace, but not other namespaces, including the testing -// namespace which Google Test's Message class is in. -// -// To allow STL containers (and other types that has a << operator -// defined in the global namespace) to be used in Google Test assertions, -// testing::Message must access the custom << operator from the global -// namespace. Hence this helper function. -// -// Note: Jeffrey Yasskin suggested an alternative fix by "using -// ::operator<<;" in the definition of Message's operator<<. That fix -// doesn't require a helper function, but unfortunately doesn't -// compile with MSVC. -template -inline void GTestStreamToHelper(std::ostream* os, const T& val) { - *os << val; -} - -namespace testing { - -// Forward declaration of classes. - -class AssertionResult; // Result of an assertion. -class Message; // Represents a failure message. -class Test; // Represents a test. -class TestInfo; // Information about a test. -class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. - -namespace internal { - -struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. -class TestInfoImpl; // Opaque implementation of TestInfo -class UnitTestImpl; // Opaque implementation of UnitTest - -// How many times InitGoogleTest() has been called. -extern int g_init_gtest_count; - -// The text used in failure messages to indicate the start of the -// stack trace. -GTEST_API_ extern const char kStackTraceMarker[]; - -// A secret type that Google Test users don't know about. It has no -// definition on purpose. Therefore it's impossible to create a -// Secret object, which is what we want. -class Secret; - -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -#define GTEST_IS_NULL_LITERAL_(x) false -#else -#define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ - -// Appends the user-supplied message to the Google-Test-generated message. -GTEST_API_ String AppendUserMessage(const String& gtest_msg, - const Message& user_msg); - -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); - - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. - -// Converts a streamable value to a String. A NULL pointer is -// converted to "(null)". When the input value is a ::string, -// ::std::string, ::wstring, or ::std::wstring object, each NUL -// character in it is replaced with "\\0". -// Declared here but defined in gtest.h, so that it has access -// to the definition of the Message class, required by the ARM -// compiler. -template -String StreamableToString(const T& streamable); - -// Formats a value to be used in a failure message. - -#ifdef GTEST_NEEDS_IS_POINTER_ - -// These are needed as the Nokia Symbian and IBM XL C/C++ compilers -// cannot decide between const T& and const T* in a function template. -// These compilers _can_ decide between class template specializations -// for T and T*, so a tr1::type_traits-like is_pointer works, and we -// can overload on that. - -// This overload makes sure that all pointers (including -// those to char or wchar_t) are printed as raw pointers. -template -inline String FormatValueForFailureMessage(internal::true_type /*dummy*/, - T* pointer) { - return StreamableToString(static_cast(pointer)); -} - -template -inline String FormatValueForFailureMessage(internal::false_type /*dummy*/, - const T& value) { - return StreamableToString(value); -} - -template -inline String FormatForFailureMessage(const T& value) { - return FormatValueForFailureMessage( - typename internal::is_pointer::type(), value); -} - -#else - -// These are needed as the above solution using is_pointer has the -// limitation that T cannot be a type without external linkage, when -// compiled using MSVC. - -template -inline String FormatForFailureMessage(const T& value) { - return StreamableToString(value); -} - -// This overload makes sure that all pointers (including -// those to char or wchar_t) are printed as raw pointers. -template -inline String FormatForFailureMessage(T* pointer) { - return StreamableToString(static_cast(pointer)); -} - -#endif // GTEST_NEEDS_IS_POINTER_ - -// These overloaded versions handle narrow and wide characters. -GTEST_API_ String FormatForFailureMessage(char ch); -GTEST_API_ String FormatForFailureMessage(wchar_t wchar); - -// When this operand is a const char* or char*, and the other operand -// is a ::std::string or ::string, we print this operand as a C string -// rather than a pointer. We do the same for wide strings. - -// This internal macro is used to avoid duplicated code. -#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ -inline String FormatForComparisonFailureMessage(\ - operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ - return operand1_printer(str);\ -}\ -inline String FormatForComparisonFailureMessage(\ - const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ - return operand1_printer(str);\ -} - -GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) -#if GTEST_HAS_STD_WSTRING -GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_STRING -GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) -#endif // GTEST_HAS_GLOBAL_STRING -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) -#endif // GTEST_HAS_GLOBAL_WSTRING - -#undef GTEST_FORMAT_IMPL_ - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -GTEST_API_ AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const String& expected_value, - const String& actual_value, - bool ignoring_case); - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -GTEST_API_ String GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value); - -// This template class represents an IEEE floating-point number -// (either single-precision or double-precision, depending on the -// template parameters). -// -// The purpose of this class is to do more sophisticated number -// comparison. (Due to round-off error, etc, it's very unlikely that -// two floating-points will be equal exactly. Hence a naive -// comparison by the == operation often doesn't work.) -// -// Format of IEEE floating-point: -// -// The most-significant bit being the leftmost, an IEEE -// floating-point looks like -// -// sign_bit exponent_bits fraction_bits -// -// Here, sign_bit is a single bit that designates the sign of the -// number. -// -// For float, there are 8 exponent bits and 23 fraction bits. -// -// For double, there are 11 exponent bits and 52 fraction bits. -// -// More details can be found at -// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -template -class FloatingPoint { - public: - // Defines the unsigned integer type that has the same size as the - // floating point number. - typedef typename TypeWithSize::UInt Bits; - - // Constants. - - // # of bits in a number. - static const size_t kBitCount = 8*sizeof(RawType); - - // # of fraction bits in a number. - static const size_t kFractionBitCount = - std::numeric_limits::digits - 1; - - // # of exponent bits in a number. - static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; - - // The mask for the sign bit. - static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); - - // The mask for the fraction bits. - static const Bits kFractionBitMask = - ~static_cast(0) >> (kExponentBitCount + 1); - - // The mask for the exponent bits. - static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); - - // How many ULP's (Units in the Last Place) we want to tolerate when - // comparing two numbers. The larger the value, the more error we - // allow. A 0 value means that two numbers must be exactly the same - // to be considered equal. - // - // The maximum error of a single floating-point operation is 0.5 - // units in the last place. On Intel CPU's, all floating-point - // calculations are done with 80-bit precision, while double has 64 - // bits. Therefore, 4 should be enough for ordinary use. - // - // See the following article for more details on ULP: - // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. - static const size_t kMaxUlps = 4; - - // Constructs a FloatingPoint from a raw floating-point number. - // - // On an Intel CPU, passing a non-normalized NAN (Not a Number) - // around may change its bits, although the new value is guaranteed - // to be also a NAN. Therefore, don't expect this constructor to - // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } - - // Static methods - - // Reinterprets a bit pattern as a floating-point number. - // - // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; - } - - // Returns the floating-point number that represent positive infinity. - static RawType Infinity() { - return ReinterpretBits(kExponentBitMask); - } - - // Non-static methods - - // Returns the bits that represents this number. - const Bits &bits() const { return u_.bits_; } - - // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } - - // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } - - // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } - - // Returns true iff this is NAN (not a number). - bool is_nan() const { - // It's a NAN if the exponent bits are all ones and the fraction - // bits are not entirely zeros. - return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); - } - - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: - // - // - returns false if either number is (or both are) NAN. - // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. - bool AlmostEquals(const FloatingPoint& rhs) const { - // The IEEE standard says that any comparison operation involving - // a NAN must return false. - if (is_nan() || rhs.is_nan()) return false; - - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) - <= kMaxUlps; - } - - private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - - // Converts an integer from the sign-and-magnitude representation to - // the biased representation. More precisely, let N be 2 to the - // power of (kBitCount - 1), an integer x is represented by the - // unsigned number x + N. - // - // For instance, - // - // -N + 1 (the most negative number representable using - // sign-and-magnitude) is represented by 1; - // 0 is represented by N; and - // N - 1 (the biggest number representable using - // sign-and-magnitude) is represented by 2N - 1. - // - // Read http://en.wikipedia.org/wiki/Signed_number_representations - // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits &sam) { - if (kSignBitMask & sam) { - // sam represents a negative number. - return ~sam + 1; - } else { - // sam represents a positive number. - return kSignBitMask | sam; - } - } - - // Given two numbers in the sign-and-magnitude representation, - // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, - const Bits &sam2) { - const Bits biased1 = SignAndMagnitudeToBiased(sam1); - const Bits biased2 = SignAndMagnitudeToBiased(sam2); - return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); - } - - FloatingPointUnion u_; -}; - -// Typedefs the instances of the FloatingPoint template class that we -// care to use. -typedef FloatingPoint Float; -typedef FloatingPoint Double; - -// In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign -// unique IDs to fixture classes and compare them. The TypeId type is -// used to hold such IDs. The user should treat TypeId as an opaque -// type: the only operation allowed on TypeId values is to compare -// them for equality using the == operator. -typedef const void* TypeId; - -template -class TypeIdHelper { - public: - // dummy_ must not have a const type. Otherwise an overly eager - // compiler (e.g. MSVC 7.1 & 8.0) may try to merge - // TypeIdHelper::dummy_ for different Ts as an "optimization". - static bool dummy_; -}; - -template -bool TypeIdHelper::dummy_ = false; - -// GetTypeId() returns the ID of type T. Different values will be -// returned for different types. Calling the function twice with the -// same type argument is guaranteed to return the same ID. -template -TypeId GetTypeId() { - // The compiler is required to allocate a different - // TypeIdHelper::dummy_ variable for each T used to instantiate - // the template. Therefore, the address of dummy_ is guaranteed to - // be unique. - return &(TypeIdHelper::dummy_); -} - -// Returns the type ID of ::testing::Test. Always call this instead -// of GetTypeId< ::testing::Test>() to get the type ID of -// ::testing::Test, as the latter may give the wrong result due to a -// suspected linker bug when compiling Google Test as a Mac OS X -// framework. -GTEST_API_ TypeId GetTestTypeId(); - -// Defines the abstract factory interface that creates instances -// of a Test object. -class TestFactoryBase { - public: - virtual ~TestFactoryBase() {} - - // Creates a test instance to run. The instance is both created and destroyed - // within TestInfoImpl::Run() - virtual Test* CreateTest() = 0; - - protected: - TestFactoryBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); -}; - -// This class provides implementation of TeastFactoryBase interface. -// It is used in TEST and TEST_F macros. -template -class TestFactoryImpl : public TestFactoryBase { - public: - virtual Test* CreateTest() { return new TestClass; } -}; - -#if GTEST_OS_WINDOWS - -// Predicate-formatters for implementing the HRESULT checking macros -// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} -// We pass a long instead of HRESULT to avoid causing an -// include dependency for the HRESULT type. -GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, - long hr); // NOLINT -GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, - long hr); // NOLINT - -#endif // GTEST_OS_WINDOWS - -// Formats a source file path and a line number as they would appear -// in a compiler error message. -inline String FormatFileLocation(const char* file, int line) { - const char* const file_name = file == NULL ? "unknown file" : file; - if (line < 0) { - return String::Format("%s:", file_name); - } -#ifdef _MSC_VER - return String::Format("%s(%d):", file_name, line); -#else - return String::Format("%s:%d:", file_name, line); -#endif // _MSC_VER -} - -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// test_case_comment: a comment on the test case that will be included in -// the test output -// comment: a comment on the test that will be included in the -// test output -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr); - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { - public: - TypedTestCasePState() : registered_(false) {} - - // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the - // program. - bool AddTestName(const char* file, int line, const char* case_name, - const char* test_name) { - if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", - FormatFileLocation(file, line).c_str(), test_name, case_name); - fflush(stderr); - posix::Abort(); - } - defined_test_names_.insert(test_name); - return true; - } - - // Verifies that registered_tests match the test names in - // defined_test_names_; returns registered_tests if successful, or - // aborts the program otherwise. - const char* VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests); - - private: - bool registered_; - ::std::set defined_test_names_; -}; - -// Skips to the first non-space char after the first comma in 'str'; -// returns NULL if no comma is found in 'str'. -inline const char* SkipComma(const char* str) { - const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; - } - while (isspace(*(++comma))) {} - return comma; -} - -// Returns the prefix of 'str' before the first comma in it; returns -// the entire string if it contains no comma. -inline String GetPrefixUntilComma(const char* str) { - const char* comma = strchr(str, ','); - return comma == NULL ? String(str) : String(str, comma - str); -} - -// TypeParameterizedTest::Register() -// registers a list of type-parameterized tests with Google Test. The -// return value is insignificant - we just need to return something -// such that we can call this function in a namespace scope. -// -// Implementation note: The GTEST_TEMPLATE_ macro declares a template -// template parameter. It's defined in gtest-type-util.h. -template -class TypeParameterizedTest { - public: - // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, - // Types). Valid values for 'index' are [0, N - 1] where N is the - // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { - typedef typename Types::Head Type; - typedef Fixture FixtureClass; - typedef typename GTEST_BIND_(TestSel, Type) TestClass; - - // First, registers the first type-parameterized test in the type - // list. - MakeAndRegisterTestInfo( - String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", - case_name, index).c_str(), - GetPrefixUntilComma(test_names).c_str(), - String::Format("TypeParam = %s", GetTypeName().c_str()).c_str(), - "", - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl); - - // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTest { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { - return true; - } -}; - -// TypeParameterizedTestCase::Register() -// registers *all combinations* of 'Tests' and 'Types' with Google -// Test. The return value is insignificant - we just need to return -// something such that we can call this function in a namespace scope. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { - typedef typename Tests::Head Head; - - // First, register the first test in 'Test' for each type in 'Types'. - TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); - - // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { - return true; - } -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// Returns the current OS stack trace as a String. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, - int skip_count); - -// Helpers for suppressing warnings on unreachable code or constant -// condition. - -// Always returns true. -GTEST_API_ bool AlwaysTrue(); - -// Always returns false. -inline bool AlwaysFalse() { return !AlwaysTrue(); } - -// A simple Linear Congruential Generator for generating random -// numbers with a uniform distribution. Unlike rand() and srand(), it -// doesn't use global state (and therefore can't interfere with user -// code). Unlike rand_r(), it's portable. An LCG isn't very random, -// but it's good enough for our purposes. -class GTEST_API_ Random { - public: - static const UInt32 kMaxRange = 1u << 31; - - explicit Random(UInt32 seed) : state_(seed) {} - - void Reseed(UInt32 seed) { state_ = seed; } - - // Generates a random number from [0, range). Crashes if 'range' is - // 0 or greater than kMaxRange. - UInt32 Generate(UInt32 range); - - private: - UInt32 state_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); -}; - -} // namespace internal -} // namespace testing - -#define GTEST_MESSAGE_(message, result_type) \ - ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \ - = ::testing::Message() - -#define GTEST_FATAL_FAILURE_(message) \ - return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) - -#define GTEST_NONFATAL_FAILURE_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) - -#define GTEST_SUCCESS_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) - -// Suppresses MSVC warnings 4072 (unreachable code) for the code following -// statement if it returns or throws (or doesn't return or throw in some -// situations). -#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ - if (::testing::internal::AlwaysTrue()) { statement; } - -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const char* gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg = "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different " \ - "type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg = "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg) - -#define GTEST_TEST_NO_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const char* gtest_msg = "") { \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \ - " Actual: it throws."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ - fail(gtest_msg) - -#define GTEST_TEST_ANY_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const char* gtest_msg = "") { \ - bool gtest_caught_any = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - gtest_caught_any = true; \ - } \ - if (!gtest_caught_any) { \ - gtest_msg = "Expected: " #statement " throws an exception.\n" \ - " Actual: it doesn't."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ - fail(gtest_msg) - - -// Implements Boolean test assertions such as EXPECT_TRUE. expression can be -// either a boolean expression or an AssertionResult. text is a textual -// represenation of expression as it was passed into the EXPECT_TRUE. -#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar_ = \ - ::testing::AssertionResult(expression)) \ - ; \ - else \ - fail(::testing::internal::GetBoolAssertionFailureMessage(\ - gtest_ar_, text, #actual, #expected).c_str()) - -#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const char* gtest_msg = "") { \ - ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ - gtest_msg = "Expected: " #statement " doesn't generate new fatal " \ - "failures in the current thread.\n" \ - " Actual: it does."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ - fail(gtest_msg) - -// Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test - -// Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, "", "", \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for death tests. It is -// #included by gtest.h so a user doesn't need to include this -// directly. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines internal utilities needed for implementing -// death tests. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ - - -namespace testing { -namespace internal { - -GTEST_DECLARE_string_(internal_run_death_test); - -// Names of the flags (needed for parsing Google Test flags). -const char kDeathTestStyleFlag[] = "death_test_style"; -const char kDeathTestUseFork[] = "death_test_use_fork"; -const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; - -#if GTEST_HAS_DEATH_TEST - -// DeathTest is a class that hides much of the complexity of the -// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method -// returns a concrete class that depends on the prevailing death test -// style, as defined by the --gtest_death_test_style and/or -// --gtest_internal_run_death_test flags. - -// In describing the results of death tests, these terms are used with -// the corresponding definitions: -// -// exit status: The integer exit information in the format specified -// by wait(2) -// exit code: The integer code passed to exit(3), _exit(2), or -// returned from main() -class GTEST_API_ DeathTest { - public: - // Create returns false if there was an error determining the - // appropriate action to take for the current death test; for example, - // if the gtest_death_test_style flag is set to an invalid value. - // The LastMessage method will return a more detailed message in that - // case. Otherwise, the DeathTest pointer pointed to by the "test" - // argument is set. If the death test should be skipped, the pointer - // is set to NULL; otherwise, it is set to the address of a new concrete - // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); - DeathTest(); - virtual ~DeathTest() { } - - // A helper class that aborts a death test when it's deleted. - class ReturnSentinel { - public: - explicit ReturnSentinel(DeathTest* test) : test_(test) { } - ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } - private: - DeathTest* const test_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); - } GTEST_ATTRIBUTE_UNUSED_; - - // An enumeration of possible roles that may be taken when a death - // test is encountered. EXECUTE means that the death test logic should - // be executed immediately. OVERSEE means that the program should prepare - // the appropriate environment for a child process to execute the death - // test, then wait for it to complete. - enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; - - // An enumeration of the two reasons that a test might be aborted. - enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE }; - - // Assumes one of the above roles. - virtual TestRole AssumeRole() = 0; - - // Waits for the death test to finish and returns its status. - virtual int Wait() = 0; - - // Returns true if the death test passed; that is, the test process - // exited during the test, its exit status matches a user-supplied - // predicate, and its stderr output matches a user-supplied regular - // expression. - // The user-supplied predicate may be a macro expression rather - // than a function pointer or functor, or else Wait and Passed could - // be combined. - virtual bool Passed(bool exit_status_ok) = 0; - - // Signals that the death test did not die as expected. - virtual void Abort(AbortReason reason) = 0; - - // Returns a human-readable outcome message regarding the outcome of - // the last death test. - static const char* LastMessage(); - - static void set_last_death_test_message(const String& message); - - private: - // A string containing a description of the outcome of the last death test. - static String last_death_test_message_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); -}; - -// Factory interface for death tests. May be mocked out for testing. -class DeathTestFactory { - public: - virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; -}; - -// A concrete DeathTestFactory implementation for normal use. -class DefaultDeathTestFactory : public DeathTestFactory { - public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); -}; - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -GTEST_API_ bool ExitedUnsuccessfully(int exit_status); - -// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, -// ASSERT_EXIT*, and EXPECT_EXIT*. -#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) -// The symbol "fail" here expands to something into which a message -// can be streamed. - -// A class representing the parsed contents of the -// --gtest_internal_run_death_test flag, as it existed when -// RUN_ALL_TESTS was called. -class InternalRunDeathTestFlag { - public: - InternalRunDeathTestFlag(const String& a_file, - int a_line, - int an_index, - int a_write_fd) - : file_(a_file), line_(a_line), index_(an_index), - write_fd_(a_write_fd) {} - - ~InternalRunDeathTestFlag() { - if (write_fd_ >= 0) - posix::Close(write_fd_); - } - - String file() const { return file_; } - int line() const { return line_; } - int index() const { return index_; } - int write_fd() const { return write_fd_; } - - private: - String file_; - int line_; - int index_; - int write_fd_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); -}; - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); - -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -#define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ - -namespace testing { - -// This flag controls the style of death tests. Valid values are "threadsafe", -// meaning that the death test child process will re-execute the test binary -// from the start, running only a single death test, or "fast", -// meaning that the child process will execute the test logic immediately -// after forking. -GTEST_DECLARE_string_(death_test_style); - -#if GTEST_HAS_DEATH_TEST - -// The following macros are useful for writing death tests. - -// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is -// executed: -// -// 1. It generates a warning if there is more than one active -// thread. This is because it's safe to fork() or clone() only -// when there is a single thread. -// -// 2. The parent process clone()s a sub-process and runs the death -// test in it; the sub-process exits with code 0 at the end of the -// death test, if it hasn't exited already. -// -// 3. The parent process waits for the sub-process to terminate. -// -// 4. The parent process checks the exit code and error message of -// the sub-process. -// -// Examples: -// -// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); -// for (int i = 0; i < 5; i++) { -// EXPECT_DEATH(server.ProcessRequest(i), -// "Invalid request .* in ProcessRequest()") -// << "Failed to die on request " << i); -// } -// -// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); -// -// bool KilledBySIGHUP(int exit_code) { -// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; -// } -// -// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); -// -// On the regular expressions used in death tests: -// -// On POSIX-compliant systems (*nix), we use the library, -// which uses the POSIX extended regex syntax. -// -// On other platforms (e.g. Windows), we only support a simple regex -// syntax implemented as part of Google Test. This limited -// implementation should be enough most of the time when writing -// death tests; though it lacks many features you can find in PCRE -// or POSIX extended regex syntax. For example, we don't support -// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and -// repetition count ("x{5,7}"), among others. -// -// Below is the syntax that we do support. We chose it to be a -// subset of both PCRE and POSIX extended regex, so it's easy to -// learn wherever you come from. In the following: 'A' denotes a -// literal character, period (.), or a single \\ escape sequence; -// 'x' and 'y' denote regular expressions; 'm' and 'n' are for -// natural numbers. -// -// c matches any literal character c -// \\d matches any decimal digit -// \\D matches any character that's not a decimal digit -// \\f matches \f -// \\n matches \n -// \\r matches \r -// \\s matches any ASCII whitespace, including \n -// \\S matches any character that's not a whitespace -// \\t matches \t -// \\v matches \v -// \\w matches any letter, _, or decimal digit -// \\W matches any character that \\w doesn't match -// \\c matches any literal character c, which must be a punctuation -// . matches any single character except \n -// A? matches 0 or 1 occurrences of A -// A* matches 0 or many occurrences of A -// A+ matches 1 or many occurrences of A -// ^ matches the beginning of a string (not that of each line) -// $ matches the end of a string (not that of each line) -// xy matches x followed by y -// -// If you accidentally use PCRE or POSIX extended regex features -// not implemented by us, you will get a run-time failure. In that -// case, please try to rewrite your regular expression within the -// above syntax. -// -// This implementation is *not* meant to be as highly tuned or robust -// as a compiled regex library, but should perform well enough for a -// death test, which already incurs significant overhead by launching -// a child process. -// -// Known caveats: -// -// A "threadsafe" style death test obtains the path to the test -// program from argv[0] and re-executes it in the sub-process. For -// simplicity, the current implementation doesn't search the PATH -// when launching the sub-process. This means that the user must -// invoke the test program via a path that contains at least one -// path separator (e.g. path/to/foo_test and -// /absolute/path/to/bar_test are fine, but foo_test is not). This -// is rarely a problem as people usually don't put the test binary -// directory in PATH. -// -// TODO(wan@google.com): make thread-safe death tests search the PATH. - -// Asserts that a given statement causes the program to exit, with an -// integer exit status that satisfies predicate, and emitting error output -// that matches regex. -#define ASSERT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) - -// Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: -#define EXPECT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) - -// Asserts that a given statement causes the program to exit, either by -// explicitly exiting with a nonzero exit code or being killed by a -// signal, and emitting error output that matches regex. -#define ASSERT_DEATH(statement, regex) \ - ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: -#define EXPECT_DEATH(statement, regex) \ - EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: - -// Tests that an exit code describes a normal exit with a given exit code. -class GTEST_API_ ExitedWithCode { - public: - explicit ExitedWithCode(int exit_code); - bool operator()(int exit_status) const; - private: - // No implementation - assignment is unsupported. - void operator=(const ExitedWithCode& other); - - const int exit_code_; -}; - -#if !GTEST_OS_WINDOWS -// Tests that an exit code describes an exit due to termination by a -// given signal. -class GTEST_API_ KilledBySignal { - public: - explicit KilledBySignal(int signum); - bool operator()(int exit_status) const; - private: - const int signum_; -}; -#endif // !GTEST_OS_WINDOWS - -// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. -// The death testing framework causes this to have interesting semantics, -// since the sideeffects of the call are only visible in opt mode, and not -// in debug mode. -// -// In practice, this can be used to test functions that utilize the -// LOG(DFATAL) macro using the following style: -// -// int DieInDebugOr12(int* sideeffect) { -// if (sideeffect) { -// *sideeffect = 12; -// } -// LOG(DFATAL) << "death"; -// return 12; -// } -// -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { -// int sideeffect = 0; -// // Only asserts in dbg. -// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); -// -// #ifdef NDEBUG -// // opt-mode has sideeffect visible. -// EXPECT_EQ(12, sideeffect); -// #else -// // dbg-mode no visible sideeffect. -// EXPECT_EQ(0, sideeffect); -// #endif -// } -// -// This will assert that DieInDebugReturn12InOpt() crashes in debug -// mode, usually due to a DCHECK or LOG(DFATAL), but returns the -// appropriate fallback value (12 in this case) in opt mode. If you -// need to test that a function has appropriate side-effects in opt -// mode, include assertions against the side-effects. A general -// pattern for this is: -// -// EXPECT_DEBUG_DEATH({ -// // Side-effects here will have an effect after this statement in -// // opt mode, but none in debug mode. -// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); -// }, "death"); -// -#ifdef NDEBUG - -#define EXPECT_DEBUG_DEATH(statement, regex) \ - do { statement; } while (::testing::internal::AlwaysFalse()) - -#define ASSERT_DEBUG_DEATH(statement, regex) \ - do { statement; } while (::testing::internal::AlwaysFalse()) - -#else - -#define EXPECT_DEBUG_DEATH(statement, regex) \ - EXPECT_DEATH(statement, regex) - -#define ASSERT_DEBUG_DEATH(statement, regex) \ - ASSERT_DEATH(statement, regex) - -#endif // NDEBUG for EXPECT_DEBUG_DEATH -#endif // GTEST_HAS_DEATH_TEST - -// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and -// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if -// death tests are supported; otherwise they just issue a warning. This is -// useful when you are combining death test assertions with normal test -// assertions in one test. -#if GTEST_HAS_DEATH_TEST -#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH(statement, regex) -#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - ASSERT_DEATH(statement, regex) -#else -#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) -#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) -#endif - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the Message class. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! - -#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ - -#include - - -namespace testing { - -// The Message class works like an ostream repeater. -// -// Typical usage: -// -// 1. You stream a bunch of values to a Message object. -// It will remember the text in a StrStream. -// 2. Then you stream the Message object to an ostream. -// This causes the text in the Message to be streamed -// to the ostream. -// -// For example; -// -// testing::Message foo; -// foo << 1 << " != " << 2; -// std::cout << foo; -// -// will print "1 != 2". -// -// Message is not intended to be inherited from. In particular, its -// destructor is not virtual. -// -// Note that StrStream behaves differently in gcc and in MSVC. You -// can stream a NULL char pointer to it in the former, but not in the -// latter (it causes an access violation if you do). The Message -// class hides this difference by treating a NULL char pointer as -// "(null)". -class GTEST_API_ Message { - private: - // The type of basic IO manipulators (endl, ends, and flush) for - // narrow streams. - typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); - - public: - // Constructs an empty Message. - // We allocate the StrStream separately because it otherwise each use of - // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's - // stack frame leading to huge stack frames in some cases; gcc does not reuse - // the stack space. - Message() : ss_(new internal::StrStream) { - // By default, we want there to be enough precision when printing - // a double to a Message. - *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); - } - - // Copy constructor. - Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT - *ss_ << msg.GetString(); - } - - // Constructs a Message from a C-string. - explicit Message(const char* str) : ss_(new internal::StrStream) { - *ss_ << str; - } - - ~Message() { delete ss_; } -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else - // Streams a non-pointer value to this object. - template - inline Message& operator <<(const T& val) { - ::GTestStreamToHelper(ss_, val); - return *this; - } - - // Streams a pointer value to this object. - // - // This function is an overload of the previous one. When you - // stream a pointer to a Message, this definition will be used as it - // is more specialized. (The C++ Standard, section - // [temp.func.order].) If you stream a non-pointer, then the - // previous definition will be used. - // - // The reason for this overload is that streaming a NULL pointer to - // ostream is undefined behavior. Depending on the compiler, you - // may get "0", "(nil)", "(null)", or an access violation. To - // ensure consistent result across compilers, we always treat NULL - // as "(null)". - template - inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - ::GTestStreamToHelper(ss_, pointer); - } - return *this; - } -#endif // GTEST_OS_SYMBIAN - - // Since the basic IO manipulators are overloaded for both narrow - // and wide streams, we have to provide this specialized definition - // of operator <<, even though its body is the same as the - // templatized version above. Without this definition, streaming - // endl or other basic IO manipulators to Message will confuse the - // compiler. - Message& operator <<(BasicNarrowIoManip val) { - *ss_ << val; - return *this; - } - - // Instead of 1/0, we want to see true/false for bool values. - Message& operator <<(bool b) { - return *this << (b ? "true" : "false"); - } - - // These two overloads allow streaming a wide C string to a Message - // using the UTF-8 encoding. - Message& operator <<(const wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); - } - Message& operator <<(wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); - } - -#if GTEST_HAS_STD_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::std::wstring& wstr); -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - - // Gets the text streamed to this object so far as a String. - // Each '\0' character in the buffer is replaced with "\\0". - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::String GetString() const { - return internal::StrStreamToString(ss_); - } - - private: -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - ::GTestStreamToHelper(ss_, pointer); - } - } - template - inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { - ::GTestStreamToHelper(ss_, value); - } -#endif // GTEST_OS_SYMBIAN - - // We'll hold the text streamed to this object here. - internal::StrStream* const ss_; - - // We declare (but don't implement) this to prevent the compiler - // from implementing the assignment operator. - void operator=(const Message&); -}; - -// Streams a Message to an ostream. -inline std::ostream& operator <<(std::ostream& os, const Message& sb) { - return os << sb.GetString(); -} - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! - -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: vladl@google.com (Vlad Losev) -// -// Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) -// -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - - -// Value-parameterized tests allow you to test your code with different -// parameters without writing multiple copies of the same test. -// -// Here is how you use value-parameterized tests: - -#if 0 - -// To write value-parameterized tests, first you should define a fixture -// class. It must be derived from testing::TestWithParam, where T is -// the type of your parameter values. TestWithParam is itself derived -// from testing::Test. T can be any copyable type. If it's a raw pointer, -// you are responsible for managing the lifespan of the pointed values. - -class FooTest : public ::testing::TestWithParam { - // You can implement all the usual class fixture members here. -}; - -// Then, use the TEST_P macro to define as many parameterized tests -// for this fixture as you want. The _P suffix is for "parameterized" -// or "pattern", whichever you prefer to think. - -TEST_P(FooTest, DoesBlah) { - // Inside a test, access the test parameter with the GetParam() method - // of the TestWithParam class: - EXPECT_TRUE(foo.Blah(GetParam())); - ... -} - -TEST_P(FooTest, HasBlahBlah) { - ... -} - -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test -// case with any set of parameters you want. Google Test defines a number -// of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which -// are all in the testing namespace: -// -// -// Range(begin, end [, step]) - Yields values {begin, begin+step, -// begin+step+step, ...}. The values do not -// include end. step defaults to 1. -// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. -// ValuesIn(container) - Yields values from a C-style array, an STL -// ValuesIn(begin,end) container, or an iterator range [begin, end). -// Bool() - Yields sequence {false, true}. -// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product -// for the math savvy) of the values generated -// by the N generators. -// -// For more details, see comments at the definitions of these functions below -// in this file. -// -// The following statement will instantiate tests from the FooTest test case -// each with parameter values "meeny", "miny", and "moe". - -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); - -// To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different -// instantiations. The tests from the instantiation above will have -// these names: -// -// * InstantiationName/FooTest.DoesBlah/0 for "meeny" -// * InstantiationName/FooTest.DoesBlah/1 for "miny" -// * InstantiationName/FooTest.DoesBlah/2 for "moe" -// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" -// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" -// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" -// -// You can use these names in --gtest_filter. -// -// This statement will instantiate all tests from FooTest again, each -// with parameter values "cat" and "dog": - -const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); - -// The tests from the instantiation above will have these names: -// -// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" -// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" -// -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. -// -// Please also note that generator expressions (including parameters to the -// generators) are evaluated in InitGoogleTest(), after main() has started. -// This allows the user on one hand, to adjust generator parameters in order -// to dynamically determine a set of tests to run and on the other hand, -// give the user a chance to inspect the generated tests with Google Test -// reflection API before RUN_ALL_TESTS() is executed. -// -// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc -// for more examples. -// -// In the future, we plan to publish the API for defining new parameter -// generators. But for now this interface remains part of the internal -// implementation and is subject to change. - -#endif // 0 - - -#if !GTEST_OS_SYMBIAN -#include -#endif - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: vladl@google.com (Vlad Losev) - -// Type and function utilities for implementing parameterized tests. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ - -#include -#include -#include - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -// Copyright 2003 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: Dan Egnor (egnor@google.com) -// -// A "smart" pointer type with reference tracking. Every pointer to a -// particular object is kept on a circular linked list. When the last pointer -// to an object is destroyed or reassigned, the object is deleted. -// -// Used properly, this deletes the object when the last reference goes away. -// There are several caveats: -// - Like all reference counting schemes, cycles lead to leaks. -// - Each smart pointer is actually two pointers (8 bytes instead of 4). -// - Every time a pointer is assigned, the entire list of pointers to that -// object is traversed. This class is therefore NOT SUITABLE when there -// will often be more than two or three pointers to a particular object. -// - References are only tracked as long as linked_ptr<> objects are copied. -// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS -// will happen (double deletion). -// -// A good use of this class is storing object references in STL containers. -// You can safely put linked_ptr<> in a vector<>. -// Other uses may not be as good. -// -// Note: If you use an incomplete type with linked_ptr<>, the class -// *containing* linked_ptr<> must have a constructor and destructor (even -// if they do nothing!). -// -// Bill Gibbons suggested we use something like this. -// -// Thread Safety: -// Unlike other linked_ptr implementations, in this implementation -// a linked_ptr object is thread-safe in the sense that: -// - it's safe to copy linked_ptr objects concurrently, -// - it's safe to copy *from* a linked_ptr and read its underlying -// raw pointer (e.g. via get()) concurrently, and -// - it's safe to write to two linked_ptrs that point to the same -// shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid -// confusion with normal linked_ptr. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ - -#include -#include - - -namespace testing { -namespace internal { - -// Protects copying of all linked_ptr objects. -GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// This is used internally by all instances of linked_ptr<>. It needs to be -// a non-template class because different types of linked_ptr<> can refer to -// the same object (linked_ptr(obj) vs linked_ptr(obj)). -// So, it needs to be possible for different types of linked_ptr to participate -// in the same circular linked list, so we need a single class type here. -// -// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. -class linked_ptr_internal { - public: - // Create a new circle that includes only this instance. - void join_new() { - next_ = this; - } - - // Many linked_ptr operations may change p.link_ for some linked_ptr - // variable p in the same circle as this object. Therefore we need - // to prevent two such operations from occurring concurrently. - // - // Note that different types of linked_ptr objects can coexist in a - // circle (e.g. linked_ptr, linked_ptr, and - // linked_ptr). Therefore we must use a single mutex to - // protect all linked_ptr objects. This can create serious - // contention in production code, but is acceptable in a testing - // framework. - - // Join an existing circle. - // L < g_linked_ptr_mutex - void join(linked_ptr_internal const* ptr) { - MutexLock lock(&g_linked_ptr_mutex); - - linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; - p->next_ = this; - next_ = ptr; - } - - // Leave whatever circle we're part of. Returns true if we were the - // last member of the circle. Once this is done, you can join() another. - // L < g_linked_ptr_mutex - bool depart() { - MutexLock lock(&g_linked_ptr_mutex); - - if (next_ == this) return true; - linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; - p->next_ = next_; - return false; - } - - private: - mutable linked_ptr_internal const* next_; -}; - -template -class linked_ptr { - public: - typedef T element_type; - - // Take over ownership of a raw pointer. This should happen as soon as - // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } - ~linked_ptr() { depart(); } - - // Copy an existing linked_ptr<>, adding ourselves to the list of references. - template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } - linked_ptr(linked_ptr const& ptr) { // NOLINT - assert(&ptr != this); - copy(&ptr); - } - - // Assignment releases the old value and acquires the new. - template linked_ptr& operator=(linked_ptr const& ptr) { - depart(); - copy(&ptr); - return *this; - } - - linked_ptr& operator=(linked_ptr const& ptr) { - if (&ptr != this) { - depart(); - copy(&ptr); - } - return *this; - } - - // Smart pointer members. - void reset(T* ptr = NULL) { - depart(); - capture(ptr); - } - T* get() const { return value_; } - T* operator->() const { return value_; } - T& operator*() const { return *value_; } - // Release ownership of the pointed object and returns it. - // Sole ownership by this linked_ptr object is required. - T* release() { - bool last = link_.depart(); - assert(last); - T* v = value_; - value_ = NULL; - return v; - } - - bool operator==(T* p) const { return value_ == p; } - bool operator!=(T* p) const { return value_ != p; } - template - bool operator==(linked_ptr const& ptr) const { - return value_ == ptr.get(); - } - template - bool operator!=(linked_ptr const& ptr) const { - return value_ != ptr.get(); - } - - private: - template - friend class linked_ptr; - - T* value_; - linked_ptr_internal link_; - - void depart() { - if (link_.depart()) delete value_; - } - - void capture(T* ptr) { - value_ = ptr; - link_.join_new(); - } - - template void copy(linked_ptr const* ptr) { - value_ = ptr->get(); - if (value_) - link_.join(&ptr->link_); - else - link_.join_new(); - } -}; - -template inline -bool operator==(T* ptr, const linked_ptr& x) { - return ptr == x.get(); -} - -template inline -bool operator!=(T* ptr, const linked_ptr& x) { - return ptr != x.get(); -} - -// A function to convert T* into linked_ptr -// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation -// for linked_ptr >(new FooBarBaz(arg)) -template -linked_ptr make_linked_ptr(T* ptr) { - return linked_ptr(ptr); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ - -#if GTEST_HAS_PARAM_TEST - -namespace testing { -namespace internal { - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when -// TEST_P macro is used to define two tests with the same name -// but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); - -template class ParamGeneratorInterface; -template class ParamGenerator; - -// Interface for iterating over elements provided by an implementation -// of ParamGeneratorInterface. -template -class ParamIteratorInterface { - public: - virtual ~ParamIteratorInterface() {} - // A pointer to the base generator instance. - // Used only for the purposes of iterator comparison - // to make sure that two iterators belong to the same generator. - virtual const ParamGeneratorInterface* BaseGenerator() const = 0; - // Advances iterator to point to the next element - // provided by the generator. The caller is responsible - // for not calling Advance() on an iterator equal to - // BaseGenerator()->End(). - virtual void Advance() = 0; - // Clones the iterator object. Used for implementing copy semantics - // of ParamIterator. - virtual ParamIteratorInterface* Clone() const = 0; - // Dereferences the current iterator and provides (read-only) access - // to the pointed value. It is the caller's responsibility not to call - // Current() on an iterator equal to BaseGenerator()->End(). - // Used for implementing ParamGenerator::operator*(). - virtual const T* Current() const = 0; - // Determines whether the given iterator and other point to the same - // element in the sequence generated by the generator. - // Used for implementing ParamGenerator::operator==(). - virtual bool Equals(const ParamIteratorInterface& other) const = 0; -}; - -// Class iterating over elements provided by an implementation of -// ParamGeneratorInterface. It wraps ParamIteratorInterface -// and implements the const forward iterator concept. -template -class ParamIterator { - public: - typedef T value_type; - typedef const T& reference; - typedef ptrdiff_t difference_type; - - // ParamIterator assumes ownership of the impl_ pointer. - ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} - ParamIterator& operator=(const ParamIterator& other) { - if (this != &other) - impl_.reset(other.impl_->Clone()); - return *this; - } - - const T& operator*() const { return *impl_->Current(); } - const T* operator->() const { return impl_->Current(); } - // Prefix version of operator++. - ParamIterator& operator++() { - impl_->Advance(); - return *this; - } - // Postfix version of operator++. - ParamIterator operator++(int /*unused*/) { - ParamIteratorInterface* clone = impl_->Clone(); - impl_->Advance(); - return ParamIterator(clone); - } - bool operator==(const ParamIterator& other) const { - return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); - } - bool operator!=(const ParamIterator& other) const { - return !(*this == other); - } - - private: - friend class ParamGenerator; - explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; -}; - -// ParamGeneratorInterface is the binary interface to access generators -// defined in other translation units. -template -class ParamGeneratorInterface { - public: - typedef T ParamType; - - virtual ~ParamGeneratorInterface() {} - - // Generator interface definition - virtual ParamIteratorInterface* Begin() const = 0; - virtual ParamIteratorInterface* End() const = 0; -}; - -// Wraps ParamGeneratorInterface and provides general generator syntax -// compatible with the STL Container concept. -// This class implements copy initialization semantics and the contained -// ParamGeneratorInterface instance is shared among all copies -// of the original object. This is possible because that instance is immutable. -template -class ParamGenerator { - public: - typedef ParamIterator iterator; - - explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} - ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} - - ParamGenerator& operator=(const ParamGenerator& other) { - impl_ = other.impl_; - return *this; - } - - iterator begin() const { return iterator(impl_->Begin()); } - iterator end() const { return iterator(impl_->End()); } - - private: - ::testing::internal::linked_ptr > impl_; -}; - -// Generates values from a range of two comparable values. Can be used to -// generate sequences of user-defined types that implement operator+() and -// operator<(). -// This class is used in the Range() function. -template -class RangeGenerator : public ParamGeneratorInterface { - public: - RangeGenerator(T begin, T end, IncrementT step) - : begin_(begin), end_(end), - step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, begin_, 0, step_); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, end_, end_index_, step_); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, T value, int index, - IncrementT step) - : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - value_ = value_ + step_; - index_++; - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const int other_index = - CheckedDowncastToActualType(&other)->index_; - return index_ == other_index; - } - - private: - Iterator(const Iterator& other) - : ParamIteratorInterface(), - base_(other.base_), value_(other.value_), index_(other.index_), - step_(other.step_) {} - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - T value_; - int index_; - const IncrementT step_; - }; // class RangeGenerator::Iterator - - static int CalculateEndIndex(const T& begin, - const T& end, - const IncrementT& step) { - int end_index = 0; - for (T i = begin; i < end; i = i + step) - end_index++; - return end_index; - } - - // No implementation - assignment is unsupported. - void operator=(const RangeGenerator& other); - - const T begin_; - const T end_; - const IncrementT step_; - // The index for the end() iterator. All the elements in the generated - // sequence are indexed (0-based) to aid iterator comparison. - const int end_index_; -}; // class RangeGenerator - - -// Generates values from a pair of STL-style iterators. Used in the -// ValuesIn() function. The elements are copied from the source range -// since the source can be located on the stack, and the generator -// is likely to persist beyond that stack frame. -template -class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { - public: - template - ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) - : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, container_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, container_.end()); - } - - private: - typedef typename ::std::vector ContainerType; - - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - typename ContainerType::const_iterator iterator) - : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - ++iterator_; - value_.reset(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - // We need to use cached value referenced by iterator_ because *iterator_ - // can return a temporary object (and of type other then T), so just - // having "return &*iterator_;" doesn't work. - // value_ is updated here and not in Advance() because Advance() - // can advance iterator_ beyond the end of the range, and we cannot - // detect that fact. The client code, on the other hand, is - // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); - return value_.get(); - } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - return iterator_ == - CheckedDowncastToActualType(&other)->iterator_; - } - - private: - Iterator(const Iterator& other) - // The explicit constructor call suppresses a false warning - // emitted by gcc when supplied with the -Wextra option. - : ParamIteratorInterface(), - base_(other.base_), - iterator_(other.iterator_) {} - - const ParamGeneratorInterface* const base_; - typename ContainerType::const_iterator iterator_; - // A cached value of *iterator_. We keep it here to allow access by - // pointer in the wrapping iterator's operator->(). - // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, - // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; - }; // class ValuesInIteratorRangeGenerator::Iterator - - // No implementation - assignment is unsupported. - void operator=(const ValuesInIteratorRangeGenerator& other); - - const ContainerType container_; -}; // class ValuesInIteratorRangeGenerator - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Stores a parameter value and later creates tests parameterized with that -// value. -template -class ParameterizedTestFactory : public TestFactoryBase { - public: - typedef typename TestClass::ParamType ParamType; - explicit ParameterizedTestFactory(ParamType parameter) : - parameter_(parameter) {} - virtual Test* CreateTest() { - TestClass::SetParam(¶meter_); - return new TestClass(); - } - - private: - const ParamType parameter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactoryBase is a base class for meta-factories that create -// test factories for passing into MakeAndRegisterTestInfo function. -template -class TestMetaFactoryBase { - public: - virtual ~TestMetaFactoryBase() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactory creates test factories for passing into -// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives -// ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call -// it for each Test/Parameter value combination. Thus it needs meta factory -// creator class. -template -class TestMetaFactory - : public TestMetaFactoryBase { - public: - typedef typename TestCase::ParamType ParamType; - - TestMetaFactory() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase -// accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations -// and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects -// and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { - public: - virtual ~ParameterizedTestCaseInfoBase() {} - - // Base part of test case name for display purposes. - virtual const String& GetTestCaseName() const = 0; - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; - // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - virtual void RegisterTests() = 0; - - protected: - ParameterizedTestCaseInfoBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all -// generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { - public: - // ParamType and GeneratorCreationFunc are private types but are required - // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; - // A function that returns an instance of appropriate generator type. - typedef ParamGenerator(GeneratorCreationFunc)(); - - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} - - // Test case base name for display purposes. - virtual const String& GetTestCaseName() const { return test_case_name_; } - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } - // TEST_P macro uses AddTestPattern() to record information - // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation - // prefix). test_base_name is the name of an individual test without - // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, - TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); - } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information - // about a generator. - int AddTestCaseInstantiation(const char* instantiation_name, - GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); - return 0; // Return value used only to run this method in namespace scope. - } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { - for (typename TestInfoContainer::iterator test_it = tests_.begin(); - test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; - for (typename InstantiationContainer::iterator gen_it = - instantiations_.begin(); gen_it != instantiations_.end(); - ++gen_it) { - const String& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); - - Message test_case_name_stream; - if ( !instantiation_name.empty() ) - test_case_name_stream << instantiation_name.c_str() << "/"; - test_case_name_stream << test_info->test_case_base_name.c_str(); - - int i = 0; - for (typename ParamGenerator::iterator param_it = - generator.begin(); - param_it != generator.end(); ++param_it, ++i) { - Message test_name_stream; - test_name_stream << test_info->test_base_name.c_str() << "/" << i; - ::testing::internal::MakeAndRegisterTestInfo( - test_case_name_stream.GetString().c_str(), - test_name_stream.GetString().c_str(), - "", // test_case_comment - "", // comment; TODO(vladl@google.com): provide parameter value - // representation. - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, - test_info->test_meta_factory->CreateTestFactory(*param_it)); - } // for param_it - } // for gen_it - } // for test_it - } // RegisterTests - - private: - // LocalTestInfo structure keeps information about a single test registered - // with TEST_P macro. - struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const String test_case_base_name; - const String test_base_name; - const scoped_ptr > test_meta_factory; - }; - typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; - - const String test_case_name_; - TestInfoContainer tests_; - InstantiationContainer instantiations_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { - public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; - } - } - - // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - const char* file, - int line) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { - // Complain about incorrect usage of Google Test facilities - // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); - abort(); - } else { - // At this point we are sure that the object we found is of the same - // type we are looking for, so we downcast it to that type - // without further checks. - typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); - } - break; - } - } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); - test_case_infos_.push_back(typed_test_info); - } - return typed_test_info; - } - void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); - } - } - - private: - typedef ::std::vector TestCaseInfoContainer; - - TestCaseInfoContainer test_case_infos_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! - -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: vladl@google.com (Vlad Losev) - -// Type and function utilities for implementing parameterized tests. -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently Google Test supports at most 50 arguments in Values, -// and at most 10 arguments in Combine. Please contact -// googletestframework@googlegroups.com if you need more. -// Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is -// currently set at 10. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Forward declarations of ValuesIn(), which is implemented in -// include/gtest/gtest-param-test.h. -template -internal::ParamGenerator< - typename ::std::iterator_traits::value_type> ValuesIn( - ForwardIterator begin, ForwardIterator end); - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]); - -template -internal::ParamGenerator ValuesIn( - const Container& container); - -namespace internal { - -// Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -template -class ValueArray2 { - public: - ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray2& other); - - const T1 v1_; - const T2 v2_; -}; - -template -class ValueArray3 { - public: - ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray3& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; -}; - -template -class ValueArray4 { - public: - ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray4& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; -}; - -template -class ValueArray5 { - public: - ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray5& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; -}; - -template -class ValueArray6 { - public: - ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray6& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; -}; - -template -class ValueArray7 { - public: - ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray7& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; -}; - -template -class ValueArray8 { - public: - ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray8& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; -}; - -template -class ValueArray9 { - public: - ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray9& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; -}; - -template -class ValueArray10 { - public: - ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray10& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; -}; - -template -class ValueArray11 { - public: - ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray11& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; -}; - -template -class ValueArray12 { - public: - ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray12& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; -}; - -template -class ValueArray13 { - public: - ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray13& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; -}; - -template -class ValueArray14 { - public: - ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray14& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; -}; - -template -class ValueArray15 { - public: - ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray15& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; -}; - -template -class ValueArray16 { - public: - ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray16& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; -}; - -template -class ValueArray17 { - public: - ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray17& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; -}; - -template -class ValueArray18 { - public: - ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray18& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; -}; - -template -class ValueArray19 { - public: - ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray19& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; -}; - -template -class ValueArray20 { - public: - ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray20& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; -}; - -template -class ValueArray21 { - public: - ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray21& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; -}; - -template -class ValueArray22 { - public: - ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray22& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; -}; - -template -class ValueArray23 { - public: - ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, - v23_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray23& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; -}; - -template -class ValueArray24 { - public: - ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray24& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; -}; - -template -class ValueArray25 { - public: - ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray25& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; -}; - -template -class ValueArray26 { - public: - ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray26& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; -}; - -template -class ValueArray27 { - public: - ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray27& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; -}; - -template -class ValueArray28 { - public: - ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray28& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; -}; - -template -class ValueArray29 { - public: - ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray29& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; -}; - -template -class ValueArray30 { - public: - ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray30& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; -}; - -template -class ValueArray31 { - public: - ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray31& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; -}; - -template -class ValueArray32 { - public: - ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray32& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; -}; - -template -class ValueArray33 { - public: - ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray33& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; -}; - -template -class ValueArray34 { - public: - ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray34& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; -}; - -template -class ValueArray35 { - public: - ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, - v35_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray35& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; -}; - -template -class ValueArray36 { - public: - ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray36& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; -}; - -template -class ValueArray37 { - public: - ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray37& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; -}; - -template -class ValueArray38 { - public: - ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray38& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; -}; - -template -class ValueArray39 { - public: - ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray39& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; -}; - -template -class ValueArray40 { - public: - ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray40& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; -}; - -template -class ValueArray41 { - public: - ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray41& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; -}; - -template -class ValueArray42 { - public: - ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray42& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; -}; - -template -class ValueArray43 { - public: - ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), - v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray43& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; -}; - -template -class ValueArray44 { - public: - ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), - v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), - v43_(v43), v44_(v44) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray44& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; -}; - -template -class ValueArray45 { - public: - ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), - v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray45& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; -}; - -template -class ValueArray46 { - public: - ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray46& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; -}; - -template -class ValueArray47 { - public: - ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), - v47_(v47) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, - v47_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray47& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; -}; - -template -class ValueArray48 { - public: - ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), - v46_(v46), v47_(v47), v48_(v48) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, - v48_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray48& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; -}; - -template -class ValueArray49 { - public: - ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, - T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, - v48_, v49_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray49& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; -}; - -template -class ValueArray50 { - public: - ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, - T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} - - template - operator ParamGenerator() const { - const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, - v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, - v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, - v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, - v48_, v49_, v50_}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray50& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; - const T50 v50_; -}; - -#if GTEST_HAS_COMBINE -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Generates values from the Cartesian product of values produced -// by the argument generators. -// -template -class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator2(const ParamGenerator& g1, - const ParamGenerator& g2) - : g1_(g1), g2_(g2) {} - virtual ~CartesianProductGenerator2() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current2_; - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - ParamType current_value_; - }; // class CartesianProductGenerator2::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator2& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; -}; // class CartesianProductGenerator2 - - -template -class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator3(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - virtual ~CartesianProductGenerator3() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current3_; - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - ParamType current_value_; - }; // class CartesianProductGenerator3::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator3& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; -}; // class CartesianProductGenerator3 - - -template -class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator4(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - virtual ~CartesianProductGenerator4() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current4_; - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - ParamType current_value_; - }; // class CartesianProductGenerator4::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator4& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; -}; // class CartesianProductGenerator4 - - -template -class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator5(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - virtual ~CartesianProductGenerator5() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current5_; - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - ParamType current_value_; - }; // class CartesianProductGenerator5::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator5& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; -}; // class CartesianProductGenerator5 - - -template -class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator6(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - virtual ~CartesianProductGenerator6() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current6_; - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - ParamType current_value_; - }; // class CartesianProductGenerator6::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator6& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; -}; // class CartesianProductGenerator6 - - -template -class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator7(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - virtual ~CartesianProductGenerator7() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current7_; - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - ParamType current_value_; - }; // class CartesianProductGenerator7::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator7& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; -}; // class CartesianProductGenerator7 - - -template -class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator8(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - virtual ~CartesianProductGenerator8() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current8_; - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - ParamType current_value_; - }; // class CartesianProductGenerator8::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator8& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; -}; // class CartesianProductGenerator8 - - -template -class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator9(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - virtual ~CartesianProductGenerator9() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current9_; - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - ParamType current_value_; - }; // class CartesianProductGenerator9::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator9& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; -}; // class CartesianProductGenerator9 - - -template -class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator10(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9, - const ParamGenerator& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - virtual ~CartesianProductGenerator10() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end(), g10_, g10_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9, - const ParamGenerator& g10, - const typename ParamGenerator::iterator& current10) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9), - begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current10_; - if (current10_ == end10_) { - current10_ = begin10_; - ++current9_; - } - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_ && - current10_ == typed_other->current10_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_), - begin10_(other.begin10_), - end10_(other.end10_), - current10_(other.current10_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_ || - current10_ == end10_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - const typename ParamGenerator::iterator begin10_; - const typename ParamGenerator::iterator end10_; - typename ParamGenerator::iterator current10_; - ParamType current_value_; - }; // class CartesianProductGenerator10::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator10& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; - const ParamGenerator g10_; -}; // class CartesianProductGenerator10 - - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Helper classes providing Combine() with polymorphic features. They allow -// casting CartesianProductGeneratorN to ParamGenerator if T is -// convertible to U. -// -template -class CartesianProductHolder2 { - public: -CartesianProductHolder2(const Generator1& g1, const Generator2& g2) - : g1_(g1), g2_(g2) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator2( - static_cast >(g1_), - static_cast >(g2_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder2& other); - - const Generator1 g1_; - const Generator2 g2_; -}; // class CartesianProductHolder2 - -template -class CartesianProductHolder3 { - public: -CartesianProductHolder3(const Generator1& g1, const Generator2& g2, - const Generator3& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator3( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder3& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; -}; // class CartesianProductHolder3 - -template -class CartesianProductHolder4 { - public: -CartesianProductHolder4(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator4( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder4& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; -}; // class CartesianProductHolder4 - -template -class CartesianProductHolder5 { - public: -CartesianProductHolder5(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator5( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder5& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; -}; // class CartesianProductHolder5 - -template -class CartesianProductHolder6 { - public: -CartesianProductHolder6(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator6( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder6& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; -}; // class CartesianProductHolder6 - -template -class CartesianProductHolder7 { - public: -CartesianProductHolder7(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator7( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder7& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; -}; // class CartesianProductHolder7 - -template -class CartesianProductHolder8 { - public: -CartesianProductHolder8(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator8( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder8& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; -}; // class CartesianProductHolder8 - -template -class CartesianProductHolder9 { - public: -CartesianProductHolder9(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator9( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder9& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; -}; // class CartesianProductHolder9 - -template -class CartesianProductHolder10 { - public: -CartesianProductHolder10(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9, const Generator10& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator10( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_), - static_cast >(g10_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder10& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; - const Generator10 g10_; -}; // class CartesianProductHolder10 - -#endif // GTEST_HAS_COMBINE - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Functions producing parameter generators. -// -// Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated -// with a particular generator, Google Test creates and runs tests -// for each element in the sequence produced by the generator. -// -// In the following sample, tests from test case FooTest are instantiated -// each three times with parameter values 3, 5, and 8: -// -// class FooTest : public TestWithParam { ... }; -// -// TEST_P(FooTest, TestThis) { -// } -// TEST_P(FooTest, TestThat) { -// } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); -// - -// Range() returns generators providing sequences of values in a range. -// -// Synopsis: -// Range(start, end) -// - returns a generator producing a sequence of values {start, start+1, -// start+2, ..., }. -// Range(start, end, step) -// - returns a generator producing a sequence of values {start, start+step, -// start+step+step, ..., }. -// Notes: -// * The generated sequences never include end. For example, Range(1, 5) -// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) -// returns a generator producing {1, 3, 5, 7}. -// * start and end must have the same type. That type may be any integral or -// floating-point type or a user defined type satisfying these conditions: -// * It must be assignable (have operator=() defined). -// * It must have operator+() (operator+(int-compatible type) for -// two-operand version). -// * It must have operator<() defined. -// Elements in the resulting sequences will also have that type. -// * Condition start < end must be satisfied in order for resulting sequences -// to contain any elements. -// -template -internal::ParamGenerator Range(T start, T end, IncrementT step) { - return internal::ParamGenerator( - new internal::RangeGenerator(start, end, step)); -} - -template -internal::ParamGenerator Range(T start, T end) { - return Range(start, end, 1); -} - -// ValuesIn() function allows generation of tests with parameters coming from -// a container. -// -// Synopsis: -// ValuesIn(const T (&array)[N]) -// - returns a generator producing sequences with elements from -// a C-style array. -// ValuesIn(const Container& container) -// - returns a generator producing sequences with elements from -// an STL-style container. -// ValuesIn(Iterator begin, Iterator end) -// - returns a generator producing sequences with elements from -// a range [begin, end) defined by a pair of STL-style iterators. These -// iterators can also be plain C pointers. -// -// Please note that ValuesIn copies the values from the containers -// passed in and keeps them to generate tests in RUN_ALL_TESTS(). -// -// Examples: -// -// This instantiates tests from test case StringTest -// each with C-string values of "foo", "bar", and "baz": -// -// const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); -// -// This instantiates tests from test case StlStringTest -// each with STL strings with values "a" and "b": -// -// ::std::vector< ::std::string> GetParameterStrings() { -// ::std::vector< ::std::string> v; -// v.push_back("a"); -// v.push_back("b"); -// return v; -// } -// -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); -// -// -// This will also instantiate tests from CharTest -// each with parameter values 'a' and 'b': -// -// ::std::list GetParameterChars() { -// ::std::list list; -// list.push_back('a'); -// list.push_back('b'); -// return list; -// } -// ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); -// -template -internal::ParamGenerator< - typename ::std::iterator_traits::value_type> ValuesIn( - ForwardIterator begin, - ForwardIterator end) { - typedef typename ::std::iterator_traits::value_type - ParamType; - return internal::ParamGenerator( - new internal::ValuesInIteratorRangeGenerator(begin, end)); -} - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]) { - return ValuesIn(array, array + N); -} - -template -internal::ParamGenerator ValuesIn( - const Container& container) { - return ValuesIn(container.begin(), container.end()); -} - -// Values() allows generating tests from explicitly specified list of -// parameters. -// -// Synopsis: -// Values(T v1, T v2, ..., T vN) -// - returns a generator producing sequences with elements v1, v2, ..., vN. -// -// For example, this instantiates tests from test case BarTest each -// with values "one", "two", and "three": -// -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); -// -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. -// The exact type of values will depend on the type of parameter in BazTest. -// -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); -// -// Currently, Values() supports from 1 to 50 parameters. -// -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); -} - -// Bool() allows generating tests with parameters in a set of (false, true). -// -// Synopsis: -// Bool() -// - returns a generator producing sequences with elements {false, true}. -// -// It is useful when testing code that depends on Boolean flags. Combinations -// of multiple flags can be tested when several Bool()'s are combined using -// Combine() function. -// -// In the following example all tests in the test case FlagDependentTest -// will be instantiated twice with parameters false and true. -// -// class FlagDependentTest : public testing::TestWithParam { -// virtual void SetUp() { -// external_flag = GetParam(); -// } -// } -// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); -// -inline internal::ParamGenerator Bool() { - return Values(false, true); -} - -#if GTEST_HAS_COMBINE -// Combine() allows the user to combine two or more sequences to produce -// values of a Cartesian product of those sequences' elements. -// -// Synopsis: -// Combine(gen1, gen2, ..., genN) -// - returns a generator producing sequences with elements coming from -// the Cartesian product of elements from the sequences generated by -// gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types -// of elements from sequences produces by gen1, gen2, ..., genN. -// -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. -// -// Example: -// -// This will instantiate tests in test case AnimalTest each one with -// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), -// tuple("dog", BLACK), and tuple("dog", WHITE): -// -// enum Color { BLACK, GRAY, WHITE }; -// class AnimalTest -// : public testing::TestWithParam > {...}; -// -// TEST_P(AnimalTest, AnimalLooksNice) {...} -// -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); -// -// This will instantiate tests in FlagDependentTest with all variations of two -// Boolean flags: -// -// class FlagDependentTest -// : public testing::TestWithParam > { -// virtual void SetUp() { -// // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); -// } -// }; -// -// TEST_P(FlagDependentTest, TestFeature1) { -// // Test your code using external_flag_1 and external_flag_2 here. -// } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); -} - -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} - -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -#endif // GTEST_HAS_COMBINE - - - -#define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) - -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -// Copyright 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ - -// When you need to test the private or protected members of a class, -// use the FRIEND_TEST macro to declare your tests as friends of the -// class. For example: -// -// class MyClass { -// private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); -// }; -// -// class MyClassTest : public testing::Test { -// // ... -// }; -// -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. -// } - -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test - -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ - -#include -#include - -namespace testing { - -// A copyable object representing the result of a test part (i.e. an -// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). -// -// Don't inherit from TestPartResult as its destructor is not virtual. -class GTEST_API_ TestPartResult { - public: - // The possible outcomes of a test part (i.e. an assertion or an - // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). - enum Type { - kSuccess, // Succeeded. - kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. - }; - - // C'tor. TestPartResult does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, - const char* a_message) - : type_(a_type), - file_name_(a_file_name), - line_number_(a_line_number), - summary_(ExtractSummary(a_message)), - message_(a_message) { - } - - // Gets the outcome of the test part. - Type type() const { return type_; } - - // Gets the name of the source file where the test part took place, or - // NULL if it's unknown. - const char* file_name() const { return file_name_.c_str(); } - - // Gets the line in the source file where the test part took place, - // or -1 if it's unknown. - int line_number() const { return line_number_; } - - // Gets the summary of the failure message. - const char* summary() const { return summary_.c_str(); } - - // Gets the message associated with the test part. - const char* message() const { return message_.c_str(); } - - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } - - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } - - // Returns true iff the test part non-fatally failed. - bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - - // Returns true iff the test part fatally failed. - bool fatally_failed() const { return type_ == kFatalFailure; } - private: - Type type_; - - // Gets the summary of the failure message by omitting the stack - // trace in it. - static internal::String ExtractSummary(const char* message); - - // The name of the source file where the test part took place, or - // NULL if the source file is unknown. - internal::String file_name_; - // The line in the source file where the test part took place, or -1 - // if the line number is unknown. - int line_number_; - internal::String summary_; // The test failure summary. - internal::String message_; // The test failure message. -}; - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result); - -// An array of TestPartResult objects. -// -// Don't inherit from TestPartResultArray as its destructor is not -// virtual. -class GTEST_API_ TestPartResultArray { - public: - TestPartResultArray() {} - - // Appends the given TestPartResult to the array. - void Append(const TestPartResult& result); - - // Returns the TestPartResult at the given index (0-based). - const TestPartResult& GetTestPartResult(int index) const; - - // Returns the number of TestPartResult objects in the array. - int size() const; - - private: - std::vector array_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); -}; - -// This interface knows how to report a test part result. -class TestPartResultReporterInterface { - public: - virtual ~TestPartResultReporterInterface() {} - - virtual void ReportTestPartResult(const TestPartResult& result) = 0; -}; - -namespace internal { - -// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a -// statement generates new fatal failures. To do so it registers itself as the -// current test part result reporter. Besides checking if fatal failures were -// reported, it only delegates the reporting to the former result reporter. -// The original result reporter is restored in the destructor. -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -class GTEST_API_ HasNewFatalFailureHelper - : public TestPartResultReporterInterface { - public: - HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); - bool has_new_fatal_failure() const { return has_new_fatal_failure_; } - private: - bool has_new_fatal_failure_; - TestPartResultReporterInterface* original_reporter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); -}; - -} // namespace internal - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - -// This header implements typed tests and type-parameterized tests. - -// Typed (aka type-driven) tests repeat the same test for types in a -// list. You must know which types you want to test with when writing -// typed tests. Here's how you do it: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - public: - ... - typedef std::list List; - static T shared_; - T value_; -}; - -// Next, associate a list of types with the test case, which will be -// repeated for each type in the list. The typedef is necessary for -// the macro to parse correctly. -typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); - -// Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. -TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. - TypeParam n = this->value_; - - // To visit static members of the fixture, add the TestFixture:: - // prefix. - n += TestFixture::shared_; - - // To refer to typedefs in the fixture, add the "typename - // TestFixture::" prefix. - typename TestFixture::List values; - values.push_back(n); - ... -} - -TYPED_TEST(FooTest, HasPropertyA) { ... } - -#endif // 0 - -// Type-parameterized tests are abstract test patterns parameterized -// by a type. Compared with typed tests, type-parameterized tests -// allow you to define the test pattern without knowing what the type -// parameters are. The defined pattern can be instantiated with -// different types any number of times, in any number of translation -// units. -// -// If you are designing an interface or concept, you can define a -// suite of type-parameterized tests to verify properties that any -// valid implementation of the interface/concept should have. Then, -// each implementation can easily instantiate the test suite to verify -// that it conforms to the requirements, without having to write -// similar tests repeatedly. Here's an example: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - ... -}; - -// Next, declare that you will define a type-parameterized test case -// (the _P suffix is for "parameterized" or "pattern", whichever you -// prefer): -TYPED_TEST_CASE_P(FooTest); - -// Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. -TYPED_TEST_P(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - TypeParam n = 0; - ... -} - -TYPED_TEST_P(FooTest, HasPropertyA) { ... } - -// Now the tricky part: you need to register all test patterns before -// you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test -// case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); - -// Finally, you are free to instantiate the pattern with the types you -// want. If you put the above code in a header file, you can #include -// it in multiple C++ source files and instantiate it multiple times. -// -// To distinguish different instances of the pattern, the first -// argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for -// different instances. -typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); - -#endif // 0 - - -// Implements typed tests. - -#if GTEST_HAS_TYPED_TEST - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the typedef for the type parameters of the -// given test case. -#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -#define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -#define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() - -#endif // GTEST_HAS_TYPED_TEST - -// Implements type-parameterized tests. - -#if GTEST_HAS_TYPED_TEST_P - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact -// name of the namespace is subject to change without notice. -#define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. -// -// Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ - -// The variables defined in the type-parameterized test macros are -// static as typically these macros are used in a .h file that can be -// #included in multiple translation units linked together. -#define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -#define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() - -#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) - -#endif // GTEST_HAS_TYPED_TEST_P - -#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. - -namespace testing { - -// Declares the flags. - -// This flag temporary enables the disabled tests. -GTEST_DECLARE_bool_(also_run_disabled_tests); - -// This flag brings the debugger on an assertion failure. -GTEST_DECLARE_bool_(break_on_failure); - -// This flag controls whether Google Test catches all test-thrown exceptions -// and logs them as failures. -GTEST_DECLARE_bool_(catch_exceptions); - -// This flag enables using colors in terminal output. Available values are -// "yes" to enable colors, "no" (disable colors), or "auto" (the default) -// to let Google Test decide. -GTEST_DECLARE_string_(color); - -// This flag sets up the filter to select by name using a glob pattern -// the tests to run. If the filter is not given all tests are executed. -GTEST_DECLARE_string_(filter); - -// This flag causes the Google Test to list tests. None of the tests listed -// are actually run if the flag is provided. -GTEST_DECLARE_bool_(list_tests); - -// This flag controls whether Google Test emits a detailed XML report to a file -// in addition to its normal textual output. -GTEST_DECLARE_string_(output); - -// This flags control whether Google Test prints the elapsed time for each -// test. -GTEST_DECLARE_bool_(print_time); - -// This flag specifies the random number seed. -GTEST_DECLARE_int32_(random_seed); - -// This flag sets how many times the tests are repeated. The default value -// is 1. If the value is -1 the tests are repeating forever. -GTEST_DECLARE_int32_(repeat); - -// This flag controls whether Google Test includes Google Test internal -// stack frames in failure stack traces. -GTEST_DECLARE_bool_(show_internal_stack_frames); - -// When this flag is specified, tests' order is randomized on every iteration. -GTEST_DECLARE_bool_(shuffle); - -// This flag specifies the maximum number of stack frames to be -// printed in a failure message. -GTEST_DECLARE_int32_(stack_trace_depth); - -// When this flag is specified, a failed assertion will throw an -// exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. -GTEST_DECLARE_bool_(throw_on_failure); - -// The upper limit for valid stack trace depths. -const int kMaxStackTraceDepth = 100; - -namespace internal { - -class AssertHelper; -class DefaultGlobalTestPartResultReporter; -class ExecDeathTest; -class NoExecDeathTest; -class FinalSuccessChecker; -class GTestFlagSaver; -class TestInfoImpl; -class TestResultAccessor; -class TestEventListenersAccessor; -class TestEventRepeater; -class WindowsDeathTest; -class UnitTestImpl* GetUnitTestImpl(); -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const String& message); -class PrettyUnitTestResultPrinter; -class XmlUnitTestResultPrinter; - -// Converts a streamable value to a String. A NULL pointer is -// converted to "(null)". When the input value is a ::string, -// ::std::string, ::wstring, or ::std::wstring object, each NUL -// character in it is replaced with "\\0". -// Declared in gtest-internal.h but defined here, so that it has access -// to the definition of the Message class, required by the ARM -// compiler. -template -String StreamableToString(const T& streamable) { - return (Message() << streamable).GetString(); -} - -} // namespace internal - -// A class for indicating whether an assertion was successful. When -// the assertion wasn't successful, the AssertionResult object -// remembers a non-empty message that describes how it failed. -// -// To create an instance of this class, use one of the factory functions -// (AssertionSuccess() and AssertionFailure()). -// -// This class is useful for two purposes: -// 1. Defining predicate functions to be used with Boolean test assertions -// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts -// 2. Defining predicate-format functions to be -// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). -// -// For example, if you define IsEven predicate: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) -// will print the message -// -// Value of: IsEven(Fib(5)) -// Actual: false (5 is odd) -// Expected: true -// -// instead of a more opaque -// -// Value of: IsEven(Fib(5)) -// Actual: false -// Expected: true -// -// in case IsEven is a simple Boolean predicate. -// -// If you expect your predicate to be reused and want to support informative -// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up -// about half as often as positive ones in our tests), supply messages for -// both success and failure cases: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess() << n << " is even"; -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print -// -// Value of: IsEven(Fib(6)) -// Actual: true (8 is even) -// Expected: false -// -// NB: Predicates that support negative Boolean assertions have reduced -// performance in positive ones so be careful not to use them in tests -// that have lots (tens of thousands) of positive Boolean assertions. -// -// To use this class with EXPECT_PRED_FORMAT assertions such as: -// -// // Verifies that Foo() returns an even number. -// EXPECT_PRED_FORMAT1(IsEven, Foo()); -// -// you need to define: -// -// testing::AssertionResult IsEven(const char* expr, int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() -// << "Expected: " << expr << " is even\n Actual: it's " << n; -// } -// -// If Foo() returns 5, you will see the following message: -// -// Expected: Foo() is even -// Actual: it's 5 -// -class GTEST_API_ AssertionResult { - public: - // Copy constructor. - // Used in EXPECT_TRUE/FALSE(assertion_result). - AssertionResult(const AssertionResult& other); - // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} - - // Returns true iff the assertion succeeded. - operator bool() const { return success_; } // NOLINT - - // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. - AssertionResult operator!() const; - - // Returns the text streamed into this AssertionResult. Test assertions - // use it when they fail (i.e., the predicate's outcome doesn't match the - // assertion's expectation). When nothing has been streamed into the - // object, returns an empty string. - const char* message() const { - return message_.get() != NULL && message_->c_str() != NULL ? - message_->c_str() : ""; - } - // TODO(vladl@google.com): Remove this after making sure no clients use it. - // Deprecated; please use message() instead. - const char* failure_message() const { return message(); } - - // Streams a custom failure message into this object. - template AssertionResult& operator<<(const T& value); - - private: - // No implementation - we want AssertionResult to be - // copy-constructible but not assignable. - void operator=(const AssertionResult& other); - - // Stores result of the assertion predicate. - bool success_; - // Stores the message describing the condition in case the expectation - // construct is not satisfied with the predicate's outcome. - // Referenced via a pointer to avoid taking too much stack frame space - // with test assertions. - internal::scoped_ptr message_; -}; // class AssertionResult - -// Streams a custom failure message into this object. -template -AssertionResult& AssertionResult::operator<<(const T& value) { - Message msg; - if (message_.get() != NULL) - msg << *message_; - msg << value; - message_.reset(new internal::String(msg.GetString())); - return *this; -} - -// Makes a successful assertion result. -GTEST_API_ AssertionResult AssertionSuccess(); - -// Makes a failed assertion result. -GTEST_API_ AssertionResult AssertionFailure(); - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << msg. -GTEST_API_ AssertionResult AssertionFailure(const Message& msg); - -// The abstract class that all tests inherit from. -// -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. -// -// When you define a test using the TEST macro, you don't need to -// explicitly derive from Test - the TEST macro automatically does -// this for you. -// -// The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: -// -// class FooTest : public testing::Test { -// protected: -// virtual void SetUp() { ... } -// virtual void TearDown() { ... } -// ... -// }; -// -// TEST_F(FooTest, Bar) { ... } -// TEST_F(FooTest, Baz) { ... } -// -// Test is not copyable. -class GTEST_API_ Test { - public: - friend class internal::TestInfoImpl; - - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - - // The d'tor is virtual as we intend to inherit from Test. - virtual ~Test(); - - // Sets up the stuff shared by all tests in this test case. - // - // Google Test will call Foo::SetUpTestCase() before running the first - // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super - // class. - static void SetUpTestCase() {} - - // Tears down the stuff shared by all tests in this test case. - // - // Google Test will call Foo::TearDownTestCase() after running the last - // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super - // class. - static void TearDownTestCase() {} - - // Returns true iff the current test has a fatal failure. - static bool HasFatalFailure(); - - // Returns true iff the current test has a non-fatal failure. - static bool HasNonfatalFailure(); - - // Returns true iff the current test has a (either fatal or - // non-fatal) failure. - static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - - // Logs a property for the current test. Only the last value for a given - // key is remembered. - // These are public static so they can be called from utility functions - // that are not members of the test fixture. - // The arguments are const char* instead strings, as Google Test is used - // on platforms where string doesn't compile. - // - // Note that a driving consideration for these RecordProperty methods - // was to produce xml output suited to the Greenspan charting utility, - // which at present will only chart values that fit in a 32-bit int. It - // is the user's responsibility to restrict their values to 32-bit ints - // if they intend them to be used with Greenspan. - static void RecordProperty(const char* key, const char* value); - static void RecordProperty(const char* key, int value); - - protected: - // Creates a Test object. - Test(); - - // Sets up the test fixture. - virtual void SetUp(); - - // Tears down the test fixture. - virtual void TearDown(); - - private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. - static bool HasSameFixtureClass(); - - // Runs the test after the test fixture has been set up. - // - // A sub-class must implement this to define the test logic. - // - // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. - // Instead, use the TEST or TEST_F macro. - virtual void TestBody() = 0; - - // Sets up, executes, and tears down the test. - void Run(); - - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; - - // Often a user mis-spells SetUp() as Setup() and spends a long time - // wondering why it is never called by Google Test. The declaration of - // the following method is solely for catching such an error at - // compile time: - // - // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. - // - // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. - // - // DO NOT OVERRIDE THIS FUNCTION. - // - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } - - // We disallow copying Tests. - GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); -}; - -typedef internal::TimeInMillis TimeInMillis; - -// A copyable object representing a user specified test property which can be -// output as a key/value string pair. -// -// Don't inherit from TestProperty as its destructor is not virtual. -class TestProperty { - public: - // C'tor. TestProperty does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestProperty object. - TestProperty(const char* a_key, const char* a_value) : - key_(a_key), value_(a_value) { - } - - // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } - - // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } - - // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const char* new_value) { - value_ = new_value; - } - - private: - // The key supplied by the user. - internal::String key_; - // The value supplied by the user. - internal::String value_; -}; - -// The result of a single Test. This includes a list of -// TestPartResults, a list of TestProperties, a count of how many -// death tests there are in the Test, and how much time it took to run -// the Test. -// -// TestResult is not copyable. -class GTEST_API_ TestResult { - public: - // Creates an empty TestResult. - TestResult(); - - // D'tor. Do not inherit from TestResult. - ~TestResult(); - - // Gets the number of all test parts. This is the sum of the number - // of successful test parts and the number of failed test parts. - int total_part_count() const; - - // Returns the number of the test properties. - int test_property_count() const; - - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } - - // Returns true iff the test failed. - bool Failed() const; - - // Returns true iff the test fatally failed. - bool HasFatalFailure() const; - - // Returns true iff the test has a non-fatal failure. - bool HasNonfatalFailure() const; - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. - const TestPartResult& GetTestPartResult(int i) const; - - // Returns the i-th test property. i can range from 0 to - // test_property_count() - 1. If i is not in that range, aborts the - // program. - const TestProperty& GetTestProperty(int i) const; - - private: - friend class TestInfo; - friend class UnitTest; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::ExecDeathTest; - friend class internal::TestInfoImpl; - friend class internal::TestResultAccessor; - friend class internal::UnitTestImpl; - friend class internal::WindowsDeathTest; - - // Gets the vector of TestPartResults. - const std::vector& test_part_results() const { - return test_part_results_; - } - - // Gets the vector of TestProperties. - const std::vector& test_properties() const { - return test_properties_; - } - - // Sets the elapsed time. - void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - - // Adds a test property to the list. The property is validated and may add - // a non-fatal failure if invalid (e.g., if it conflicts with reserved - // key names). If a property is already recorded for the same key, the - // value will be updated, rather than storing multiple values for the same - // key. - void RecordProperty(const TestProperty& test_property); - - // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const TestProperty& test_property); - - // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); - - // Returns the death test count. - int death_test_count() const { return death_test_count_; } - - // Increments the death test count, returning the new count. - int increment_death_test_count() { return ++death_test_count_; } - - // Clears the test part results. - void ClearTestPartResults(); - - // Clears the object. - void Clear(); - - // Protects mutable state of the property vector and of owned - // properties, whose values may be updated. - internal::Mutex test_properites_mutex_; - - // The vector of TestPartResults - std::vector test_part_results_; - // The vector of TestProperties - std::vector test_properties_; - // Running count of death tests. - int death_test_count_; - // The elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - - // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); -}; // class TestResult - -// A TestInfo object stores the following information about a test: -// -// Test case name -// Test name -// Whether the test should be run -// A function pointer that creates the test object when invoked -// Test result -// -// The constructor of TestInfo registers itself with the UnitTest -// singleton such that the RUN_ALL_TESTS() macro knows which tests to -// run. -class GTEST_API_ TestInfo { - public: - // Destructs a TestInfo object. This function is not virtual, so - // don't inherit from TestInfo. - ~TestInfo(); - - // Returns the test case name. - const char* test_case_name() const; - - // Returns the test name. - const char* name() const; - - // Returns the test case comment. - const char* test_case_comment() const; - - // Returns the test comment. - const char* comment() const; - - // Returns true if this test should run, that is if the test is not disabled - // (or it is disabled but the also_run_disabled_tests flag has been specified) - // and its full name matches the user-specified filter. - // - // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as - // "Foo.Bar". Only the tests that match the filter will run. - // - // A filter is a colon-separated list of glob (not regex) patterns, - // optionally followed by a '-' and a colon-separated list of - // negative patterns (tests to exclude). A test is run if it - // matches one of the positive patterns and does not match any of - // the negative patterns. - // - // For example, *A*:Foo.* is a filter that matches any string that - // contains the character 'A' or starts with "Foo.". - bool should_run() const; - - // Returns the result of the test. - const TestResult* result() const; - - private: -#if GTEST_HAS_DEATH_TEST - friend class internal::DefaultDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - friend class Test; - friend class TestCase; - friend class internal::TestInfoImpl; - friend class internal::UnitTestImpl; - friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory); - - // Returns true if this test matches the user-specified filter. - bool matches_filter() const; - - // Increments the number of death tests encountered in this test so - // far. - int increment_death_test_count(); - - // Accessors for the implementation object. - internal::TestInfoImpl* impl() { return impl_; } - const internal::TestInfoImpl* impl() const { return impl_; } - - // Constructs a TestInfo object. The newly constructed instance assumes - // ownership of the factory object. - TestInfo(const char* test_case_name, const char* name, - const char* test_case_comment, const char* comment, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory); - - // An opaque implementation object. - internal::TestInfoImpl* impl_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); -}; - -// A test case, which consists of a vector of TestInfos. -// -// TestCase is not copyable. -class GTEST_API_ TestCase { - public: - // Creates a TestCase with the given name. - // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. - // - // Arguments: - // - // name: name of the test case - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* comment, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Destructor of TestCase. - virtual ~TestCase(); - - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } - - // Returns the test case comment. - const char* comment() const { return comment_.c_str(); } - - // Returns true if any test in this test case should run. - bool should_run() const { return should_run_; } - - // Gets the number of successful tests in this test case. - int successful_test_count() const; - - // Gets the number of failed tests in this test case. - int failed_test_count() const; - - // Gets the number of disabled tests in this test case. - int disabled_test_count() const; - - // Get the number of tests in this test case that should run. - int test_to_run_count() const; - - // Gets the number of all tests in this test case. - int total_test_count() const; - - // Returns true iff the test case passed. - bool Passed() const { return !Failed(); } - - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - const TestInfo* GetTestInfo(int i) const; - - private: - friend class Test; - friend class internal::UnitTestImpl; - - // Gets the (mutable) vector of TestInfos in this TestCase. - std::vector& test_info_list() { return test_info_list_; } - - // Gets the (immutable) vector of TestInfos in this TestCase. - const std::vector& test_info_list() const { - return test_info_list_; - } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - TestInfo* GetMutableTestInfo(int i); - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); - - // Clears the results of all tests in this test case. - void ClearResult(); - - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); - } - - // Runs every test in this TestCase. - void Run(); - - // Returns true iff test passed. - static bool TestPassed(const TestInfo * test_info); - - // Returns true iff test failed. - static bool TestFailed(const TestInfo * test_info); - - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo * test_info); - - // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo *test_info); - - // Shuffles the tests in this test case. - void ShuffleTests(internal::Random* random); - - // Restores the test order to before the first shuffle. - void UnshuffleTests(); - - // Name of the test case. - internal::String name_; - // Comment on the test case. - internal::String comment_; - // The vector of TestInfos in their original order. It owns the - // elements in the vector. - std::vector test_info_list_; - // Provides a level of indirection for the test list to allow easy - // shuffling and restoring the test order. The i-th element in this - // vector is the index of the i-th test in the shuffled test list. - std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. - bool should_run_; - // Elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); -}; - -// An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own -// environment(s). -// -// An Environment object does the set-up and tear-down in virtual -// methods SetUp() and TearDown() instead of the constructor and the -// destructor, as: -// -// 1. You cannot safely throw from a destructor. This is a problem -// as in some cases Google Test is used where exceptions are enabled, and -// we may want to implement ASSERT_* using exceptions where they are -// available. -// 2. You cannot use ASSERT_* directly in a constructor or -// destructor. -class Environment { - public: - // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} - - // Override this to define how to set up the environment. - virtual void SetUp() {} - - // Override this to define how to tear down the environment. - virtual void TearDown() {} - private: - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } -}; - -// The interface for tracing execution of tests. The methods are organized in -// the order the corresponding events are fired. -class TestEventListener { - public: - virtual ~TestEventListener() {} - - // Fired before any test activity starts. - virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; - - // Fired before each iteration of tests starts. There may be more than - // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration - // index, starting from 0. - virtual void OnTestIterationStart(const UnitTest& unit_test, - int iteration) = 0; - - // Fired before environment set-up for each iteration of tests starts. - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; - - // Fired after environment set-up for each iteration of tests ends. - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; - - // Fired before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; - - // Fired after a failed assertion or a SUCCESS(). - virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; - - // Fired after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; - - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; - - // Fired before environment tear-down for each iteration of tests starts. - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; - - // Fired after environment tear-down for each iteration of tests ends. - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; - - // Fired after each iteration of tests finishes. - virtual void OnTestIterationEnd(const UnitTest& unit_test, - int iteration) = 0; - - // Fired after all test activities have ended. - virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; -}; - -// The convenience class for users who need to override just one or two -// methods and are not concerned that a possible change to a signature of -// the methods they override will not be caught during the build. For -// comments about each method please see the definition of TestEventListener -// above. -class EmptyTestEventListener : public TestEventListener { - public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} -}; - -// TestEventListeners lets users add listeners to track events in Google Test. -class GTEST_API_ TestEventListeners { - public: - TestEventListeners(); - ~TestEventListeners(); - - // Appends an event listener to the end of the list. Google Test assumes - // the ownership of the listener (i.e. it will delete the listener when - // the test program finishes). - void Append(TestEventListener* listener); - - // Removes the given event listener from the list and returns it. It then - // becomes the caller's responsibility to delete the listener. Returns - // NULL if the listener is not found in the list. - TestEventListener* Release(TestEventListener* listener); - - // Returns the standard listener responsible for the default console - // output. Can be removed from the listeners list to shut down default - // console output. Note that removing this object from the listener list - // with Release transfers its ownership to the caller and makes this - // function return NULL the next time. - TestEventListener* default_result_printer() const { - return default_result_printer_; - } - - // Returns the standard listener responsible for the default XML output - // controlled by the --gtest_output=xml flag. Can be removed from the - // listeners list by users who want to shut down the default XML output - // controlled by this flag and substitute it with custom one. Note that - // removing this object from the listener list with Release transfers its - // ownership to the caller and makes this function return NULL the next - // time. - TestEventListener* default_xml_generator() const { - return default_xml_generator_; - } - - private: - friend class TestCase; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::NoExecDeathTest; - friend class internal::TestEventListenersAccessor; - friend class internal::TestInfoImpl; - friend class internal::UnitTestImpl; - - // Returns repeater that broadcasts the TestEventListener events to all - // subscribers. - TestEventListener* repeater(); - - // Sets the default_result_printer attribute to the provided listener. - // The listener is also added to the listener list and previous - // default_result_printer is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultResultPrinter(TestEventListener* listener); - - // Sets the default_xml_generator attribute to the provided listener. The - // listener is also added to the listener list and previous - // default_xml_generator is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultXmlGenerator(TestEventListener* listener); - - // Controls whether events will be forwarded by the repeater to the - // listeners in the list. - bool EventForwardingEnabled() const; - void SuppressEventForwarding(); - - // The actual list of listeners. - internal::TestEventRepeater* repeater_; - // Listener responsible for the standard result output. - TestEventListener* default_result_printer_; - // Listener responsible for the creation of the XML output file. - TestEventListener* default_xml_generator_; - - // We disallow copying TestEventListeners. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); -}; - -// A UnitTest consists of a vector of TestCases. -// -// This is a singleton class. The only instance of UnitTest is -// created when UnitTest::GetInstance() is first called. This -// instance is never deleted. -// -// UnitTest is not copyable. -// -// This class is thread-safe as long as the methods are called -// according to their specification. -class GTEST_API_ UnitTest { - public: - // Gets the singleton UnitTest object. The first time this method - // is called, a UnitTest object is constructed and returned. - // Consecutive calls will return the same object. - static UnitTest* GetInstance(); - - // Runs all tests in this UnitTest object and prints the result. - // Returns 0 if successful, or 1 otherwise. - // - // This method can only be called from the main thread. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - int Run() GTEST_MUST_USE_RESULT_; - - // Returns the working directory when the first TEST() or TEST_F() - // was executed. The UnitTest object owns the string. - const char* original_working_dir() const; - - // Returns the TestCase object for the test that's currently running, - // or NULL if no test is running. - const TestCase* current_test_case() const; - - // Returns the TestInfo object for the test that's currently running, - // or NULL if no test is running. - const TestInfo* current_test_info() const; - - // Returns the random seed used at the start of the current test run. - int random_seed() const; - -#if GTEST_HAS_PARAM_TEST - // Returns the ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); -#endif // GTEST_HAS_PARAM_TEST - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const; - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const; - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const; - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const; - - // Returns the list of event listeners that can be used to track events - // inside Google Test. - TestEventListeners& listeners(); - - private: - // Registers and returns a global test environment. When a test - // program is run, all global test environments will be set-up in - // the order they were registered. After all tests in the program - // have finished, all global test environments will be torn-down in - // the *reverse* order they were registered. - // - // The UnitTest object takes ownership of the given environment. - // - // This method can only be called from the main thread. - Environment* AddEnvironment(Environment* env); - - // Adds a TestPartResult to the current TestResult object. All - // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) - // eventually call this to report their results. The user code - // should use the assertion macros instead of calling this directly. - void AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const internal::String& message, - const internal::String& os_stack_trace); - - // Adds a TestProperty to the current TestResult object. If the result already - // contains a property with the same key, the value will be updated. - void RecordPropertyForCurrentTest(const char* key, const char* value); - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); - - // Accessors for the implementation object. - internal::UnitTestImpl* impl() { return impl_; } - const internal::UnitTestImpl* impl() const { return impl_; } - - // These classes and funcions are friends as they need to access private - // members of UnitTest. - friend class Test; - friend class internal::AssertHelper; - friend class internal::ScopedTrace; - friend Environment* AddGlobalTestEnvironment(Environment* env); - friend internal::UnitTestImpl* internal::GetUnitTestImpl(); - friend void internal::ReportFailureInUnknownLocation( - TestPartResult::Type result_type, - const internal::String& message); - - // Creates an empty UnitTest. - UnitTest(); - - // D'tor - virtual ~UnitTest(); - - // Pushes a trace defined by SCOPED_TRACE() on to the per-thread - // Google Test trace stack. - void PushGTestTrace(const internal::TraceInfo& trace); - - // Pops a trace from the per-thread Google Test trace stack. - void PopGTestTrace(); - - // Protects mutable state in *impl_. This is mutable as some const - // methods need to lock it too. - mutable internal::Mutex mutex_; - - // Opaque implementation object. This field is never changed once - // the object is constructed. We don't mark it as const here, as - // doing so will cause a warning in the constructor of UnitTest. - // Mutable state in *impl_ is protected by mutex_. - internal::UnitTestImpl* impl_; - - // We disallow copying UnitTest. - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); -}; - -// A convenient wrapper for adding an environment for the test -// program. -// -// You should call this before RUN_ALL_TESTS() is called, probably in -// main(). If you use gtest_main, you need to call this before main() -// starts for it to take effect. For example, you can define a global -// variable like this: -// -// testing::Environment* const foo_env = -// testing::AddGlobalTestEnvironment(new FooEnvironment); -// -// However, we strongly recommend you to write your own main() and -// call AddGlobalTestEnvironment() there, as relying on initialization -// of global variables makes the code harder to read and may cause -// problems when you register multiple environments from different -// translation units and the environments have dependencies among them -// (remember that the compiler doesn't guarantee the order in which -// global variables from different translation units are initialized). -inline Environment* AddGlobalTestEnvironment(Environment* env) { - return UnitTest::GetInstance()->AddEnvironment(env); -} - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -GTEST_API_ void InitGoogleTest(int* argc, char** argv); - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); - -namespace internal { - -// These overloaded versions handle ::std::string and ::std::wstring. -GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) { - return (Message() << '"' << str << '"').GetString(); -} - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) { - return (Message() << "L\"" << wstr << '"').GetString(); -} -#endif // GTEST_HAS_STD_WSTRING - -// These overloaded versions handle ::string and ::wstring. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ inline String FormatForFailureMessage(const ::string& str) { - return (Message() << '"' << str << '"').GetString(); -} -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) { - return (Message() << "L\"" << wstr << '"').GetString(); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char*, and print it as a C string when it is compared against an -// std::string object, for example. -// -// The default implementation ignores the type of the other operand. -// Some specialized versions are used to handle formatting wide or -// narrow C strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -String FormatForComparisonFailureMessage(const T1& value, - const T2& /* other_operand */) { - return FormatForFailureMessage(value); -} - -// The helper function for {ASSERT|EXPECT}_EQ. -template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -#ifdef _MSC_VER -#pragma warning(push) // Saves the current warning state. -#pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - - if (expected == actual) { - return AssertionSuccess(); - } - -#ifdef _MSC_VER -#pragma warning(pop) // Restores the warning state. -#endif - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// With this overloaded version, we allow anonymous enums to be used -// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums -// can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); - -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template -class EqHelper { - public: - // This templatized version is for the general case. - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // With this overloaded version, we allow anonymous enums to be used - // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous - // enums can be implicitly cast to BiggestInt. - // - // Even though its body looks the same as the above version, we - // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } -}; - -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // This version will be picked when the second argument to - // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer). - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& /* expected */, - T2* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); - } -}; - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste -// of similar code. -// -// For each templatized helper function, we also define an overloaded -// version for BiggestInt in order to reduce code bloat and allow -// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled -// with gcc 4. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -template \ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - const T1& val1, const T2& val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - Message msg;\ - msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - return AssertionFailure(msg);\ - }\ -}\ -GTEST_API_ AssertionResult CmpHelper##op_name(\ - const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) - -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// Implements the helper function for {ASSERT|EXPECT}_NE -GTEST_IMPL_CMP_HELPER_(NE, !=); -// Implements the helper function for {ASSERT|EXPECT}_LE -GTEST_IMPL_CMP_HELPER_(LE, <=); -// Implements the helper function for {ASSERT|EXPECT}_LT -GTEST_IMPL_CMP_HELPER_(LT, < ); -// Implements the helper function for {ASSERT|EXPECT}_GE -GTEST_IMPL_CMP_HELPER_(GE, >=); -// Implements the helper function for {ASSERT|EXPECT}_GT -GTEST_IMPL_CMP_HELPER_(GT, > ); - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRNE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - - -// Helper function for *_STREQ on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); - -// Helper function for *_STRNE on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2); - -} // namespace internal - -// IsSubstring() and IsNotSubstring() are intended to be used as the -// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by -// themselves. They check whether needle is a substring of haystack -// (NULL is considered a substring of itself only), and return an -// appropriate error message when they fail. -// -// The {needle,haystack}_expr arguments are the stringified -// expressions that generated the two real arguments. -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -// Helper template function for comparing floating-points. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); - - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - StrStream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; - - StrStream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; - - return EqFailure(expected_expression, - actual_expression, - StrStreamToString(&expected_ss), - StrStreamToString(&actual_ss), - false); -} - -// Helper function for implementing ASSERT_NEAR. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error); - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// A class that enables one to stream messages to assertion macros -class GTEST_API_ AssertHelper { - public: - // Constructor. - AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message); - ~AssertHelper(); - - // Message assignment is a semantic trick to enable assertion - // streaming; see the GTEST_MESSAGE_ macro below. - void operator=(const Message& message) const; - - private: - // We put our data in a struct so that the size of the AssertHelper class can - // be as small as possible. This is important because gcc is incapable of - // re-using stack space even for temporary variables, so every EXPECT_EQ - // reserves stack space for another AssertHelper. - struct AssertHelperData { - AssertHelperData(TestPartResult::Type t, - const char* srcfile, - int line_num, - const char* msg) - : type(t), file(srcfile), line(line_num), message(msg) { } - - TestPartResult::Type const type; - const char* const file; - int const line; - String const message; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); - }; - - AssertHelperData* const data_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); -}; - -} // namespace internal - -#if GTEST_HAS_PARAM_TEST -// The abstract base class that all value-parameterized tests inherit from. -// -// This class adds support for accessing the test parameter value via -// the GetParam() method. -// -// Use it with one of the parameter generator defining functions, like Range(), -// Values(), ValuesIn(), Bool(), and Combine(). -// -// class FooTest : public ::testing::TestWithParam { -// protected: -// FooTest() { -// // Can use GetParam() here. -// } -// virtual ~FooTest() { -// // Can use GetParam() here. -// } -// virtual void SetUp() { -// // Can use GetParam() here. -// } -// virtual void TearDown { -// // Can use GetParam() here. -// } -// }; -// TEST_P(FooTest, DoesBar) { -// // Can use GetParam() method here. -// Foo foo; -// ASSERT_TRUE(foo.DoesBar(GetParam())); -// } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); - -template -class TestWithParam : public Test { - public: - typedef T ParamType; - - // The current parameter value. Is also available in the test fixture's - // constructor. - const ParamType& GetParam() const { return *parameter_; } - - private: - // Sets parameter value. The caller is responsible for making sure the value - // remains alive and unchanged throughout the current test. - static void SetParam(const ParamType* parameter) { - parameter_ = parameter; - } - - // Static value used for accessing parameter during a test lifetime. - static const ParamType* parameter_; - - // TestClass must be a subclass of TestWithParam. - template friend class internal::ParameterizedTestFactory; -}; - -template -const T* TestWithParam::parameter_ = NULL; - -#endif // GTEST_HAS_PARAM_TEST - -// Macros for indicating success/failure in test code. - -// ADD_FAILURE unconditionally adds a failure to the current test. -// SUCCEED generates a success - it doesn't automatically make the -// current test successful, as a test is only successful when it has -// no failure. -// -// EXPECT_* verifies that a certain condition is satisfied. If not, -// it behaves like ADD_FAILURE. In particular: -// -// EXPECT_TRUE verifies that a Boolean condition is true. -// EXPECT_FALSE verifies that a Boolean condition is false. -// -// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except -// that they will also abort the current function on failure. People -// usually want the fail-fast behavior of FAIL and ASSERT_*, but those -// writing data-driven tests often find themselves using ADD_FAILURE -// and EXPECT_* more. -// -// Examples: -// -// EXPECT_TRUE(server.StatusIsOK()); -// ASSERT_FALSE(server.HasPendingRequest(port)) -// << "There are still pending requests " << "on port " << port; - -// Generates a nonfatal failure with a generic message. -#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") - -// Generates a fatal failure with a generic message. -#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") - -// Define this macro to 1 to omit the definition of FAIL(), which is a -// generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_FAIL -#define FAIL() GTEST_FAIL() -#endif - -// Generates a success with a generic message. -#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") - -// Define this macro to 1 to omit the definition of SUCCEED(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_SUCCEED -#define SUCCEED() GTEST_SUCCEED() -#endif - -// Macros for testing exceptions. -// -// * {ASSERT|EXPECT}_THROW(statement, expected_exception): -// Tests that the statement throws the expected exception. -// * {ASSERT|EXPECT}_NO_THROW(statement): -// Tests that the statement doesn't throw any exception. -// * {ASSERT|EXPECT}_ANY_THROW(statement): -// Tests that the statement throws an exception. - -#define EXPECT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) -#define EXPECT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define EXPECT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define ASSERT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) -#define ASSERT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) -#define ASSERT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) - -// Boolean assertions. Condition can be either a Boolean expression or an -// AssertionResult. For more information on how to use AssertionResult with -// these macros see comments on that class. -#define EXPECT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_NONFATAL_FAILURE_) -#define EXPECT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_NONFATAL_FAILURE_) -#define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_FATAL_FAILURE_) -#define ASSERT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_FATAL_FAILURE_) - -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -// Copyright 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command -// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! -// -// Implements a family of generic predicate assertion macros. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ - -// This header implements a family of generic predicate assertion -// macros: -// -// ASSERT_PRED_FORMAT1(pred_format, v1) -// ASSERT_PRED_FORMAT2(pred_format, v1, v2) -// ... -// -// where pred_format is a function or functor that takes n (in the -// case of ASSERT_PRED_FORMATn) values and their source expression -// text, and returns a testing::AssertionResult. See the definition -// of ASSERT_EQ in gtest.h for an example. -// -// If you don't care about formatting, you can use the more -// restrictive version: -// -// ASSERT_PRED1(pred, v1) -// ASSERT_PRED2(pred, v1, v2) -// ... -// -// where pred is an n-ary function or functor that returns bool, -// and the values v1, v2, ..., must support the << operator for -// streaming to std::ostream. -// -// We also define the EXPECT_* variations. -// -// For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. - -// GTEST_ASSERT_ is the basic statement to which all of the assertions -// in this file reduce. Don't use this in your code. - -#define GTEST_ASSERT_(expression, on_failure) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar = (expression)) \ - ; \ - else \ - on_failure(gtest_ar.failure_message()) - - -// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -template -AssertionResult AssertPred1Helper(const char* pred_text, - const char* e1, - Pred pred, - const T1& v1) { - if (pred(v1)) return AssertionSuccess(); - - Message msg; - msg << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; - return AssertionFailure(msg); -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. -// Don't use this in your code. -#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, v1),\ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -#define GTEST_PRED1_(pred, v1, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ - #v1, \ - pred, \ - v1), on_failure) - -// Unary predicate assertion macros. -#define EXPECT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -template -AssertionResult AssertPred2Helper(const char* pred_text, - const char* e1, - const char* e2, - Pred pred, - const T1& v1, - const T2& v2) { - if (pred(v1, v2)) return AssertionSuccess(); - - Message msg; - msg << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; - return AssertionFailure(msg); -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. -// Don't use this in your code. -#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -#define GTEST_PRED2_(pred, v1, v2, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ - #v1, \ - #v2, \ - pred, \ - v1, \ - v2), on_failure) - -// Binary predicate assertion macros. -#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -template -AssertionResult AssertPred3Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3) { - if (pred(v1, v2, v3)) return AssertionSuccess(); - - Message msg; - msg << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; - return AssertionFailure(msg); -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. -// Don't use this in your code. -#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - pred, \ - v1, \ - v2, \ - v3), on_failure) - -// Ternary predicate assertion macros. -#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -template -AssertionResult AssertPred4Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4) { - if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - - Message msg; - msg << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; - return AssertionFailure(msg); -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. -// Don't use this in your code. -#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4), on_failure) - -// 4-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -template -AssertionResult AssertPred5Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - const char* e5, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4, - const T5& v5) { - if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - - Message msg; - msg << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; - return AssertionFailure(msg); -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. -// Don't use this in your code. -#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - #v5, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4, \ - v5), on_failure) - -// 5-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) - - - -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Macros for testing equalities and inequalities. -// -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 -// -// When they are not, Google Test prints both the tested expressions and -// their actual values. The values must be compatible built-in types, -// or you will get a compiler error. By "compatible" we mean that the -// values can be compared by the respective operator. -// -// Note: -// -// 1. It is possible to make a user-defined type work with -// {ASSERT|EXPECT}_??(), but that requires overloading the -// comparison operators and is thus discouraged by the Google C++ -// Usage Guide. Therefore, you are advised to use the -// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are -// equal. -// -// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on -// pointers (in particular, C strings). Therefore, if you use it -// with two C strings, you are testing how their locations in memory -// are related, not how their content is related. To compare two C -// strings by content, use {ASSERT|EXPECT}_STR*(). -// -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you -// what the actual value is when it fails, and similarly for the -// other comparisons. -// -// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() -// evaluate their arguments, which is undefined. -// -// 5. These macros evaluate their arguments exactly once. -// -// Examples: -// -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); -// ASSERT_LT(i, array_size); -// ASSERT_GT(records.size(), 0) << "There is no record left."; - -#define EXPECT_EQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) -#define EXPECT_LE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define EXPECT_LT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define EXPECT_GE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define EXPECT_GT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -#define ASSERT_EQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define ASSERT_NE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) -#define ASSERT_LE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define ASSERT_LT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define ASSERT_GE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define ASSERT_GT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -// C String Comparisons. All tests treat NULL and any non-NULL string -// as different. Two NULLs are equal. -// -// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 -// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 -// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case -// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case -// -// For wide or narrow string objects, you can use the -// {ASSERT|EXPECT}_??() macros. -// -// Don't depend on the order in which the arguments are evaluated, -// which is undefined. -// -// These macros evaluate their arguments exactly once. - -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define EXPECT_STRNE(s1, s2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define EXPECT_STRCASENE(s1, s2)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define ASSERT_STRNE(s1, s2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define ASSERT_STRCASENE(s1, s2)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -// Macros for comparing floating-point numbers. -// -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): -// Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): -// Tests that two double values are almost equal. -// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): -// Tests that v1 and v2 are within the given distance to each other. -// -// Google Test uses ULP-based comparison to automatically pick a default -// error bound that is appropriate for the operands. See the -// FloatingPoint template class in gtest-internal.h if you are -// interested in the implementation details. - -#define EXPECT_FLOAT_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_DOUBLE_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_FLOAT_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_DOUBLE_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_NEAR(val1, val2, abs_error)\ - EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -#define ASSERT_NEAR(val1, val2, abs_error)\ - ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -// These predicate format functions work on floating-point values, and -// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. -// -// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2); -GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2); - - -#if GTEST_OS_WINDOWS - -// Macros that test for HRESULT failure and success, these are only useful -// on Windows, and rely on Windows SDK macros and APIs to compile. -// -// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) -// -// When expr unexpectedly fails or succeeds, Google Test prints the -// expected result and the actual result with both a human-readable -// string representation of the error, if available, as well as the -// hex result code. -#define EXPECT_HRESULT_SUCCEEDED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -#define ASSERT_HRESULT_SUCCEEDED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -#define EXPECT_HRESULT_FAILED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -#define ASSERT_HRESULT_FAILED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -#endif // GTEST_OS_WINDOWS - -// Macros that execute statement and check that it doesn't generate new fatal -// failures in the current thread. -// -// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); -// -// Examples: -// -// EXPECT_NO_FATAL_FAILURE(Process()); -// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; -// -#define ASSERT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) -#define EXPECT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) - -// Causes a trace (including the source file path, the current line -// number, and the given message) to be included in every test failure -// message generated by code in the current scope. The effect is -// undone when the control leaves the current scope. -// -// The message argument can be anything streamable to std::ostream. -// -// In the implementation, we include the current line number as part -// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s -// to appear in the same block - as long as they are on different -// lines. -#define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) - -namespace internal { - -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper {}; - -} // namespace internal - -// Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. -// -// Instead of making StaticAssertTypeEq a class template, we make it a -// function template that invokes a helper class template. This -// prevents a user from misusing StaticAssertTypeEq by -// defining objects of that type. -// -// CAVEAT: -// -// When used inside a method of a class template, -// StaticAssertTypeEq() is effective ONLY IF the method is -// instantiated. For example, given: -// -// template class Foo { -// public: -// void Bar() { testing::StaticAssertTypeEq(); } -// }; -// -// the code: -// -// void Test1() { Foo foo; } -// -// will NOT generate a compiler error, as Foo::Bar() is never -// actually instantiated. Instead, you need: -// -// void Test2() { Foo foo; foo.Bar(); } -// -// to cause a compiler error. -template -bool StaticAssertTypeEq() { - internal::StaticAssertTypeEqHelper(); - return true; -} - -// Defines a test. -// -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. -// -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. -// -// The user should put his test code between braces after using this -// macro. Example: -// -// TEST(FooTest, InitializesCorrectly) { -// Foo foo; -// EXPECT_TRUE(foo.StatusIsOK()); -// } - -// Note that we call GetTestTypeId() instead of GetTypeId< -// ::testing::Test>() here to get the type ID of testing::Test. This -// is to work around a suspected linker bug when using Google Test as -// a framework on Mac OS X. The bug causes GetTypeId< -// ::testing::Test>() to return different values depending on whether -// the call is from the Google Test framework itself or from user test -// code. GetTestTypeId() is guaranteed to always return the same -// value, as it always calls GetTypeId<>() from the Google Test -// framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) - -// Define this macro to 1 to omit the definition of TEST(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_TEST -#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) -#endif - -// Defines a test that uses a test fixture. -// -// The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. -// -// A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: -// -// class FooTest : public testing::Test { -// protected: -// virtual void SetUp() { b_.AddElement(3); } -// -// Foo a_; -// Foo b_; -// }; -// -// TEST_F(FooTest, InitializesCorrectly) { -// EXPECT_TRUE(a_.StatusIsOK()); -// } -// -// TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); -// } - -#define TEST_F(test_fixture, test_name)\ - GTEST_TEST_(test_fixture, test_name, test_fixture, \ - ::testing::internal::GetTypeId()) - -// Use this macro in main() to run all tests. It returns 0 if all -// tests are successful, or 1 otherwise. -// -// RUN_ALL_TESTS() should be invoked after the command line has been -// parsed by InitGoogleTest(). - -#define RUN_ALL_TESTS()\ - (::testing::UnitTest::GetInstance()->Run()) - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt index 84863a43ff..16e1b7b524 100644 --- a/Fwk/CMakeLists.txt +++ b/Fwk/CMakeLists.txt @@ -15,7 +15,7 @@ add_subdirectory(AppFwk/cafCommand) add_subdirectory(AppFwk/cafUserInterface) # Unit Tests -add_subdirectory(AppFwk/cafTests/cafProjectDataModel_UnitTests) +add_subdirectory(AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests) add_subdirectory(AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests) add_subdirectory(AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) From 3e9e5779ab38dcfce36653695be859a60ef7b3ca Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 12:19:29 +0100 Subject: [PATCH 140/290] [Fwk] Updated headers and added unit tests, fixed minor issues related to text stream operator overload --- Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h | 6 +- Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h | 3 +- Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h | 3 +- .../cafPdmCvf_UnitTests/CMakeLists.txt | 56 + .../cafPdmCoreColor3fTest.cpp | 59 + .../cafPdmCoreMat4dTest.cpp | 73 + .../cafPdmCoreVec3dTest.cpp | 61 + .../cafPdmCvf_UnitTests.cpp | 56 + .../cafPdmCvf_UnitTests/gtest/gtest-all.cpp | 8510 ++++++++ .../cafPdmCvf_UnitTests/gtest/gtest.h | 18007 ++++++++++++++++ Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfColor.h | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfMat4d.h | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfVec3d.h | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h | 3 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreMat4d.h | 10 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h | 10 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.cpp | 13 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.h | 7 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.cpp | 18 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.h | 7 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.cpp | 37 +- Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.h | 7 +- .../cafPdmCore_UnitTests/CMakeLists.txt | 3 +- .../TapCvfSpecialization.cpp | 4 - Fwk/CMakeLists.txt | 4 +- 27 files changed, 26888 insertions(+), 79 deletions(-) create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCvf_UnitTests.cpp create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest-all.cpp create mode 100644 Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest.h diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h index d77a0b4a1c..e942b7b7b7 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreColor3f.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,17 +34,16 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" #include "cvfColor3.h" #include "cafInternalPdmValueFieldSpecializations.h" +#include "cafPdmXmlColor3f.h" #include - namespace caf { @@ -75,7 +74,6 @@ class PdmValueFieldSpecialization { return variantValue == variantValue2; } - }; diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h index 6eb4289b94..f9cf7a1e5b 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreMat4d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h index bd044460de..b0991a0837 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCoreVec3d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt new file mode 100644 index 0000000000..8f95b1daf8 --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required (VERSION 2.8) + +find_package ( Qt4 COMPONENTS QtCore ) +include (${QT_USE_FILE}) + +project ( cafPdmCvf_UnitTests ) + +include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR} + ${cafPdmCore_SOURCE_DIR} + ${cafPdmXml_SOURCE_DIR} + ${cafPdmCvf_SOURCE_DIR} + + ${LibCore_SOURCE_DIR} +) + + +set( PROJECT_FILES + + cafPdmCvf_UnitTests.cpp + gtest/gtest-all.cpp + + cafPdmCoreVec3dTest.cpp + cafPdmCoreColor3fTest.cpp + cafPdmCoreMat4dTest.cpp +) + +# add the executable +add_executable (${PROJECT_NAME} + ${PROJECT_FILES} +) + +source_group("" FILES ${PROJECT_FILES}) + +message(STATUS ${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) + +target_link_libraries ( ${PROJECT_NAME} + cafPdmCore + cafPdmXml + LibCore + cafPdmCvf + ${QT_LIBRARIES} +) + +# Copy Qt Dlls +if (MSVC) + set (QTLIBLIST QtCore QtGui) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) +endif(MSVC) diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp new file mode 100644 index 0000000000..c84ab6067a --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreColor3fTest.cpp @@ -0,0 +1,59 @@ +#include "cafPdmCoreColor3f.h" + +#include "gtest/gtest.h" + + +TEST(SerializeTest, PdmCoreColor3f) +{ + float r = 0.4f; + float g = 0.2f; + float b = 0.18f; + cvf::Color3f myColor(r, g, b); + + QString textString; + { + QTextStream out(&textString); + out << myColor; + + EXPECT_EQ(0, textString.compare("0.4 0.2 0.18")); + } + + { + cvf::Color3f decoded; + QTextStream out(&textString); + out >> decoded; + + EXPECT_TRUE(decoded == myColor); + } +} + +TEST(VariantTest, PdmCoreColor3f) +{ + float r = 0.4f; + float g = 0.2f; + float b = 0.18f; + cvf::Color3f myColor(r, g, b); + + QVariant myVariant = caf::PdmValueFieldSpecialization::convert(myColor); + + cvf::Color3f decoded; + caf::PdmValueFieldSpecialization::setFromVariant(myVariant, decoded); + + EXPECT_FLOAT_EQ(myColor.r(), decoded.r()); + EXPECT_FLOAT_EQ(myColor.g(), decoded.g()); + EXPECT_NEAR(myColor.b(), decoded.b(), 0.01); // For some reason, 0.18 is not close enough to use EXPECT_FLOAT_EQ +} + +TEST(SerializeSeveralTest, PdmCoreColor3f) +{ + float r = 0.4f; + float g = 0.2f; + float b = 0.18f; + cvf::Color3f myColor(r, g, b); + + QString textString; + { + QTextStream out(&textString); + out << myColor << " " << myColor; + } +} diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp new file mode 100644 index 0000000000..f66c5efda2 --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreMat4dTest.cpp @@ -0,0 +1,73 @@ +#include "cafPdmCoreMat4d.h" + +#include "gtest/gtest.h" + +#include "cvfMatrix4.h" + +cvf::Mat4d createMatrix() +{ + double m00 = 0.00; + double m01 = 0.01; + double m02 = 0.02; + double m03 = 0.03; + double m10 = 0.10; + double m11 = 0.11; + double m12 = 0.12; + double m13 = 0.13; + double m20 = 0.20; + double m21 = 0.21; + double m22 = 0.22; + double m23 = 0.23; + double m30 = 0.30; + double m31 = 0.31; + double m32 = 0.32; + double m33 = 0.33; + + cvf::Mat4d myVector(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33); + + return myVector; +} + +TEST(SerializeTest, PdmCoreMat4d) +{ + cvf::Mat4d myMatrix = createMatrix(); + + QString textString; + { + QTextStream out(&textString); + out << myMatrix; + + EXPECT_EQ(0, textString.compare("0 0.01 0.02 0.03 0.1 0.11 0.12 0.13 0.2 0.21 0.22 0.23 0.3 0.31 0.32 0.33")); + } + + { + cvf::Mat4d decoded; + QTextStream out(&textString); + out >> decoded; + + EXPECT_TRUE(decoded.equals(myMatrix)); + } +} + +TEST(VariantTest, PdmCoreMat4d) +{ + cvf::Mat4d myMatrix = createMatrix(); + + QVariant myVariant = caf::PdmValueFieldSpecialization::convert(myMatrix); + + cvf::Mat4d decoded; + caf::PdmValueFieldSpecialization::setFromVariant(myVariant, decoded); + + EXPECT_TRUE(decoded.equals(myMatrix)); +} + +TEST(SerializeSeveralTest, PdmCoreMat4d) +{ + cvf::Mat4d myMatrix = createMatrix(); + + QString textString; + { + QTextStream out(&textString); + out << myMatrix << " " << myMatrix; + } +} diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp new file mode 100644 index 0000000000..8e293646f5 --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCoreVec3dTest.cpp @@ -0,0 +1,61 @@ +#include "cafPdmCoreVec3d.h" + +#include "gtest/gtest.h" + +#include "cvfVector3.h" + +TEST(SerializeTest, PdmCoreVec3d) +{ + double a = 2.4; + double b = 12.4; + double c = 232.778; + + cvf::Vec3d myVector(a, b, c); + + QString textString; + { + QTextStream out(&textString); + out << myVector; + + EXPECT_EQ(0, textString.compare("2.4 12.4 232.778")); + } + + { + cvf::Vec3d decoded; + QTextStream out(&textString); + out >> decoded; + + EXPECT_TRUE(decoded.equals(myVector)); + } +} + +TEST(VariantTest, PdmCoreVec3d) +{ + double a = 2.4; + double b = 12.4; + double c = 232.778; + + cvf::Vec3d myVector(a, b, c); + + QVariant myVariant = caf::PdmValueFieldSpecialization::convert(myVector); + + cvf::Vec3d decoded; + caf::PdmValueFieldSpecialization::setFromVariant(myVariant, decoded); + + EXPECT_TRUE(decoded.equals(myVector)); +} + +TEST(SerializeSeveralTest, PdmCoreVec3d) +{ + double a = 2.4; + double b = 12.4; + double c = 232.778; + + cvf::Vec3d myVector(a, b, c); + + QString textString; + { + QTextStream out(&textString); + out << myVector << " " << myVector; + } +} diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCvf_UnitTests.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCvf_UnitTests.cpp new file mode 100644 index 0000000000..a1a46c1e56 --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/cafPdmCvf_UnitTests.cpp @@ -0,0 +1,56 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + + +#include "gtest/gtest.h" +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int main(int argc, char **argv) +{ + + testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + + char text[5]; + std::cin.getline(text, 5); + + return result; +} diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest-all.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest-all.cpp new file mode 100644 index 0000000000..644479a63c --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest-all.cpp @@ -0,0 +1,8510 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include + +// The following lines pull in the real gtest *.cc files. +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const char* substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const String substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY_ 1 + +#include +#include +#include +// Declares vsnprintf(). This header is not available on Windows. +#include +#include +#include +#include +#include +#include + +#elif GTEST_OS_SYMBIAN +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT + +#elif GTEST_OS_ZOS +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +#include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +#include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +#define GTEST_HAS_GETTIMEOFDAY_ 1 +#include // NOLINT +#endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +#define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +#include // NOLINT +#include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +#include +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +#error "gtest-internal-inl.h is part of Google Test's internal implementation." +#error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +#include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + + +#if GTEST_OS_WINDOWS +#include // For DWORD. +#endif // GTEST_OS_WINDOWS + + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + bool pretty_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + return static_cast(std::count_if(c.begin(), c.end(), predicate)); +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +class TestInfoImpl { + public: + TestInfoImpl(TestInfo* parent, const char* test_case_name, + const char* name, const char* test_case_comment, + const char* comment, TypeId fixture_class_id, + internal::TestFactoryBase* factory); + ~TestInfoImpl(); + + // Returns true if this test should run. + bool should_run() const { return should_run_; } + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Returns true if this test is disabled. Disabled tests are not run. + bool is_disabled() const { return is_disabled_; } + + // Sets the is_disabled member. + void set_is_disabled(bool is) { is_disabled_ = is; } + + // Returns true if this test matches the filter specified by the user. + bool matches_filter() const { return matches_filter_; } + + // Sets the matches_filter member. + void set_matches_filter(bool matches) { matches_filter_ = matches; } + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the test case comment. + const char* test_case_comment() const { return test_case_comment_.c_str(); } + + // Returns the test comment. + const char* comment() const { return comment_.c_str(); } + + // Returns the ID of the test fixture class. + TypeId fixture_class_id() const { return fixture_class_id_; } + + // Returns the test result. + TestResult* result() { return &result_; } + const TestResult* result() const { return &result_; } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + // Clears the test result. + void ClearResult() { result_.Clear(); } + + // Clears the test result in the given TestInfo object. + static void ClearTestResult(TestInfo * test_info) { + test_info->impl()->ClearResult(); + } + + private: + // These fields are immutable properties of the test. + TestInfo* const parent_; // The owner of this object + const String test_case_name_; // Test case name + const String name_; // Test name + const String test_case_comment_; // Test case comment + const String comment_; // Test comment + const TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl); +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo * test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->test_case_comment(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has + // guards protecting from registering the tests more then once. + // If value-parameterized tests are disabled, RegisterParameterizedTests + // is present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns 0 if all tests are successful, or 1 otherwise. If any + // exception is thrown during a test on Windows, this test is + // considered to be failed, but the rest of the tests will still be + // run. (We disable exceptions on Linux and Mac OS X, so the issue + // doesn't apply there.) + int RunAllTests(); + + // Clears the results of all tests, including the ad hoc test. + void ClearResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + private: + friend class ::testing::UnitTest; + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsDigit(char ch); +GTEST_API_ bool IsPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsWhiteSpace(char ch); +GTEST_API_ bool IsWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastErrnoDescription(); + +#if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +#endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !isdigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. +#if GTEST_OS_WINDOWS && !defined(__GNUC__) + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); +#else + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); +#endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +#define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", false), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_OS_WINDOWS +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle an exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception. + return (GTEST_FLAG(catch_exceptions) && + exception_code != EXCEPTION_BREAKPOINT) ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_OS_WINDOWS + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const char* substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure(msg); + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + msg << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + if (strstr(r.message(), substr) == NULL) { + msg << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + return AssertionFailure(msg); + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const char* substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str()); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; +#ifdef _MSC_VER + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +#pragma warning(pop) // Restores the warning state. +#else + _ftime64(&now); +#endif // _MSC_VER + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +#error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +namespace internal { + +// Formats a value to be used in a failure message. + +// For a char value, we print it as a C++ char literal and as an +// unsigned integer (both in decimal and in hexadecimal). +String FormatForFailureMessage(char ch) { + const unsigned int ch_as_uint = ch; + // A String object cannot contain '\0', so we print "\\0" when ch is + // '\0'. + return String::Format("'%s' (%u, 0x%X)", + ch ? String::Format("%c", ch).c_str() : "\\0", + ch_as_uint, ch_as_uint); +} + +// For a wchar_t value, we print it as a C++ wchar_t literal and as an +// unsigned integer (both in decimal and in hexidecimal). +String FormatForFailureMessage(wchar_t wchar) { + // The C++ standard doesn't specify the exact size of the wchar_t + // type. It just says that it shall have the same size as another + // integral type, called its underlying type. + // + // Therefore, in order to print a wchar_t value in the numeric form, + // we first convert it to the largest integral type (UInt64) and + // then print the converted value. + // + // We use streaming to print the value as "%llu" doesn't work + // correctly with MSVC 7.1. + const UInt64 wchar_as_uint64 = wchar; + Message msg; + // A String object cannot contain '\0', so we print "\\0" when wchar is + // L'\0'. + char buffer[32]; // CodePointToUtf8 requires a buffer that big. + msg << "L'" + << (wchar ? CodePointToUtf8(static_cast(wchar), buffer) : "\\0") + << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16) + << wchar_as_uint64 << ")"; + return msg.GetString(); +} + +} // namespace internal + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new internal::String(*other.message_) : + static_cast(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure(msg); +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + Message msg; + msg << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; + return AssertionFailure(msg); +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + StrStream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + StrStream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + Message msg; + msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StrStreamToString(&val1_ss) << " vs " + << StrStreamToString(&val2_ss); + + return AssertionFailure(msg); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + Message msg;\ + msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return AssertionFailure(msg);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + return AssertionFailure(msg); + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure( + Message() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""); +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; +#else + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && isspace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } +#endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + Message msg; + msg << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; + + return ::testing::AssertionFailure(msg); +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + StrStream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StrStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + Message msg; + msg << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); + return AssertionFailure(msg); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX + return wcscasecmp(lhs, rhs) == 0; +#else + // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes + // may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4996) // Temporarily disables warning 4996. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a StrStream to a String, converting NUL +// bytes to "\\0" along the way. +String StrStreamToString(StrStream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper StrStream to do this transformation + // because String doesn't support push_back(). + StrStream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +#if GTEST_OS_WINDOWS +// We are on Windows. + +// Adds an "exception thrown" fatal failure to the current test. +static void AddExceptionThrownFailure(DWORD exception_code, + const char* location) { + Message message; + message << "Exception thrown with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " in " << location << "."; + + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + message.GetString()); +} + +#endif // GTEST_OS_WINDOWS + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const internal::TestInfoImpl* const first_test_info = + test_case->test_info_list()[0]->impl(); + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const internal::TestInfoImpl* const this_test_info = + impl->current_test_info()->impl(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id(); + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + SetUp(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "SetUp()"); + } + + // We will run the test only if SetUp() had no fatal failure. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TestBody(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "the test body"); + } + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + __try { + TearDown(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), "TearDown()"); + } + +#else // We are on a compiler or platform that doesn't support SEH. + impl->os_stack_trace_getter()->UponLeavingGTest(); + SetUp(); + + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + TestBody(); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + TearDown(); +#endif // GTEST_HAS_SEH +} + + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object via impl_. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) { + impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name, + a_test_case_comment, a_comment, + fixture_class_id, factory); +} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { + delete impl_; +} + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// test_case_comment: a comment on the test case that will be included in +// the test output +// comment: a comment on the test that will be included in the +// test output +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, test_case_comment, comment, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +// Returns the test case name. +const char* TestInfo::test_case_name() const { + return impl_->test_case_name(); +} + +// Returns the test name. +const char* TestInfo::name() const { + return impl_->name(); +} + +// Returns the test case comment. +const char* TestInfo::test_case_comment() const { + return impl_->test_case_comment(); +} + +// Returns the test comment. +const char* TestInfo::comment() const { + return impl_->comment(); +} + +// Returns true if this test should run. +bool TestInfo::should_run() const { return impl_->should_run(); } + +// Returns true if this test matches the user-specified filter. +bool TestInfo::matches_filter() const { return impl_->matches_filter(); } + +// Returns the result of the test. +const TestResult* TestInfo::result() const { return impl_->result(); } + +// Increments the number of death tests encountered in this test so +// far. +int TestInfo::increment_death_test_count() { + return impl_->result()->increment_death_test_count(); +} + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfoImpl::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(parent_); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*parent_); + + const TimeInMillis start = GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + Test* test = NULL; + + __try { + // Creates the test object. + test = factory_->CreateTest(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + AddExceptionThrownFailure(GetExceptionCode(), + "the test fixture's constructor"); + return; + } +#else // We are on a compiler or platform that doesn't support SEH. + + // TODO(wan): If test->Run() throws, test won't be deleted. This is + // not a problem now as we don't use exceptions. If we were to + // enable exceptions, we should revise the following to be + // exception-safe. + + // Creates the test object. + Test* test = factory_->CreateTest(); +#endif // GTEST_HAS_SEH + + // Runs the test only if the constructor of the test fixture didn't + // generate a fatal failure. + if (!Test::HasFatalFailure()) { + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + delete test; + test = NULL; + + result_.set_elapsed_time(GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*parent_); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +} // namespace internal + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + comment_(a_comment), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + set_up_tc_(); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->impl()->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + tear_down_tc_(); + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult); +} + +// Returns true iff test passed. +bool TestCase::TestPassed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Passed(); +} + +// Returns true iff test failed. +bool TestCase::TestFailed(const TestInfo * test_info) { + const internal::TestInfoImpl* const impl = test_info->impl(); + return impl->should_run() && impl->result()->Failed(); +} + +// Returns true iff test is disabled. +bool TestCase::TestDisabled(const TestInfo * test_info) { + return test_info->impl()->is_disabled(); +} + +// Returns true if the given test should run. +bool TestCase::ShouldRunTest(const TestInfo *test_info) { + return test_info->impl()->should_run(); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + } + + return "Unknown result type"; +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %s of %s.\n", + internal::posix::GetEnv(kTestShardIndex), + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_case.comment()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.comment()[0] == '\0') { + printf("\n"); + } else { + printf(", where %s\n", test_info.comment()); + } + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + if (test_case.comment()[0] != '\0' || + test_info.comment()[0] != '\0') { + printf(", where %s", test_case.comment()); + if (test_case.comment()[0] != '\0' && + test_info.comment()[0] != '\0') { + printf(" and "); + } + } + printf("%s\n", test_info.comment()); + } + } +} + + void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static String RemoveInvalidXmlCharacters(const char* str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) { + char* const output = new char[strlen(str) + 1]; + char* appender = output; + for (char ch = *str; ch != '\0'; ch = *++str) + if (IsValidXmlCharacter(ch)) + *appender++ = ch; + *appender = '\0'; + + String ret_value(output); + delete[] output; + return ret_value; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const String message = RemoveInvalidXmlCharacters(String::Format( + "%s:%d\n%s", + part.file_name(), part.line_number(), + part.message()).c_str()); + OutputXmlCDataSection(stream, message.c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + StrStream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StrStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +#if GTEST_HAS_EXCEPTIONS +// A failed Google Test assertion will throw an exception of this type +// when exceptions are enabled. We derive it from std::runtime_error, +// which is for errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { +#if GTEST_HAS_SEH + // Catch SEH-style exceptions. + + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected.. + if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { +#if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +#endif // !GTEST_OS_WINDOWS_MOBILE + +#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +#endif + +#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +#endif + } + + __try { + return impl_->RunAllTests(); + } __except(internal::UnitTestOptions::GTestShouldProcessSEH( + GetExceptionCode())) { + printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode()); + fflush(stdout); + return 1; + } + +#else // We are on a compiler or platform that doesn't support SEH. + + return impl_->RunAllTests(); +#endif // GTEST_HAS_SEH +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. +#if GTEST_HAS_DEATH_TEST + elapsed_time_(0), + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory) { +#else + elapsed_time_(0) { +#endif // GTEST_HAS_DEATH_TEST + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns 0 if all tests are successful, or 1 otherwise. If any +// exception is thrown during a test on Windows, this test is +// considered to be failed, but the rest of the tests will still be +// run. (We disable exceptions on Linux and Mac OS X, so the issue +// doesn't apply there.) +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +int UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return 1; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return 0; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return 0; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + ClearResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + // Returns 0 if all tests passed, or 1 other wise. + return failed ? 1 : 0; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->impl()->set_is_disabled(is_disabled); + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->impl()->set_matches_filter(matches_filter); + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->impl()->set_should_run(is_selected); + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter()) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + current_test_info_->impl()->result() : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// TestInfoImpl constructor. The new instance assumes ownership of the test +// factory object. +TestInfoImpl::TestInfoImpl(TestInfo* parent, + const char* a_test_case_name, + const char* a_name, + const char* a_test_case_comment, + const char* a_comment, + TypeId a_fixture_class_id, + internal::TestFactoryBase* factory) : + parent_(parent), + test_case_name_(String(a_test_case_name)), + name_(String(a_name)), + test_case_comment_(String(a_test_case_comment)), + comment_(String(a_comment)), + fixture_class_id_(a_fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory) { +} + +// TestInfoImpl destructor. +TestInfoImpl::~TestInfoImpl() { + delete factory_; +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable +// code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +#if GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" +" Suppress pop-ups caused by exceptions.\n" +#endif // GTEST_OS_WINDOWS +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + + +#if GTEST_HAS_DEATH_TEST + +#if GTEST_OS_MAC +#include +#endif // GTEST_OS_MAC + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS +#include +#else +#include +#include +#endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +#if GTEST_OS_WINDOWS + return exit_status == exit_code_; +#else + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; +#endif // GTEST_OS_WINDOWS +} + +#if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +#endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; +#if GTEST_OS_WINDOWS + m << "Exited with exit status " << exit_code; +#else + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +#ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +#endif +#endif // GTEST_OS_WINDOWS + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +#if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +#endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test +// can conclude. DIED means that the process died while executing the +// test code; LIVED means that process lived beyond the end of the test +// code; and RETURNED means that the test statement attempted a "return," +// which is not allowed. IN_PROGRESS means the test has not yet +// concluded. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +#define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned; + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd())); + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, or RETURNED. The death test fails +// in the latter two cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg: " << error_message; + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg: " << error_message; + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg: " << error_message; + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n"; + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +#if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* statement, + const RE* regex, + const char* file, + int line) + : DeathTestImpl(statement, regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status; + GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status) + != FALSE); + child_handle_.Reset(); + set_status(static_cast(status)); + return this->status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +#else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +#if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +#else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +#endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +#if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +#else + const bool use_fork = true; +#endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +#endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +#if GTEST_OS_WINDOWS + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } +#else + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } +#endif // GTEST_OS_WINDOWS + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +#if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +#endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +#if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +#else + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } +#endif // GTEST_OS_WINDOWS + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + + +#include + +#if GTEST_OS_WINDOWS_MOBILE +#include +#elif GTEST_OS_WINDOWS +#include +#include +#elif GTEST_OS_SYMBIAN +// Symbian OpenC has PATH_MAX in sys/syslimits.h +#include +#else +#include +#include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +#define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +#define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +#define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +#else +const char kCurrentDirectoryString[] = ".\\"; +#endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +#include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +#include +#include +#else +#include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +#include +#include +#include +#endif // GTEST_OS_MAC + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsDigit(ch); + case 'D': return !IsDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsWhiteSpace(ch); + case 'S': return !IsWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsWordChar(ch); + case 'W': return !IsWordChar(ch); + } + return IsPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION_ + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { +#if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +#else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +#endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION_ + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << static_cast(toupper(full_flag.c_str()[i])); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (isspace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest.h b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest.h new file mode 100644 index 0000000000..c0a1902e25 --- /dev/null +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/gtest/gtest.h @@ -0,0 +1,18007 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_LINUX - Linux +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax. Not available on +// Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // For ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +#include +#endif // !_WIN32_WCE + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +#define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +#define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +#define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +#define GTEST_OS_WINDOWS 1 +#ifdef _WIN32_WCE +#define GTEST_OS_WINDOWS_MOBILE 1 +#elif defined(__MINGW__) || defined(__MINGW32__) +#define GTEST_OS_WINDOWS_MINGW 1 +#else +#define GTEST_OS_WINDOWS_DESKTOP 1 +#endif // _WIN32_WCE +#elif defined __APPLE__ +#define GTEST_OS_MAC 1 +#elif defined __linux__ +#define GTEST_OS_LINUX 1 +#elif defined __MVS__ +#define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +#define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +#define GTEST_OS_AIX 1 +#endif // __CYGWIN__ + +#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \ + GTEST_OS_SOLARIS || GTEST_OS_AIX + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +#if !GTEST_OS_WINDOWS_MOBILE +#include // NOLINT +#include // NOLINT +#endif + +// is not available on Windows. Use our own simple regex +// implementation instead. +#define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +#define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || + // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +#ifndef _HAS_EXCEPTIONS +#define _HAS_EXCEPTIONS 1 +#endif // _HAS_EXCEPTIONS +#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +#elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +#define GTEST_HAS_EXCEPTIONS 1 +#elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +#define GTEST_HAS_EXCEPTIONS 1 +#else +// For other compilers, we assume exceptions are disabled to be +// conservative. +#define GTEST_HAS_EXCEPTIONS 0 +#endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +#define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +#error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +#define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.5 and below doesn't support ::std::wstring. +// Cygwin 1.7 might add wstring support; this should be updated when clear. +// Solaris' libc++ doesn't support it either. +#define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +#define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +#ifdef _MSC_VER + +#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +#ifdef __GXX_RTTI +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif // __GXX_RTTI + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +#ifdef __RTTI_ALL__ +#define GTEST_HAS_RTTI 1 +#else +#define GTEST_HAS_RTTI 0 +#endif + +#else + +// For all other compilers, we assume RTTI is enabled. +#define GTEST_HAS_RTTI 1 + +#endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +#include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) +#endif // GTEST_HAS_PTHREAD + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +// The user didn't tell us not to do it, so we assume it's OK. +#define GTEST_HAS_TR1_TUPLE 1 +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, GCC 4.0.0+ and MSVC +// 2010 are the only mainstream compilers that come with a TR1 tuple +// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by +// defining __GNUC__ and friends, but cannot compile GCC's tuple +// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB +// Feature Pack download, which we cannot assume the user has. +#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ + || _MSC_VER >= 1600 +#define GTEST_USE_OWN_TR1_TUPLE 0 +#else +#define GTEST_USE_OWN_TR1_TUPLE 1 +#endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +#if GTEST_USE_OWN_TR1_TUPLE +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { typedef T0 type; }; + +template +struct TupleElement { typedef T1 type; }; + +template +struct TupleElement { typedef T2 type; }; + +template +struct TupleElement { typedef T3 type; }; + +template +struct TupleElement { typedef T4 type; }; + +template +struct TupleElement { typedef T5 type; }; + +template +struct TupleElement { typedef T6 type; }; + +template +struct TupleElement { typedef T7 type; }; + +template +struct TupleElement { typedef T8 type; }; + +template +struct TupleElement { typedef T9 type; }; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { static const int value = 0; }; + +template +struct tuple_size { static const int value = 1; }; + +template +struct tuple_size { static const int value = 2; }; + +template +struct tuple_size { static const int value = 3; }; + +template +struct tuple_size { static const int value = 4; }; + +template +struct tuple_size { static const int value = 5; }; + +template +struct tuple_size { static const int value = 6; }; + +template +struct tuple_size { static const int value = 7; }; + +template +struct tuple_size { static const int value = 8; }; + +template +struct tuple_size { static const int value = 9; }; + +template +struct tuple_size { static const int value = 10; }; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +#ifdef BOOST_HAS_TR1_TUPLE +#undef BOOST_HAS_TR1_TUPLE +#endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +#include + +#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +#define _TR1_FUNCTIONAL 1 +#include +#undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +#else +#include // NOLINT +#endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +#else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +#include // NOLINT +#endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +#if GTEST_OS_LINUX && !defined(__ia64__) +#define GTEST_HAS_CLONE 1 +#else +#define GTEST_HAS_CLONE 0 +#endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#define GTEST_HAS_STREAM_REDIRECTION_ 1 +#endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX) +#define GTEST_HAS_DEATH_TEST 1 +#include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, and IBM Visual Age support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) +#define GTEST_HAS_TYPED_TEST 1 +#define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +#define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +#define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +#define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +#define GTEST_HAS_SEH 1 +#else +// Assume no SEH. +#define GTEST_HAS_SEH 0 +#endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +#if GTEST_LINKED_AS_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllimport) +#elif GTEST_CREATE_SHARED_LIBRARY +#define GTEST_API_ __declspec(dllexport) +#endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +#define GTEST_API_ +#endif + +namespace testing { + +class Message; + +namespace internal { + +class String; + +typedef ::std::stringstream StrStream; + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of a string, as Google Test may be used + // where string is not available. We also do not use Google Test's own + // String type here, in order to simplify dependencies between the + // files. + const char* pattern_; + bool is_valid_; +#if GTEST_USES_POSIX_RE + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). +#else // GTEST_USES_SIMPLE_RE + const char* full_pattern_; // For FullMatch(); +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION_ + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ String GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ String GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION_ + + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +// GTEST_HAS_DEATH_TEST implies we have ::std::string. +const ::std::vector& GetArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +#include + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + } + + // Releases this mutex. + void Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_ = 0; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. +}; + +// Forward-declares a static mutex. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + owner_ = 0; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +#define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void AssertHeld() const {} +}; + +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +#define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +#define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +#define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +#define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +#if GTEST_OS_WINDOWS +#define GTEST_PATH_SEP_ "\\" +#define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +#define GTEST_PATH_SEP_ "/" +#define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +#ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +#else // !__BORLANDC__ +#if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +#else +inline int IsATTY(int fd) { return _isatty(fd); } +#endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +#endif // __BORLANDC__ + +#if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +#else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +#endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +#pragma warning(push) +#pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +#if GTEST_OS_LINUX +#include +#include +#include +#include +#endif // GTEST_OS_LINUX + +#include +#include +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +#include +#endif + +#include + +#include + +namespace testing { +namespace internal { + +// String - a UTF-8 string class. +// +// For historic reasons, we don't use std::string. +// +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. +// +// NULL and the empty string are considered different. NULL is less +// than anything (including the empty string) except itself. +// +// This class only provides minimum functionality necessary for +// implementing Google Test. We do not intend to implement a full-fledged +// string class here. +// +// Since the purpose of this class is to provide a substitute for +// std::string on platforms where it cannot be used, we define a copy +// constructor and assignment operators such that we don't need +// conditional compilation in a lot of places. +// +// In order to make the representation efficient, the d'tor of String +// is not virtual. Therefore DO NOT INHERIT FROM String. +class GTEST_API_ String { + public: + // Static utility methods + + // Returns the input enclosed in double quotes if it's not NULL; + // otherwise returns "(null)". For example, "\"Hello\"" is returned + // for input "Hello". + // + // This is useful for printing a C string in the syntax of a literal. + // + // Known issue: escape sequences are not handled yet. + static String ShowCStringQuoted(const char* c_str); + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static String ShowWideCString(const wchar_t* wide_c_str); + + // Similar to ShowWideCString(), except that this function encloses + // the converted string in double quotes. + static String ShowWideCStringQuoted(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Formats a list of arguments to a String, using the same format + // spec string as for printf. + // + // We do not use the StringPrintf class as it is not universally + // available. + // + // The result is limited to 4096 characters (including the tailing + // 0). If 4096 characters are not enough to format the input, + // "" is returned. + static String Format(const char* format, ...); + + // C'tors + + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} + + // Constructs a String by cloning a 0-terminated C string. + String(const char* a_c_str) { // NOLINT + if (a_c_str == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(a_c_str, strlen(a_c_str)); + } + } + + // Constructs a String by copying a given number of chars from a + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t a_length) { + ConstructNonNull(buffer, a_length); + } + + // The copy c'tor creates a new copy of the string. The two + // String objects do not share content. + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } + + // D'tor. String is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~String() { delete[] c_str_; } + + // Allows a String to be implicitly converted to an ::std::string or + // ::string, and vice versa. Converting a String containing a NULL + // pointer to ::std::string or ::string is undefined behavior. + // Converting a ::std::string or ::string containing an embedded NUL + // character to a String will result in the prefix up to the first + // NUL character. + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::std::string() const { return ::std::string(c_str(), length()); } + +#if GTEST_HAS_GLOBAL_STRING + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::string() const { return ::string(c_str(), length()); } +#endif // GTEST_HAS_GLOBAL_STRING + + // Returns true iff this is an empty string (i.e. ""). + bool empty() const { return (c_str() != NULL) && (length() == 0); } + + // Compares this with another String. + // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 + // if this is greater than rhs. + int Compare(const String& rhs) const; + + // Returns true iff this String equals the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } + + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". + bool operator<(const String& rhs) const { return Compare(rhs) < 0; } + + // Returns true iff this String doesn't equal the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } + + // Returns true iff this String ends with the given suffix. *Any* + // String is considered to end with a NULL or empty suffix. + bool EndsWith(const char* suffix) const; + + // Returns true iff this String ends with the given suffix, not considering + // case. Any String is considered to end with a NULL or empty suffix. + bool EndsWithCaseInsensitive(const char* suffix) const; + + // Returns the length of the encapsulated string, or 0 if the + // string is NULL. + size_t length() const { return length_; } + + // Gets the 0-terminated C string this String object represents. + // The String object still owns the string. Therefore the caller + // should NOT delete the return value. + const char* c_str() const { return c_str_; } + + // Assigns a C string to this object. Self-assignment works. + const String& operator=(const char* a_c_str) { + return *this = String(a_c_str); + } + + // Assigns a String object to this object. Self-assignment works. + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); + } + } + + return *this; + } + + private: + // Constructs a non-NULL String from the given content. This + // function can only be called when data_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t a_length) { + char* const str = new char[a_length + 1]; + memcpy(str, buffer, a_length); + str[a_length] = '\0'; + c_str_ = str; + length_ = a_length; + } + + const char* c_str_; + size_t length_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; +} + +// Gets the content of the StrStream's buffer as a String. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ String StrStreamToString(StrStream* stream); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". + +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const char* pathname) : pathname_(pathname) { + Normalize(); + } + + explicit FilePath(const String& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + String ToString() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is NULL or "". + bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + String pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +#ifdef __GLIBCXX__ +#include +#endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// GetTypeName() returns a human-readable name of type T. +template +String GetTypeName() { +#if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +#ifdef __GLIBCXX__ + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. + char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +#else + return name; +#endif // __GLIBCXX__ + +#else + return ""; +#endif // GTEST_HAS_RTTI +} + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +#define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +#define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Google Test defines the testing::Message class to allow construction of +// test messages via the << operator. The idea is that anything +// streamable to std::ostream can be streamed to a testing::Message. +// This allows a user to use his own types in Google Test assertions by +// overloading the << operator. +// +// util/gtl/stl_logging-inl.h overloads << for STL containers. These +// overloads cannot be defined in the std namespace, as that will be +// undefined behavior. Therefore, they are defined in the global +// namespace instead. +// +// C++'s symbol lookup rule (i.e. Koenig lookup) says that these +// overloads are visible in either the std namespace or the global +// namespace, but not other namespaces, including the testing +// namespace which Google Test's Message class is in. +// +// To allow STL containers (and other types that has a << operator +// defined in the global namespace) to be used in Google Test assertions, +// testing::Message must access the custom << operator from the global +// namespace. Hence this helper function. +// +// Note: Jeffrey Yasskin suggested an alternative fix by "using +// ::operator<<;" in the definition of Message's operator<<. That fix +// doesn't require a helper function, but unfortunately doesn't +// compile with MSVC. +template +inline void GTestStreamToHelper(std::ostream* os, const T& val) { + *os << val; +} + +namespace testing { + +// Forward declaration of classes. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +#define GTEST_IS_NULL_LITERAL_(x) false +#else +#define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ String AppendUserMessage(const String& gtest_msg, + const Message& user_msg); + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +// Formats a value to be used in a failure message. + +#ifdef GTEST_NEEDS_IS_POINTER_ + +// These are needed as the Nokia Symbian and IBM XL C/C++ compilers +// cannot decide between const T& and const T* in a function template. +// These compilers _can_ decide between class template specializations +// for T and T*, so a tr1::type_traits-like is_pointer works, and we +// can overload on that. + +// This overload makes sure that all pointers (including +// those to char or wchar_t) are printed as raw pointers. +template +inline String FormatValueForFailureMessage(internal::true_type /*dummy*/, + T* pointer) { + return StreamableToString(static_cast(pointer)); +} + +template +inline String FormatValueForFailureMessage(internal::false_type /*dummy*/, + const T& value) { + return StreamableToString(value); +} + +template +inline String FormatForFailureMessage(const T& value) { + return FormatValueForFailureMessage( + typename internal::is_pointer::type(), value); +} + +#else + +// These are needed as the above solution using is_pointer has the +// limitation that T cannot be a type without external linkage, when +// compiled using MSVC. + +template +inline String FormatForFailureMessage(const T& value) { + return StreamableToString(value); +} + +// This overload makes sure that all pointers (including +// those to char or wchar_t) are printed as raw pointers. +template +inline String FormatForFailureMessage(T* pointer) { + return StreamableToString(static_cast(pointer)); +} + +#endif // GTEST_NEEDS_IS_POINTER_ + +// These overloaded versions handle narrow and wide characters. +GTEST_API_ String FormatForFailureMessage(char ch); +GTEST_API_ String FormatForFailureMessage(wchar_t wchar); + +// When this operand is a const char* or char*, and the other operand +// is a ::std::string or ::string, we print this operand as a C string +// rather than a pointer. We do the same for wide strings. + +// This internal macro is used to avoid duplicated code. +#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ +inline String FormatForComparisonFailureMessage(\ + operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +}\ +inline String FormatForComparisonFailureMessage(\ + const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +} + +GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) +#if GTEST_HAS_STD_WSTRING +GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) +#endif // GTEST_HAS_GLOBAL_STRING +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_GLOBAL_WSTRING + +#undef GTEST_FORMAT_IMPL_ + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ String GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Formats a source file path and a line number as they would appear +// in a compiler error message. +inline String FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? "unknown file" : file; + if (line < 0) { + return String::Format("%s:", file_name); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line); +#else + return String::Format("%s:%d:", file_name, line); +#endif // _MSC_VER +} + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// test_case_comment: a comment on the test case that will be included in +// the test output +// comment: a comment on the test that will be included in the +// test output +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (isspace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline String GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? String(str) : String(str, comma - str); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", + case_name, index).c_str(), + GetPrefixUntilComma(test_names).c_str(), + String::Format("TypeParam = %s", GetTypeName().c_str()).c_str(), + "", + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, + int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_(message, result_type) \ + ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \ + = ::testing::Message() + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg = "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different " \ + "type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg = "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail(gtest_msg) + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + gtest_msg = "Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail(gtest_msg) + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const char* gtest_msg = "") { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + gtest_msg = "Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail(gtest_msg) + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, "", "", \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the two reasons that a test might be aborted. + enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const String& message); + + private: + // A string containing a description of the outcome of the last death test. + static String last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const String& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + String file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + String file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +#define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i); +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +#define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +#define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +#define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +#define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +#if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +#endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +#ifdef NDEBUG + +#define EXPECT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +#define ASSERT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +#else + +#define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +#define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +#endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a StrStream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that StrStream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + // We allocate the StrStream separately because it otherwise each use of + // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's + // stack frame leading to huge stack frames in some cases; gcc does not reuse + // the stack space. + Message() : ss_(new internal::StrStream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); + } + + // Copy constructor. + Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new internal::StrStream) { + *ss_ << str; + } + + ~Message() { delete ss_; } +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + ::GTestStreamToHelper(ss_, val); + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_, pointer); + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + Message& operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as a String. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::String GetString() const { + return internal::StrStreamToString(ss_); + } + + private: +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_, pointer); + } + } + template + inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { + ::GTestStreamToHelper(ss_, value); + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + internal::StrStream* const ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It must be derived from testing::TestWithParam, where T is +// the type of your parameter values. TestWithParam is itself derived +// from testing::Test. T can be any copyable type. If it's a raw pointer, +// you are responsible for managing the lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. + +#endif // 0 + + +#if !GTEST_OS_SYMBIAN +#include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + // Release ownership of the pointed object and returns it. + // Sole ownership by this linked_ptr object is required. + T* release() { + bool last = link_.depart(); + assert(last); + T* v = value_; + value_ = NULL; + return v; + } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + ::testing::internal::linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const String& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const String& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const char* instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const String& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + Message test_case_name_stream; + if ( !instantiation_name.empty() ) + test_case_name_stream << instantiation_name.c_str() << "/"; + test_case_name_stream << test_info->test_case_base_name.c_str(); + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name.c_str() << "/" << i; + ::testing::internal::MakeAndRegisterTestInfo( + test_case_name_stream.GetString().c_str(), + test_name_stream.GetString().c_str(), + "", // test_case_comment + "", // comment; TODO(vladl@google.com): provide parameter value + // representation. + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const String test_case_base_name; + const String test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const String test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::std::iterator_traits::value_type> ValuesIn( + ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, + v23_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, + v35_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, + v47_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_, v50_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +#if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +#endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::std::iterator_traits::value_type> ValuesIn( + ForwardIterator begin, + ForwardIterator end) { + typedef typename ::std::iterator_traits::value_type + ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +#if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +#endif // GTEST_HAS_COMBINE + + + +#define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { return file_name_.c_str(); } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static internal::String ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // NULL if the source file is unknown. + internal::String file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + internal::String summary_; // The test failure summary. + internal::String message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +#define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +#define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +#define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +#define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +#define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class TestInfoImpl; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message); +class PrettyUnitTestResultPrinter; +class XmlUnitTestResultPrinter; + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared in gtest-internal.h but defined here, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL && message_->c_str() != NULL ? + message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value); + + private: + // No implementation - we want AssertionResult to be + // copy-constructible but not assignable. + void operator=(const AssertionResult& other); + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr message_; +}; // class AssertionResult + +// Streams a custom failure message into this object. +template +AssertionResult& AssertionResult::operator<<(const T& value) { + Message msg; + if (message_.get() != NULL) + msg << *message_; + msg << value; + message_.reset(new internal::String(msg.GetString())); + return *this; +} + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class internal::TestInfoImpl; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test. Only the last value for a given + // key is remembered. + // These are public static so they can be called from utility functions + // that are not members of the test fixture. + // The arguments are const char* instead strings, as Google Test is used + // on platforms where string doesn't compile. + // + // Note that a driving consideration for these RecordProperty methods + // was to produce xml output suited to the Greenspan charting utility, + // which at present will only chart values that fit in a 32-bit int. It + // is the user's responsibility to restrict their values to 32-bit ints + // if they intend them to be used with Greenspan. + static void RecordProperty(const char* key, const char* value); + static void RecordProperty(const char* key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* a_key, const char* a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + internal::String key_; + // The value supplied by the user. + internal::String value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestInfoImpl; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const; + + // Returns the test name. + const char* name() const; + + // Returns the test case comment. + const char* test_case_comment() const; + + // Returns the test comment. + const char* comment() const; + + // Returns true if this test should run, that is if the test is not disabled + // (or it is disabled but the also_run_disabled_tests flag has been specified) + // and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const; + + // Returns the result of the test. + const TestResult* result() const; + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::TestInfoImpl; + friend class internal::UnitTestImpl; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Returns true if this test matches the user-specified filter. + bool matches_filter() const; + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count(); + + // Accessors for the implementation object. + internal::TestInfoImpl* impl() { return impl_; } + const internal::TestInfoImpl* impl() const { return impl_; } + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const char* test_case_name, const char* name, + const char* test_case_comment, const char* comment, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // An opaque implementation object. + internal::TestInfoImpl* impl_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* comment, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the test case comment. + const char* comment() const { return comment_.c_str(); } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Returns true iff test passed. + static bool TestPassed(const TestInfo * test_info); + + // Returns true iff test failed. + static bool TestFailed(const TestInfo * test_info); + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo * test_info); + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo *test_info); + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + internal::String name_; + // Comment on the test case. + internal::String comment_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCESS(). + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::TestInfoImpl; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const; + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const; + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace); + + // Adds a TestProperty to the current TestResult object. If the result already + // contains a property with the same key, the value will be updated. + void RecordPropertyForCurrentTest(const char* key, const char* value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const internal::String& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace(); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// These overloaded versions handle ::std::string and ::std::wstring. +GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) { + return (Message() << '"' << str << '"').GetString(); +} + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) { + return (Message() << "L\"" << wstr << '"').GetString(); +} +#endif // GTEST_HAS_STD_WSTRING + +// These overloaded versions handle ::string and ::wstring. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ inline String FormatForFailureMessage(const ::string& str) { + return (Message() << '"' << str << '"').GetString(); +} +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) { + return (Message() << "L\"" << wstr << '"').GetString(); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char*, and print it as a C string when it is compared against an +// std::string object, for example. +// +// The default implementation ignores the type of the other operand. +// Some specialized versions are used to handle formatting wide or +// narrow C strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +String FormatForComparisonFailureMessage(const T1& value, + const T2& /* other_operand */) { + return FormatForFailureMessage(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to + // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& /* expected */, + T2* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + Message msg;\ + msg << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return AssertionFailure(msg);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, < ); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, > ); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + StrStream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + StrStream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StrStreamToString(&expected_ss), + StrStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The abstract base class that all value-parameterized tests inherit from. +// +// This class adds support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class TestWithParam : public Test { + public: + typedef T ParamType; + + // The current parameter value. Is also available in the test fixture's + // constructor. + const ParamType& GetParam() const { return *parameter_; } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of TestWithParam. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* TestWithParam::parameter_ = NULL; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// +// Examples: +// +// EXPECT_TRUE(server.StatusIsOK()); +// ASSERT_FALSE(server.HasPendingRequest(port)) +// << "There are still pending requests " << "on port " << port; + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +#define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +#define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + Message msg; + msg << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; + return AssertionFailure(msg); +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// C String Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +#define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +#define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +#define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +namespace internal { + +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +} // namespace internal + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Use this macro in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). + +#define RUN_ALL_TESTS()\ + (::testing::UnitTest::GetInstance()->Run()) + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfColor.h b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfColor.h index 810a8320fa..2605d1283e 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfColor.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfColor.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfMat4d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfMat4d.h index a6293a251d..5313046111 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfMat4d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfMat4d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfVec3d.h index 4948fee8d2..6f517d4a9d 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmFieldCvfVec3d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2014 Ceetron Solutions AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp index 4506c24939..cedd8caabe 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h index 395c886d14..daa6d4de62 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreMat4d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreMat4d.h index 9adf5b38ef..6057fbe528 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreMat4d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreMat4d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,17 +34,16 @@ // //################################################################################################## - #pragma once -#include "cvfBase.h" -#include "cvfMatrix4.h" +#include "cafPdmCoreMat4d.h" #include "cafInternalPdmValueFieldSpecializations.h" #include "cafPdmUiFieldSpecialization.h" #include "cafPdmUiItem.h" -#include "cafPdmCoreMat4d.h" +#include "cvfBase.h" +#include "cvfMatrix4.h" namespace caf { @@ -59,7 +58,6 @@ class PdmUiFieldSpecialization < cvf::Mat4d > return PdmValueFieldSpecialization< cvf::Mat4d >::convert(value); } - /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, cvf::Mat4d& value) { diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp index c5cd968f37..e56bd5af6b 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h index 2fd75fea97..df7eb2bd1c 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,17 +34,17 @@ // //################################################################################################## - #pragma once -#include "cvfBase.h" -#include "cvfVector3.h" +#include "cafPdmCoreVec3d.h" #include "cafInternalPdmValueFieldSpecializations.h" #include "cafPdmUiFieldSpecialization.h" #include "cafPdmUiItem.h" -#include "cafPdmCoreVec3d.h" +#include "cvfBase.h" +#include "cvfVector3.h" + class Vec3dDummy { diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.cpp index 23b27d1b0a..9dc6ec48be 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -36,10 +36,9 @@ #include "cafPdmXmlColor3f.h" - #include -void operator >> (QTextStream& str, cvf::Color3f& value) +QTextStream& operator >> (QTextStream& str, cvf::Color3f& value) { QString text; @@ -49,11 +48,13 @@ void operator >> (QTextStream& str, cvf::Color3f& value) str >> b; value.set(r, g, b); + + return str; } -void operator << (QTextStream& str, const cvf::Color3f& value) +QTextStream& operator << (QTextStream& str, const cvf::Color3f& value) { str << value.r() << " " << value.g() << " " << value.b(); -} - + return str; +} diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.h index 36d19809ec..c14942ec69 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlColor3f.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" @@ -46,5 +45,5 @@ class QTextStream; /// QTextStream Stream operator for cvf::Color3f //================================================================================================== -void operator >> (QTextStream& str, cvf::Color3f& value); -void operator << (QTextStream& str, const cvf::Color3f& value); +QTextStream& operator >> (QTextStream& str, cvf::Color3f& value); +QTextStream& operator << (QTextStream& str, const cvf::Color3f& value); diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.cpp index 89dc738c41..0a4cf063ec 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -36,10 +36,9 @@ #include "cafPdmXmlMat4d.h" - #include -void operator >> (QTextStream& str, cvf::Mat4d& value) +QTextStream& operator >> (QTextStream& str, cvf::Mat4d& value) { for (int r = 0; r < 4; ++r) { @@ -48,15 +47,24 @@ void operator >> (QTextStream& str, cvf::Mat4d& value) str >> value(r, c); } } + + return str; } -void operator << (QTextStream& str, const cvf::Mat4d& value) +QTextStream& operator << (QTextStream& str, const cvf::Mat4d& value) { for (int r = 0; r < 4; ++r) { for (int c = 0; c < 4; ++c) { - str << value(r, c) << " "; + str << value(r, c); + + if (r * c < 9) + { + str << " "; + } } } + + return str; } diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.h index 51fd8a5737..20ce3c654d 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlMat4d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" @@ -42,5 +41,5 @@ class QTextStream; -void operator >> (QTextStream& str, cvf::Mat4d& value); -void operator << (QTextStream& str, const cvf::Mat4d& value); +QTextStream& operator >> (QTextStream& str, cvf::Mat4d& value); +QTextStream& operator << (QTextStream& str, const cvf::Mat4d& value); diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.cpp index 63f645936a..432d82dbf2 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.cpp @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -36,36 +36,25 @@ #include "cafPdmXmlVec3d.h" - #include -void operator >> (QTextStream& str, cvf::Vec3d& value) +QTextStream& operator >> (QTextStream& str, cvf::Vec3d& value) { - bool streamStatusOk = true; - - cvf::Vec3d tmp; - for (int r = 0; r < 3; ++r) - { - str >> tmp[r]; + QString text; - if (str.status() != QTextStream::Ok) - { - streamStatusOk = false; - } - } + double x, y, z; + str >> x; + str >> y; + str >> z; - if (streamStatusOk) - { - value = tmp; - } + value.set(x, y, z); + return str; } -void operator << (QTextStream& str, const cvf::Vec3d& value) +QTextStream& operator << (QTextStream& str, const cvf::Vec3d& value) { - for (int r = 0; r < 3; ++r) - { - str << value[r]; - if (r < 2) str << " "; - } + str << value.x() << " " << value.y() << " " << value.z(); + + return str; } diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.h index a3af7fa539..3b2f02f4d2 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmXmlVec3d.h @@ -1,7 +1,7 @@ //################################################################################################## // // Custom Visualization Core library -// Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -34,7 +34,6 @@ // //################################################################################################## - #pragma once #include "cvfBase.h" @@ -42,5 +41,5 @@ class QTextStream; -void operator >> (QTextStream& str, cvf::Vec3d& value); -void operator << (QTextStream& str, const cvf::Vec3d& value); +QTextStream& operator >> (QTextStream& str, cvf::Vec3d& value); +QTextStream& operator << (QTextStream& str, const cvf::Vec3d& value); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt index 6040797dd5..add7096a0d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 2.8) -find_package ( Qt4 COMPONENTS QtCore ) +find_package ( Qt4 COMPONENTS QtCore QtGui ) include (${QT_USE_FILE}) project ( cafPdmCore_UnitTests ) @@ -42,6 +42,7 @@ target_link_libraries ( ${PROJECT_NAME} ${QT_LIBRARIES} ) + # Copy Qt Dlls if (MSVC) set (QTLIBLIST QtCore ) diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index a06f74de5b..d7314cd68b 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -1,10 +1,6 @@ #include "TapCvfSpecialization.h" -#include "cafPdmCoreVec3d.h" -#include "cafPdmXmlVec3d.h" -#include "cafPdmUiCoreVec3d.h" - CAF_PDM_SOURCE_INIT(TapCvfSpecialization, "TapCvfSpecialization"); diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt index 16e1b7b524..84845ecf4a 100644 --- a/Fwk/CMakeLists.txt +++ b/Fwk/CMakeLists.txt @@ -35,7 +35,9 @@ if (USE_CEE_VIZ) add_subdirectory(VizFwk/LibCore) add_subdirectory(AppFwk/cafPdmCvf) + add_subdirectory(AppFwk/cafPdmCvf/cafPdmCvf_UnitTests) + add_subdirectory(AppFwk/cafTests/cafTestCvfApplication) - set_property(TARGET LibCore cafPdmCvf cafTestCvfApplication PROPERTY FOLDER "CeeViz") + set_property(TARGET LibCore cafPdmCvf cafPdmCvf_UnitTests cafTestCvfApplication PROPERTY FOLDER "CeeViz") endif() From 3a3d28003b488725b2719891e33aa487e20c3a86 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 13:58:17 +0100 Subject: [PATCH 141/290] [Fwk] Use PdmValueFieldSpecialization instead of QVariant constructor --- .../cafInternalPdmValueFieldSpecializations.h | 35 +++++++++---------- .../cafInternalPdmFieldTypeSpecializations.h | 19 ++-------- 2 files changed, 18 insertions(+), 36 deletions(-) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h index 50112cc5cd..7e37599b80 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafInternalPdmValueFieldSpecializations.h @@ -1,5 +1,9 @@ #pragma once +#include "cafAppEnum.h" + +#include + #include namespace caf @@ -39,15 +43,12 @@ class PdmValueFieldSpecialization { return variantValue == variantValue2; } - }; -} // End of namespace caf - -#include "cafAppEnum.h" -namespace caf -{ +//================================================================================================== +/// Partial specialization for caf::AppEnum +//================================================================================================== template class PdmValueFieldSpecialization > { @@ -67,18 +68,12 @@ class PdmValueFieldSpecialization > { return variantValue == variantValue2; } - }; -} // End of namespace caf - - - -#include - -namespace caf -{ +//================================================================================================== +/// Partial specialization for std::vector +//================================================================================================== template class PdmValueFieldSpecialization > { @@ -89,10 +84,10 @@ class PdmValueFieldSpecialization > typename std::vector::const_iterator it; for (it = value.begin(); it != value.end() ; ++it) { - returnList.push_back(QVariant::fromValue(*it)); + returnList.push_back(PdmValueFieldSpecialization::convert(*it)); } - return returnList; + return returnList; } static void setFromVariant(const QVariant& variantValue, std::vector& value) @@ -103,7 +98,10 @@ class PdmValueFieldSpecialization > QList lst = variantValue.toList(); for (int i = 0; i < lst.size(); ++i) { - value.push_back(lst[i].value()); + T val; + PdmValueFieldSpecialization::setFromVariant(lst[i], val); + + value.push_back(val); } } } @@ -112,7 +110,6 @@ class PdmValueFieldSpecialization > { return variantValue == variantValue2; } - }; } // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h index 749c956410..ea4e37d1e8 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h @@ -111,28 +111,13 @@ class PdmUiFieldSpecialization < std::vector > /// Convert the field value into a QVariant static QVariant convert(const std::vector& value) { - QList returnList; - typename std::vector::const_iterator it; - for (it = value.begin(); it != value.end() ; ++it) - { - returnList.push_back(QVariant(*it)); - } - return returnList; + return PdmValueFieldSpecialization< std::vector >::convert(value); } /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, std::vector& value) { - if (variantValue.canConvert< QList >()) - { - value.clear(); - QList lst = variantValue.toList(); - int i; - for (i = 0; i < lst.size(); ++i) - { - value.push_back(lst[i].value()); - } - } + return PdmValueFieldSpecialization< std::vector >::setFromVariant(variantValue, value); } static bool isEqual(const QVariant& variantValue, const QVariant& variantValue2) From 5093b559d2435da2642bf1ddc6718b43af14a76a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 14:00:59 +0100 Subject: [PATCH 142/290] [Fwk] Set default editor for std::vector of Vec3d --- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp index e56bd5af6b..0df470f53d 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp @@ -39,8 +39,10 @@ #include "cafPdmField.h" #include "cafPdmProxyValueField.h" #include "cafPdmUiLineEditor.h" +#include "cafPdmUiListEditor.h" CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(caf::PdmUiLineEditor, cvf::Vec3d); +CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(caf::PdmUiListEditor, std::vector); //-------------------------------------------------------------------------------------------------- // If the macro for registering the editor is put as the single statement From 8e85c4e8fbeabb38f80ba0128e6232657eff58fa Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 14:01:24 +0100 Subject: [PATCH 143/290] [Fwk] Created test project for Cvf specialization --- .../cafTestCvfApplication/MainWindow.cpp | 395 +----------------- .../cafTestCvfApplication/MainWindow.h | 9 +- .../TapCvfSpecialization.cpp | 1 + .../cafTestCvfApplication/TapProject.cpp | 3 + .../cafTestCvfApplication/TapProject.h | 5 + 5 files changed, 35 insertions(+), 378 deletions(-) diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp index 1070ca1279..08a3f90ad3 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.cpp @@ -1,24 +1,9 @@ - -#include "cafPdmField.h" - #include "MainWindow.h" -#include "WidgetLayoutTest.h" - -#include -#include -#include -#include -#include +#include "WidgetLayoutTest.h" #include "cafAppEnum.h" - -#ifdef TAP_USE_COMMAND_FRAMEWORK -#include "cafCmdExecCommandManager.h" -#include "cafCmdSelectionHelper.h" -#include "cafCmdFeatureManager.h" -#endif - +#include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmObjectGroup.h" #include "cafPdmProxyValueField.h" @@ -32,329 +17,18 @@ #include "cafPdmUiTreeView.h" #include "cafSelectionManager.h" +#include +#include +#include +#include +#include - -class DemoPdmObjectGroup : public caf::PdmObjectCollection -{ - CAF_PDM_HEADER_INIT; -public: - - DemoPdmObjectGroup() - { - objects.uiCapability()->setUiHidden(true); - - } -}; - -CAF_PDM_SOURCE_INIT(DemoPdmObjectGroup, "DemoPdmObjectGroup"); - -class SmallDemoPdmObject: public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - - SmallDemoPdmObject() - { - CAF_PDM_InitObject("Small Demo Object", ":/images/win/filenew.png", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework"); - - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Toggle Field", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want" ); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Text", "", "Text tooltip", "This is a place you can enter a small integer value if you want"); - - m_proxyDoubleField.registerSetMethod(this, &SmallDemoPdmObject::setDoubleMember); - m_proxyDoubleField.registerGetMethod(this, &SmallDemoPdmObject::doubleMember); - CAF_PDM_InitFieldNoDefault(&m_proxyDoubleField, "ProxyDouble", "Proxy Double", "", "", ""); - - m_proxyDoubleField = 0; - if (!(m_proxyDoubleField == 3)) { std::cout << "Double is not 3 " << std::endl; } - - } - - - caf::PdmField m_doubleField; - caf::PdmField m_intField; - caf::PdmField m_textField; - caf::PdmProxyValueField m_proxyDoubleField; - - caf::PdmField m_toggleField; - virtual caf::PdmFieldHandle* objectToggleField() - { - return &m_toggleField; - } - - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) - { - if (changedField == &m_toggleField) - { - std::cout << "Toggle Field changed" << std::endl; - } - } - - void setDoubleMember(const double& d) { m_doubleMember = d; std::cout << "setDoubleMember" << std::endl; } - double doubleMember() const { std::cout << "doubleMember" << std::endl; return m_doubleMember; } - -private: - double m_doubleMember; - -}; - -CAF_PDM_SOURCE_INIT(SmallDemoPdmObject, "SmallDemoPdmObject"); - - -class SmallDemoPdmObjectA: public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - - enum TestEnumType - { - T1, T2, T3 - }; - - - SmallDemoPdmObjectA() - { - CAF_PDM_InitObject("Small Demo Object A", "", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework"); - - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Toggle Field", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here","This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString("Small Demo Object A"), "Name Text Field", "", "", ""); - CAF_PDM_InitField(&m_testEnumField, "TestEnumValue", caf::AppEnum(T1), "EnumField", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_ptrField, "m_ptrField", "PtrField", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&m_proxyEnumField, "ProxyEnumValue", "ProxyEnum", "", "", ""); - m_proxyEnumField.registerSetMethod(this, &SmallDemoPdmObjectA::setEnumMember); - m_proxyEnumField.registerGetMethod(this, &SmallDemoPdmObjectA::enumMember); - m_proxyEnumMember = T2; - - m_testEnumField.capability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); - } - - caf::PdmField m_doubleField; - caf::PdmField m_intField; - caf::PdmField m_textField; - caf::PdmField< caf::AppEnum > m_testEnumField; - caf::PdmPtrField m_ptrField; - - caf::PdmProxyValueField< caf::AppEnum > m_proxyEnumField; - void setEnumMember(const caf::AppEnum& val) { m_proxyEnumMember = val; } - caf::AppEnum enumMember() const { return m_proxyEnumMember; } - TestEnumType m_proxyEnumMember; - - - - caf::PdmField m_toggleField; - virtual caf::PdmFieldHandle* objectToggleField() - { - return &m_toggleField; - } - - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) - { - if (changedField == &m_toggleField) - { - std::cout << "Toggle Field changed" << std::endl; - } - } - - virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) - { - QList options; - - - if (&m_ptrField == fieldNeedingOptions) - { - caf::PdmFieldHandle* field; - std::vector objects; - field = this->parentField(); - - field->childObjects(&objects); - - for (size_t i = 0; i < objects.size(); ++i) - { - QString userDesc; - - caf::PdmUiObjectHandle* uiObject = caf::uiObj(objects[i]); - if (uiObject) - { - if (uiObject->userDescriptionField()) - { - caf::PdmUiFieldHandle* uiFieldHandle = uiObject->userDescriptionField()->uiCapability(); - if (uiFieldHandle) - { - userDesc = uiFieldHandle->uiValue().toString(); - } - } - - options.push_back(caf::PdmOptionItemInfo(uiObject->uiName() + "(" + userDesc + ")", QVariant::fromValue(caf::PdmPointer(objects[i])))); - } - } - } - - if (useOptionsOnly) *useOptionsOnly = true; - - return options; - } - - //-------------------------------------------------------------------------------------------------- - /// - //-------------------------------------------------------------------------------------------------- - virtual caf::PdmFieldHandle* userDescriptionField() - { - return &m_textField; - } - -}; - -CAF_PDM_SOURCE_INIT(SmallDemoPdmObjectA, "SmallDemoPdmObjectA"); - -namespace caf -{ - template<> - void AppEnum::setUp() - { - addItem(SmallDemoPdmObjectA::T1, "T1", "An A letter"); - addItem(SmallDemoPdmObjectA::T2, "T2", "A B letter"); - addItem(SmallDemoPdmObjectA::T3, "T3", "A B C letter"); - setDefault(SmallDemoPdmObjectA::T1); - - } - -} -Q_DECLARE_METATYPE(caf::AppEnum); - - - - -class DemoPdmObject: public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - - DemoPdmObject() - { - CAF_PDM_InitObject( "Demo Object", "", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework"); - - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Toggle Field", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want" ); - CAF_PDM_InitField(&m_boolField, "BooleanValue", false, "Boolean:" , "", "Boolean:Enter some small number here", "Boolean:This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString("Demo Object Description Field"), "", "", "", ""); - CAF_PDM_InitField(&m_filePath, "FilePath", QString(""), "Filename", "", "", ""); - CAF_PDM_InitField(&m_longText, "LongText", QString("Test text"), "Long Text", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&m_multiSelectList, "MultiSelect", "Selection List", "", "List" , "This is a multi selection list" ); - CAF_PDM_InitFieldNoDefault(&m_objectList, "ObjectList", "Objects list Field", "", "List" , "This is a list of PdmObjects" ); - CAF_PDM_InitFieldNoDefault(&m_objectListOfSameType, "m_objectListOfSameType", "Same type Objects list Field", "", "Same type List" , "Same type list of PdmObjects" ); - CAF_PDM_InitFieldNoDefault(&m_ptrField, "m_ptrField", "PtrField", "", "Same type List", "Same type list of PdmObjects"); - - m_filePath.capability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); - m_filePath.capability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); - m_longText.capability()->setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName()); - m_longText.capability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); - - } - - //-------------------------------------------------------------------------------------------------- - /// - //-------------------------------------------------------------------------------------------------- - virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) - { - uiOrdering.add(&m_ptrField); - uiOrdering.add(&m_boolField); - caf::PdmUiGroup* group1 = uiOrdering.addNewGroup("Name1"); - group1->add(&m_doubleField); - caf::PdmUiGroup* group2 = uiOrdering.addNewGroup("Name2"); - group2->add(&m_intField); - caf::PdmUiGroup* group3 = group2->addNewGroup("Name3"); - group3->add(&m_textField); - - //uiConfig->add(&f3); - //uiConfig->forgetRemainingFields(); - } - - //-------------------------------------------------------------------------------------------------- - /// - //-------------------------------------------------------------------------------------------------- - virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) - { - QList options; - if (&m_multiSelectList == fieldNeedingOptions) - { - - options.push_back(caf::PdmOptionItemInfo("Choice 1", "Choice1")); - options.push_back(caf::PdmOptionItemInfo("Choice 2", "Choice2")); - options.push_back(caf::PdmOptionItemInfo("Choice 3", "Choice3")); - options.push_back(caf::PdmOptionItemInfo("Choice 4", "Choice4")); - options.push_back(caf::PdmOptionItemInfo("Choice 5", "Choice5")); - options.push_back(caf::PdmOptionItemInfo("Choice 6", "Choice6")); - - } - - if (&m_ptrField == fieldNeedingOptions) - { - for (size_t i = 0; i < m_objectListOfSameType.size(); ++i) - { - caf::PdmUiObjectHandle* uiObject = caf::uiObj(m_objectListOfSameType[i]); - if (uiObject) - { - options.push_back(caf::PdmOptionItemInfo(uiObject->uiName(), QVariant::fromValue(caf::PdmPointer(m_objectListOfSameType[i])))); - } - } - } - - if (useOptionsOnly) *useOptionsOnly = true; - - return options; - } - - //-------------------------------------------------------------------------------------------------- - /// - //-------------------------------------------------------------------------------------------------- - virtual caf::PdmFieldHandle* userDescriptionField() - { - return &m_textField; - } - - - - // Fields - caf::PdmField m_boolField; - caf::PdmField m_doubleField; - caf::PdmField m_intField; - caf::PdmField m_textField; - - caf::PdmField m_filePath; - - caf::PdmField m_longText; - caf::PdmField > m_multiSelectList; - - - caf::PdmChildArrayField< caf::PdmObjectHandle* > m_objectList; - caf::PdmChildArrayField< SmallDemoPdmObjectA* > m_objectListOfSameType; - caf::PdmPtrField m_ptrField; - - - caf::PdmField m_toggleField; - virtual caf::PdmFieldHandle* objectToggleField() - { - return &m_toggleField; - } - - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) - { - if (changedField == &m_toggleField) - { - std::cout << "Toggle Field changed" << std::endl; - } - } - -}; - -CAF_PDM_SOURCE_INIT(DemoPdmObject, "DemoPdmObject"); - +#ifdef TAP_USE_COMMAND_FRAMEWORK +#include "cafCmdExecCommandManager.h" +#include "cafCmdSelectionHelper.h" +#include "cafCmdFeatureManager.h" +#endif +#include "TapProject.h" MainWindow* MainWindow::sm_mainWindowInstance = NULL; @@ -372,10 +46,10 @@ MainWindow::MainWindow() createDockPanels(); buildTestModel(); - setPdmRoot(m_testRoot); + setPdmRoot(m_project); sm_mainWindowInstance = this; - caf::SelectionManager::instance()->setPdmRootObject(m_testRoot); + caf::SelectionManager::instance()->setPdmRootObject(m_project); #ifdef TAP_USE_COMMAND_FRAMEWORK caf::CmdExecCommandManager::instance()->enableUndoCommandSystem(true); @@ -457,37 +131,7 @@ void MainWindow::createDockPanels() //-------------------------------------------------------------------------------------------------- void MainWindow::buildTestModel() { - m_testRoot = new DemoPdmObjectGroup; - - DemoPdmObject* demoObject = new DemoPdmObject; - m_testRoot->objects.push_back(demoObject); - - SmallDemoPdmObject* smallObj1 = new SmallDemoPdmObject; - m_testRoot->objects.push_back(smallObj1); - - SmallDemoPdmObjectA* smallObj2 = new SmallDemoPdmObjectA; - m_testRoot->objects.push_back(smallObj2); - - DemoPdmObject* demoObj2 = new DemoPdmObject; - - demoObject->m_textField = "Mitt Demo Obj"; - demoObject->m_objectList.push_back(demoObj2); - demoObject->m_objectList.push_back(new SmallDemoPdmObjectA()); - SmallDemoPdmObject* smallObj3 = new SmallDemoPdmObject(); - demoObject->m_objectList.push_back(smallObj3); - demoObject->m_objectList.push_back(new SmallDemoPdmObject()); - - demoObject->m_objectListOfSameType.push_back(new SmallDemoPdmObjectA()); - demoObject->m_objectListOfSameType.push_back(new SmallDemoPdmObjectA()); - demoObject->m_objectListOfSameType.push_back(new SmallDemoPdmObjectA()); - demoObject->m_objectListOfSameType.push_back(new SmallDemoPdmObjectA()); - - - demoObj2->m_objectList.push_back(new SmallDemoPdmObjectA()); - demoObj2->m_objectList.push_back(new SmallDemoPdmObjectA()); - demoObj2->m_objectList.push_back(new SmallDemoPdmObject()); - - delete smallObj3; + m_project = new TapProject; } @@ -544,10 +188,9 @@ MainWindow::~MainWindow() //-------------------------------------------------------------------------------------------------- void MainWindow::releaseTestData() { - if (m_testRoot) + if (m_project) { - m_testRoot->objects.deleteAllChildObjects(); - delete m_testRoot; + delete m_project; } } @@ -586,6 +229,7 @@ void MainWindow::createActions() //-------------------------------------------------------------------------------------------------- void MainWindow::slotInsert() { +/* std::vector selection; m_pdmUiTreeView->selectedUiItems(selection); @@ -615,6 +259,7 @@ void MainWindow::slotInsert() } #endif } +*/ } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h index b9728a6824..afa9d3ad56 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/MainWindow.h @@ -1,13 +1,15 @@ #pragma once -#include +#include #include #include -class DemoPdmObject; class QTreeView; class QUndoView; +class TapProject; + + namespace caf { class PdmObjectCollection; @@ -58,6 +60,7 @@ private slots: caf::PdmUiTreeView* m_pdmUiTreeView2; caf::PdmUiPropertyView* m_pdmUiPropertyView; caf::PdmUiTableView* m_pdmUiTableView; - caf::PdmObjectCollection* m_testRoot; + + TapProject* m_project; }; diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index d7314cd68b..d11f8ae999 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -18,4 +18,5 @@ TapCvfSpecialization::TapCvfSpecialization() CAF_PDM_InitFieldNoDefault(&m_vecArrayField, "Points", "Selected points", "", "", ""); + m_vecArrayField.v().push_back(cvf::Vec3d(1, 2, 3)); } diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.cpp index 39df038a32..22fe1c2e1d 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.cpp @@ -1,4 +1,5 @@ #include "TapProject.h" +#include "TapCvfSpecialization.h" CAF_PDM_SOURCE_INIT(TapProject, "RPMProject"); @@ -9,6 +10,8 @@ TapProject::TapProject(void) { CAF_PDM_InitFieldNoDefault(&m_objectList, "ObjectList", "Objects list Field", "", "List", "This is a list of PdmObjects"); + CAF_PDM_InitFieldNoDefault(&m_testSpecialization, "TapCvfSpecialization", "TapCvfSpecialization Field", "", "", ""); + m_testSpecialization = new TapCvfSpecialization; } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h index 9ce03e4c9b..ac27ea67ee 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapProject.h @@ -1,7 +1,11 @@ #pragma once + #include "cafPdmDocument.h" #include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" + +class TapCvfSpecialization; class TapProject : public caf::PdmDocument @@ -14,4 +18,5 @@ class TapProject : public caf::PdmDocument caf::PdmChildArrayField< caf::PdmObjectHandle* > m_objectList; + caf::PdmChildField< TapCvfSpecialization* > m_testSpecialization; }; \ No newline at end of file From df604f7e12ea743c159e03dce21ac484683aa3cb Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 14:18:11 +0100 Subject: [PATCH 144/290] Commented out test project --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43df9b07d5..b6749c4ba2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,7 +208,7 @@ add_subdirectory(Fwk/AppFwk/cafUserInterface) add_subdirectory(Fwk/AppFwk/cafPdmCvf) add_subdirectory(Fwk/AppFwk/CommonCode) -add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication) +#add_subdirectory(Fwk/AppFwk/cafTests/cafTestCvfApplication) add_subdirectory(Fwk/AppFwk/cafTensor) From 147580e342f4963cffef55a3966ab24d9175cc10 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 05:54:43 -0800 Subject: [PATCH 145/290] Linux fix --- .../cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h index ea4e37d1e8..288b8fe381 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafInternalPdmFieldTypeSpecializations.h @@ -2,6 +2,7 @@ #include "cafPdmObjectHandle.h" #include "cafPdmPointer.h" +#include "cafInternalPdmValueFieldSpecializations.h" #include From 3c4142fc5263ef4049ba8ea8a3843309cbcec877 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 16:00:08 +0100 Subject: [PATCH 146/290] (#678) Show context menu commands on intersection Added hide intersection --- .../RivCrossSectionGeometryGenerator.cpp | 26 ++++-- .../RivCrossSectionGeometryGenerator.h | 15 +++- .../RivCrossSectionPartMgr.cpp | 2 +- .../RivCrossSectionSourceInfo.cpp | 8 ++ .../RivCrossSectionSourceInfo.h | 3 + .../ReservoirDataModel/RigMainGrid.cpp | 2 + .../UserInterface/RiuViewerCommands.cpp | 85 +++++++++++++------ .../UserInterface/RiuViewerCommands.h | 19 +++-- 8 files changed, 118 insertions(+), 42 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index f08201bfb9..5fa806c61d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -18,21 +18,26 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RivCrossSectionGeometryGenerator.h" -#include "cvfBoundingBox.h" + #include "RigMainGrid.h" -#include "cvfDrawableGeo.h" #include "RigResultAccessor.h" -#include "cvfScalarMapper.h" + +#include "RimCrossSection.h" + +#include "cvfDrawableGeo.h" #include "cvfPrimitiveSetDirect.h" +#include "cvfScalarMapper.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const std::vector > &polylines, - const cvf::Vec3d& extrusionDirection, - const RivCrossSectionHexGridIntf* grid) - : m_polyLines(polylines), +RivCrossSectionGeometryGenerator::RivCrossSectionGeometryGenerator(const RimCrossSection* crossSection, + std::vector > &polylines, + const cvf::Vec3d& extrusionDirection, + const RivCrossSectionHexGridIntf* grid) + : m_crossSection(crossSection), + m_polyLines(polylines), m_extrusionDirection(extrusionDirection), m_hexGrid(grid) { @@ -1185,6 +1190,13 @@ const std::vector& RivCrossSectionGeometryGenerator::triangleV return m_triVxToCellCornerWeights; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimCrossSection* RivCrossSectionGeometryGenerator::crossSection() const +{ + return m_crossSection; +} //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index f2e96c74c4..77e6526460 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -18,15 +18,20 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + +#include "cafPdmPointer.h" + +#include "cvfArray.h" #include "cvfBase.h" +#include "cvfBoundingBox.h" #include "cvfObject.h" #include "cvfVector3.h" -#include "cvfArray.h" #include class RigMainGrid; class RigResultAccessor; +class RimCrossSection; namespace cvf { @@ -34,7 +39,6 @@ namespace cvf class DrawableGeo; } -#include "cvfBoundingBox.h" class RivCrossSectionHexGridIntf : public cvf::Object @@ -124,7 +128,8 @@ class RivVertexWeights class RivCrossSectionGeometryGenerator : public cvf::Object { public: - RivCrossSectionGeometryGenerator(const std::vector > &polylines, + RivCrossSectionGeometryGenerator(const RimCrossSection* crossSection, + std::vector > &polylines, const cvf::Vec3d& extrusionDirection, const RivCrossSectionHexGridIntf* grid ); @@ -138,6 +143,8 @@ class RivCrossSectionGeometryGenerator : public cvf::Object const std::vector& triangleToCellIndex() const; const std::vector& triangleVxToCellCornerInterpolationWeights() const; + const RimCrossSection* crossSection() const; + private: void calculateArrays(); static void adjustPolyline(const std::vector& polyLine, @@ -153,5 +160,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object cvf::ref m_cellBorderLineVxes; std::vector m_triangleToCellIdxMap; std::vector m_triVxToCellCornerWeights; + + const RimCrossSection* m_crossSection; }; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 75a8cdcf89..e46e2f6f74 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -417,7 +417,7 @@ void RivCrossSectionPartMgr::computeData() { cvf::Vec3d direction = extrusionDirection(polyLines[0]); cvf::ref hexGrid = createHexGridInterface(); - m_crossSectionGenerator = new RivCrossSectionGeometryGenerator(polyLines, direction, hexGrid.p()); + m_crossSectionGenerator = new RivCrossSectionGeometryGenerator(m_rimCrossSection, polyLines, direction, hexGrid.p()); } } diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp index 2a9f4889fc..2f35e3f6cd 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.cpp @@ -40,3 +40,11 @@ const std::vector& RivCrossSectionSourceInfo::triangleToCellIndex() cons return m_crossSectionGeometryGenerator->triangleToCellIndex(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimCrossSection* RivCrossSectionSourceInfo::crossSection() const +{ + return m_crossSectionGeometryGenerator->crossSection(); +} diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h index c402319657..46afb6e409 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionSourceInfo.h @@ -24,6 +24,7 @@ #include "cvfArray.h" class RivCrossSectionGeometryGenerator; +class RimCrossSection; class RivCrossSectionSourceInfo : public cvf::Object { @@ -32,6 +33,8 @@ class RivCrossSectionSourceInfo : public cvf::Object const std::vector& triangleToCellIndex() const; + const RimCrossSection* crossSection() const; + private: cvf::cref m_crossSectionGeometryGenerator; }; diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp index 0cd30db889..463ba5e632 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp @@ -408,6 +408,8 @@ const RigFault* RigMainGrid::findFaultFromCellIndexAndCellFace(size_t reservoirC { CVF_ASSERT(m_faultsPrCellAcc.notNull()); + if (face == cvf::StructGridInterface::NO_FACE) return NULL; + int faultIdx = m_faultsPrCellAcc->faultIdx(reservoirCellIndex, face); if (faultIdx != RigFaultsPrCellAccumulator::NO_FAULT ) { diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 3816b46598..5307026e49 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -37,6 +37,7 @@ #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" #include "RimContextCommandBuilder.h" +#include "RimCrossSection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipsePropertyFilter.h" @@ -125,7 +126,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) QMenu menu; - uint faceIndex = cvf::UNDEFINED_UINT; + uint firstPartTriangleIndex = cvf::UNDEFINED_UINT; cvf::Vec3d localIntersectionPoint(cvf::Vec3d::ZERO); cvf::Part* firstHitPart = NULL; @@ -135,15 +136,16 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) if (m_viewer->rayPick(winPosX, winPosY, &hitItems)) { - extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &faceIndex, &nncFirstHitPart, NULL); + extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &firstPartTriangleIndex, &nncFirstHitPart, NULL); } - if (firstHitPart && faceIndex != cvf::UNDEFINED_UINT) + if (firstHitPart && firstPartTriangleIndex != cvf::UNDEFINED_UINT) { const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivCrossSectionSourceInfo* crossSectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - if (rivSourceInfo || femSourceInfo) + if (rivSourceInfo || femSourceInfo || crossSectionSourceInfo) { if (rivSourceInfo) { @@ -152,13 +154,21 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) // Set the data regarding what was hit m_currentGridIdx = rivSourceInfo->gridIndex(); - m_currentCellIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellIndex(faceIndex); - m_currentFaceIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellFace(faceIndex); + m_currentCellIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellIndex(firstPartTriangleIndex); + m_currentFaceIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellFace(firstPartTriangleIndex); } - else + else if (femSourceInfo) { m_currentGridIdx = femSourceInfo->femPartIndex(); - m_currentCellIndex = femSourceInfo->triangleToElmMapper()->elementIndex(faceIndex); + m_currentCellIndex = femSourceInfo->triangleToElmMapper()->elementIndex(firstPartTriangleIndex); + } + else if (crossSectionSourceInfo) + { + findCellAndGridIndex(crossSectionSourceInfo, firstPartTriangleIndex, &m_currentCellIndex, &m_currentGridIdx); + m_currentFaceIndex = cvf::StructGridInterface::NO_FACE; + m_currentCrossSection = const_cast(crossSectionSourceInfo->crossSection()); + + menu.addAction(QString("Hide intersection"), this, SLOT(slotHideIntersection())); } // IJK -slice commands @@ -337,7 +347,6 @@ void RiuViewerCommands::slotHideFault() RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); if(!eclipseView) return; - const RigCaseData* reservoir = eclipseView->eclipseCase()->reservoirData(); const RigFault* fault = reservoir->mainGrid()->findFaultFromCellIndexAndCellFace(m_currentCellIndex, m_currentFaceIndex); if (fault) @@ -384,6 +393,23 @@ void RiuViewerCommands::slotAddGeoMechPropertyFilter() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::slotHideIntersection() +{ + if (m_currentCrossSection) + { + m_currentCrossSection->isActive = false; + m_currentCrossSection->updateConnectedEditors(); + + if (m_reservoirView) + { + m_reservoirView->scheduleCreateDisplayModelAndRedraw(); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -441,22 +467,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } else if (crossSectionSourceInfo) { - RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); - RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); - - if (eclipseView) - { - size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; - - const RigCell& cell = eclipseView->eclipseCase()->reservoirData()->mainGrid()->globalCellArray()[globalCellIndex]; - cellIndex = cell.gridLocalCellIndex(); - gridIndex = cell.hostGrid()->gridIndex(); - } - else if (geomView) - { - cellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; - gridIndex = 0; - } + findCellAndGridIndex(crossSectionSourceInfo, firstPartTriangleIndex, &cellIndex, &gridIndex); } } @@ -525,6 +536,30 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::findCellAndGridIndex(const RivCrossSectionSourceInfo* crossSectionSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex) +{ + CVF_ASSERT(cellIndex && gridIndex); + + RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + if (eclipseView) + { + size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; + + const RigCell& cell = eclipseView->eclipseCase()->reservoirData()->mainGrid()->globalCellArray()[globalCellIndex]; + *cellIndex = cell.gridLocalCellIndex(); + *gridIndex = cell.hostGrid()->gridIndex(); + } + else if (geomView) + { + *cellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; + *gridIndex = 0; + } +} + //-------------------------------------------------------------------------------------------------- /// Perform picking and return the index of the face that was hit, if a drawable geo was hit //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 9e6c9b80d2..e7bc42825d 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -18,19 +18,22 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + +#include "cvfStructGrid.h" +#include "cafPdmPointer.h" + #include +#include -class RiuViewer; -class RimView; +class RimCrossSection; class RimEclipseView; class RimGeoMechView; +class RimView; +class RiuViewer; +class RivCrossSectionSourceInfo; class QMouseEvent; -#include "cvfStructGrid.h" -#include "cafPdmPointer.h" -#include - namespace cvf { class HitItemCollection; class Part; @@ -49,6 +52,8 @@ class RiuViewerCommands: public QObject void displayContextMenu(QMouseEvent* event); void handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers); + void findCellAndGridIndex(const RivCrossSectionSourceInfo* crossSectionSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex); + private slots: void slotRangeFilterI(); @@ -57,6 +62,7 @@ private slots: void slotHideFault(); void slotAddEclipsePropertyFilter(); void slotAddGeoMechPropertyFilter(); + void slotHideIntersection(); private: void ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size_t* i, size_t* j, size_t* k); @@ -69,6 +75,7 @@ private slots: cvf::StructGridInterface::FaceType m_currentFaceIndex; caf::PdmPointer m_reservoirView; + caf::PdmPointer m_currentCrossSection; QPointer m_viewer; }; From 7ebd6514cb9531193440df188a865c036431ad69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 15:59:02 +0100 Subject: [PATCH 147/290] (#675) (#666) Extrapolating intersection by user amount, along well-end directions Making vertical-only well paths more robust also. --- .../ProjectDataModel/RimCrossSection.cpp | 107 ++++++++++++++---- .../ProjectDataModel/RimCrossSection.h | 12 +- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 2f112541fd..2e80cab7fb 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -67,12 +67,13 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitField(&isActive, "Active", true, "Active", "", "", ""); isActive.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&type, "Type", "Type", "", "", ""); - CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); - CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); - CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); - CAF_PDM_InitField (&branchIndex, "Branch", -1, "Branch", "", "", ""); - + CAF_PDM_InitFieldNoDefault(&type, "Type", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); + CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); + CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); + CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); + CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); + uiCapability()->setUiChildrenHidden(true); } @@ -86,7 +87,8 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, changedField == &direction || changedField == &wellPath || changedField == &simulationWell || - changedField == &branchIndex) + changedField == &m_branchIndex || + changedField == &m_extentLength) { m_crossSectionPartMgr = NULL; @@ -104,7 +106,15 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, { m_wellBranchCenterlines.clear(); updateWellCenterline(); - branchIndex = -1; + if (m_wellBranchCenterlines.size()) + { + cvf::Vec3d wellLength = m_wellBranchCenterlines[0].front() - m_wellBranchCenterlines[0].back(); + if (wellLength.length() < 200) + { + + } + } + m_branchIndex = -1; } } @@ -120,6 +130,7 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& if (type == CS_WELL_PATH) { uiOrdering.add(&wellPath); + uiOrdering.add(&m_extentLength); } else if (type == CS_SIMULATION_WELL) { @@ -127,14 +138,16 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& updateWellCenterline(); if (simulationWell() && m_wellBranchCenterlines.size() > 1) { - uiOrdering.add(&branchIndex); + uiOrdering.add(&m_branchIndex); } + uiOrdering.add(&m_extentLength); } else { // User defined poly line } + uiOrdering.setForgetRemainingFields(true); } @@ -184,7 +197,7 @@ QList RimCrossSection::calculateValueOptions(const caf:: options.push_front(caf::PdmOptionItemInfo("None", QVariant::fromValue(caf::PdmPointer(NULL)))); } } - else if (fieldNeedingOptions == &branchIndex) + else if (fieldNeedingOptions == &m_branchIndex) { updateWellCenterline(); @@ -251,12 +264,12 @@ std::vector< std::vector > RimCrossSection::polyLines() const { updateWellCenterline(); - if (0 <= branchIndex && branchIndex < m_wellBranchCenterlines.size()) + if (0 <= m_branchIndex && m_branchIndex < m_wellBranchCenterlines.size()) { - lines.push_back(m_wellBranchCenterlines[branchIndex]); + lines.push_back(m_wellBranchCenterlines[m_branchIndex]); } - if (branchIndex == -1) + if (m_branchIndex == -1) { lines = m_wellBranchCenterlines; } @@ -271,14 +284,10 @@ std::vector< std::vector > RimCrossSection::polyLines() const { for (int lIdx = 0; lIdx < lines.size(); ++lIdx) { - cvf::Vec3d startToEnd = (lines[lIdx].back() - lines[lIdx].front()); - startToEnd[2] = 0.0; - - cvf::Vec3d newStart = lines[lIdx].front() - startToEnd * 0.1; - cvf::Vec3d newEnd = lines[lIdx].back() + startToEnd * 0.1; + std::vector& polyLine = lines[lIdx]; + addExtents(polyLine); + - lines[lIdx].insert(lines[lIdx].begin(), newStart); - lines[lIdx].push_back(newEnd); } } @@ -315,3 +324,61 @@ void RimCrossSection::updateWellCenterline() const } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::addExtents(std::vector &polyLine) const +{ + size_t lineVxCount = polyLine.size(); + + if (lineVxCount == 0) return; + + // Add extent at end of well + { + size_t endIdxOffset = lineVxCount > 3 ? 3: lineVxCount; + cvf::Vec3d endDirection = (polyLine[lineVxCount-1] - polyLine[lineVxCount-endIdxOffset]); + endDirection[2] = 0; // Remove z. make extent lenght be horizontally + if (endDirection.length() < 1e-2) + { + endDirection = polyLine.back() - polyLine.front(); + endDirection[2] = 0; + + if (endDirection.length() < 1e-2) + { + endDirection = cvf::Vec3d::X_AXIS; + } + } + + endDirection.normalize(); + + cvf::Vec3d newEnd = polyLine.back() + endDirection * m_extentLength(); + + polyLine.push_back(newEnd); + } + + // Add extent at start + { + size_t endIdxOffset = lineVxCount > 3 ? 3: lineVxCount-1; + cvf::Vec3d startDirection = (polyLine[0] - polyLine[endIdxOffset]); + startDirection[2] = 0; // Remove z. make extent lenght be horizontally + if (startDirection.length() < 1e-2) + { + startDirection = polyLine.front() - polyLine.back(); + startDirection[2] = 0; + + if (startDirection.length() < 1e-2) + { + startDirection = -cvf::Vec3d::X_AXIS; + } + } + + startDirection.normalize(); + + cvf::Vec3d newStart = polyLine.front() + startDirection * m_extentLength(); + + polyLine.insert(polyLine.begin(), newStart); + } + + +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index d43dad5b4a..180aab4106 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -67,22 +67,28 @@ class RimCrossSection : public caf::PdmObject caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; - caf::PdmField branchIndex; + + std::vector< std::vector > polyLines() const; - virtual caf::PdmFieldHandle* userDescriptionField(); - virtual caf::PdmFieldHandle* objectToggleField(); + void addExtents(std::vector &polyLine) const; RivCrossSectionPartMgr* crossSectionPartMgr(); protected: + virtual caf::PdmFieldHandle* userDescriptionField(); + virtual caf::PdmFieldHandle* objectToggleField(); + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); private: + caf::PdmField m_branchIndex; + caf::PdmField m_extentLength; + RimEclipseWellCollection* simulationWellCollection(); void updateWellCenterline() const; From c86bb47fa9299c4dc1c3798ef2b21471d380c842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 16:11:32 +0100 Subject: [PATCH 148/290] (#666) Fixed assert reported in comment --- ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index e46e2f6f74..1915494eed 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -78,13 +78,15 @@ void RivCrossSectionPartMgr::applySingleColorEffect() //-------------------------------------------------------------------------------------------------- void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) { + if (m_crossSectionGenerator.isNull()) return; + RimEclipseView* eclipseView; m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); + if (eclipseView) { RimEclipseCellColors* cellResultColors = eclipseView->cellResult(); - if (m_crossSectionGenerator.isNull()) return; CVF_ASSERT(cellResultColors); From 2bf6771da0972e9da9a2383da66072d9277a8b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 26 Nov 2015 16:47:45 +0100 Subject: [PATCH 149/290] (#675) Addjusted default extent when we have a small reservoir. --- .../ProjectDataModel/RimCrossSection.cpp | 28 +++++++++++++------ .../ProjectDataModel/RimCrossSection.h | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 2e80cab7fb..25e355dc81 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -30,6 +30,7 @@ #include "RivCrossSectionPartMgr.h" #include "RigSimulationWellCenterLineCalculator.h" +#include "RimCase.h" namespace caf { @@ -106,14 +107,6 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, { m_wellBranchCenterlines.clear(); updateWellCenterline(); - if (m_wellBranchCenterlines.size()) - { - cvf::Vec3d wellLength = m_wellBranchCenterlines[0].front() - m_wellBranchCenterlines[0].back(); - if (wellLength.length() < 200) - { - - } - } m_branchIndex = -1; } } @@ -147,6 +140,7 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& // User defined poly line } + updateWellExtentDefaultValue(); uiOrdering.setForgetRemainingFields(true); } @@ -382,3 +376,21 @@ void RimCrossSection::addExtents(std::vector &polyLine) const } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::updateWellExtentDefaultValue() +{ + RimCase* ownerCase = NULL; + firstAnchestorOrThisOfType(ownerCase); + + if (ownerCase) + { + cvf::BoundingBox caseBB = ownerCase->activeCellsBoundingBox(); + if (m_extentLength == m_extentLength.defaultValue() && caseBB.radius() < 1000) + { + m_extentLength = caseBB.radius() * 0.1; + } + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 180aab4106..f9e263a829 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -91,6 +91,7 @@ class RimCrossSection : public caf::PdmObject RimEclipseWellCollection* simulationWellCollection(); void updateWellCenterline() const; + void updateWellExtentDefaultValue(); private: cvf::ref m_crossSectionPartMgr; From eb4fefce7cb5a34e4626e420d56518e3ecbbe119 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 26 Nov 2015 18:42:07 +0100 Subject: [PATCH 150/290] Removed obsolete file --- Fwk/AppFwk/CMakeLists.txt | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 Fwk/AppFwk/CMakeLists.txt diff --git a/Fwk/AppFwk/CMakeLists.txt b/Fwk/AppFwk/CMakeLists.txt deleted file mode 100644 index 4aaad1afe9..0000000000 --- a/Fwk/AppFwk/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required (VERSION 2.8) - -project (CeeApp) - - -find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) -include (${QT_USE_FILE}) - - -#libraries -add_subdirectory (cafProjectDataModel/cafPdmCore) -add_subdirectory (cafProjectDataModel/cafPdmUiCore) -add_subdirectory (cafProjectDataModel/cafPdmXml) - -add_subdirectory(cafProjectDataModel) -add_subdirectory(cafCommand) -add_subdirectory(cafUserInterface) - -#executables -add_subdirectory(cafTests/cafProjectDataModel_UnitTests) -add_subdirectory(cafTests/cafTestApplication) - -add_subdirectory (cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests) -add_subdirectory (cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) - -# Organize sub-projects into folders on Visual Studio -# Turn on using solution folders -set_property(GLOBAL PROPERTY USE_FOLDERS ON) - -set_property(TARGET cafPdmCore cafPdmCore_UnitTests cafPdmXml cafPdmXml_UnitTests cafPdmUiCore PROPERTY FOLDER "PdmCore") - From 5c0c18ca30a8e1d49556569f9024608fd11a53c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 10:13:29 +0100 Subject: [PATCH 151/290] (#668) Autmatically change itersection name when changing well or branch --- .../ProjectDataModel/RimCrossSection.cpp | 29 ++++++++++ .../ProjectDataModel/RimCrossSection.h | 58 +++++++++---------- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 25e355dc81..e82c90fae0 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -109,6 +109,15 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateWellCenterline(); m_branchIndex = -1; } + + + if (changedField == &simulationWell + || changedField == &wellPath + || changedField == &m_branchIndex) + { + updateName(); + } + } //-------------------------------------------------------------------------------------------------- @@ -394,3 +403,23 @@ void RimCrossSection::updateWellExtentDefaultValue() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::updateName() +{ + if (type == CS_SIMULATION_WELL && simulationWell()) + { + name = simulationWell()->name(); + if (m_branchIndex() != -1) + { + name = name() + " Branch " + QString::number(m_branchIndex() + 1); + } + } + else if (type() == CS_WELL_PATH && wellPath()) + { + name = wellPath()->name(); + } + +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index f9e263a829..4d8ccb326f 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -59,41 +59,39 @@ class RimCrossSection : public caf::PdmObject public: RimCrossSection(); - caf::PdmField name; - caf::PdmField isActive; + caf::PdmField name; + caf::PdmField isActive; caf::PdmField< caf::AppEnum< CrossSectionEnum > > type; caf::PdmField< caf::AppEnum< CrossSectionDirEnum > > direction; - caf::PdmPtrField wellPath; - caf::PdmPtrField simulationWell; + caf::PdmPtrField wellPath; + caf::PdmPtrField simulationWell; - - - std::vector< std::vector > polyLines() const; - - void addExtents(std::vector &polyLine) const; - - RivCrossSectionPartMgr* crossSectionPartMgr(); + std::vector< std::vector > polyLines() const; + RivCrossSectionPartMgr* crossSectionPartMgr(); protected: - virtual caf::PdmFieldHandle* userDescriptionField(); - virtual caf::PdmFieldHandle* objectToggleField(); - - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); - - virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); - -private: - caf::PdmField m_branchIndex; - caf::PdmField m_extentLength; - - RimEclipseWellCollection* simulationWellCollection(); - void updateWellCenterline() const; - void updateWellExtentDefaultValue(); - -private: - cvf::ref m_crossSectionPartMgr; - mutable std::vector< std::vector > m_wellBranchCenterlines; + virtual caf::PdmFieldHandle* userDescriptionField(); + virtual caf::PdmFieldHandle* objectToggleField(); + + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); + + virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); + +private: + caf::PdmField m_branchIndex; + caf::PdmField m_extentLength; + + RimEclipseWellCollection* simulationWellCollection(); + void updateWellCenterline() const; + void updateWellExtentDefaultValue(); + void addExtents(std::vector &polyLine) const; + void updateName(); +private: + cvf::ref m_crossSectionPartMgr; + + mutable + std::vector< std::vector > m_wellBranchCenterlines; }; From 563aa95abf87377959850ac604f54765b8d458e8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 07:57:35 +0100 Subject: [PATCH 152/290] [Fwk] Static initializer must be placed at file global scope in order to always call the constructor in the cpp file --- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h | 19 ++++++++++------- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h | 24 ++++++++++++---------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h index daa6d4de62..549ab34133 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h @@ -45,11 +45,6 @@ #include "cafPdmCoreColor3f.h" -class Color3fDummy -{ -public: - Color3fDummy(); -}; namespace caf { @@ -61,8 +56,6 @@ class PdmUiFieldSpecialization < cvf::Color3f > /// Convert the field value into a QVariant static QVariant convert(const cvf::Color3f& value) { - static Color3fDummy dummy; - return PdmValueFieldSpecialization< cvf::Color3f >::convert(value); } @@ -92,3 +85,15 @@ class PdmUiFieldSpecialization < cvf::Color3f > } // end namespace caf + +//-------------------------------------------------------------------------------------------------- +// If the macro for registering the editor is put as the single statement +// in a cpp file, a dummy static class must be used to make sure the compile unit +// is included +//-------------------------------------------------------------------------------------------------- +class Color3fDummy +{ +public: + Color3fDummy(); +}; +static Color3fDummy cafPdmColor3fDummy; diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h index df7eb2bd1c..25f9c37b81 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h @@ -46,13 +46,6 @@ #include "cvfVector3.h" -class Vec3dDummy -{ -public: - Vec3dDummy(); -}; - - namespace caf { @@ -63,12 +56,9 @@ class PdmUiFieldSpecialization < cvf::Vec3d > /// Convert the field value into a QVariant static QVariant convert(const cvf::Vec3d& value) { - static Vec3dDummy dummy; - return PdmValueFieldSpecialization< cvf::Vec3d >::convert(value); } - /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, cvf::Vec3d& value) { @@ -89,8 +79,20 @@ class PdmUiFieldSpecialization < cvf::Vec3d > /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmDataValueField< cvf::Vec3d >&, std::vector*) { } - }; } // end namespace caf + + +//-------------------------------------------------------------------------------------------------- +// If the macro for registering the editor is put as the single statement +// in a cpp file, a dummy static class must be used to make sure the compile unit +// is included +//-------------------------------------------------------------------------------------------------- +class Vec3dDummy +{ +public: + Vec3dDummy(); +}; +static Vec3dDummy cafPdmVec3dDummy; From bf5de931139ca3c42acba0bc9e659c9a1f2cf858 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 10:01:17 +0100 Subject: [PATCH 153/290] [Fwk] Improved static initializer naming --- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp | 2 +- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h | 6 +++--- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp | 3 +-- Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.h | 6 +++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp index cedd8caabe..28d7a8d78e 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.cpp @@ -47,7 +47,7 @@ CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(caf::PdmUiColorEditor, cvf::Color3f); // in a cpp file, a dummy static class must be used to make sure the compile unit // is included //-------------------------------------------------------------------------------------------------- -Color3fDummy::Color3fDummy() +PdmColor3fInitializer::PdmColor3fInitializer() { } diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h index 549ab34133..801b2b4d0f 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreColor3f.h @@ -91,9 +91,9 @@ class PdmUiFieldSpecialization < cvf::Color3f > // in a cpp file, a dummy static class must be used to make sure the compile unit // is included //-------------------------------------------------------------------------------------------------- -class Color3fDummy +class PdmColor3fInitializer { public: - Color3fDummy(); + PdmColor3fInitializer(); }; -static Color3fDummy cafPdmColor3fDummy; +static PdmColor3fInitializer pdmColor3fInitializer; diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp index 0df470f53d..308804ff50 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmUiCoreVec3d.cpp @@ -49,7 +49,6 @@ CAF_PDM_UI_REGISTER_DEFAULT_FIELD_EDITOR(caf::PdmUiListEditor, std::vector // in a cpp file, a dummy static class must be used to make sure the compile unit // is included //-------------------------------------------------------------------------------------------------- -class Vec3dDummy +class PdmVec3dInitializer { public: - Vec3dDummy(); + PdmVec3dInitializer(); }; -static Vec3dDummy cafPdmVec3dDummy; +static PdmVec3dInitializer pdmVec3dInitializer; From cbdf446716da65bd91fad9bd300e80e8f243fd80 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 10:37:51 +0100 Subject: [PATCH 154/290] (#670) Grid box: Do not use scientific notation on legend --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 905f06be32..0b9fc15c5a 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -570,7 +570,11 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection { legendValue = -domainCoordsTickValues->at(idx); } - geo->addText(cvf::String(legendValue), vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); + + cvf::int64 integerValue = static_cast(legendValue); + cvf::String numberText = cvf::String("%1").arg(integerValue); + + geo->addText(numberText, vertices->get(idx*2 + 1) + (0.5f * tickLength) * tickMarkDir); } cvf::ref part = new cvf::Part; From f8d3b850475c70c2a69e3314e4d6f7f7a1f87320 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 10:47:12 +0100 Subject: [PATCH 155/290] (#669) Grid Box: When creating a new view, enable grid box by default --- ApplicationCode/ProjectDataModel/RimView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 75fbe324ab..14b5e4f081 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -101,7 +101,7 @@ RimView::RimView(void) CAF_PDM_InitField(&meshMode, "MeshMode", defaultMeshType, "Grid lines", "", "", ""); CAF_PDM_InitFieldNoDefault(&surfaceMode, "SurfaceMode", "Grid surface", "", "", ""); - CAF_PDM_InitField(&showGridBox, "ShowGridBox", false, "Show Grid Box", "", "", ""); + CAF_PDM_InitField(&showGridBox, "ShowGridBox", true, "Show Grid Box", "", "", ""); CAF_PDM_InitField(&m_disableLighting, "DisableLighting", false, "Disable Results Lighting", "", "Disable light model for scalar result colors", ""); From 9fff7825afc3c06694518728fd2d5ca881f99a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 11:27:06 +0100 Subject: [PATCH 156/290] (#676) Start intersections of well paths when the trajectory enters the active cells bounding box. --- .../ProjectDataModel/RimCrossSection.cpp | 49 ++++++++++++++++++- .../ProjectDataModel/RimCrossSection.h | 1 + 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index e82c90fae0..56dcb132c7 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -259,6 +259,7 @@ std::vector< std::vector > RimCrossSection::polyLines() const if (wellPath()) { lines.push_back(wellPath->wellPathGeometry()->m_wellPathPoints); + clipToReservoir(lines[0]); } } else if (type == CS_SIMULATION_WELL) @@ -289,8 +290,6 @@ std::vector< std::vector > RimCrossSection::polyLines() const { std::vector& polyLine = lines[lIdx]; addExtents(polyLine); - - } } @@ -423,3 +422,49 @@ void RimCrossSection::updateName() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::clipToReservoir(std::vector &polyLine) const +{ + RimCase* ownerCase = NULL; + firstAnchestorOrThisOfType(ownerCase); + + std::vector clippedPolyLine; + + if (ownerCase) + { + cvf::BoundingBox caseBB = ownerCase->activeCellsBoundingBox(); + bool hasEnteredReservoirBB = false; + for (size_t vxIdx = 0 ; vxIdx < polyLine.size(); ++vxIdx) + { + if (!caseBB.contains(polyLine[vxIdx])) + { + continue; + } + + if (!hasEnteredReservoirBB) + { + if (vxIdx > 0) + { + // clip line, and add vx to start + cvf::Plane topPlane; + topPlane.setFromPointAndNormal(caseBB.max(), cvf::Vec3d::Z_AXIS); + cvf::Vec3d intersection; + + if (topPlane.intersect(polyLine[vxIdx-1], polyLine[vxIdx], &intersection)) + { + clippedPolyLine.push_back(intersection); + } + } + + hasEnteredReservoirBB = true; + } + + clippedPolyLine.push_back(polyLine[vxIdx]); + } + } + + polyLine.swap(clippedPolyLine); +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 4d8ccb326f..01db56fa44 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -88,6 +88,7 @@ class RimCrossSection : public caf::PdmObject void updateWellCenterline() const; void updateWellExtentDefaultValue(); void addExtents(std::vector &polyLine) const; + void clipToReservoir(std::vector &polyLine) const; void updateName(); private: cvf::ref m_crossSectionPartMgr; From 09c88fb768a627dc484c7f336e39bff423ba6134 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 11:23:10 +0100 Subject: [PATCH 157/290] (#667) Intersection visibility will now follow fault visibility --- .../ModelVisualization/RivCrossSectionPartMgr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 1915494eed..dab62ffa4e 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -302,7 +302,7 @@ void RivCrossSectionPartMgr::generatePartGeometry() } cvf::ref part = new cvf::Part; - part->setName("Cross Section "); + part->setName("Cross Section"); part->setDrawable(geo.p()); // Set mapping from triangle face index to cell index @@ -310,7 +310,7 @@ void RivCrossSectionPartMgr::generatePartGeometry() part->setSourceInfo(si.p()); part->updateBoundingBox(); - part->setEnableMask(surfaceBit); + part->setEnableMask(faultBit); part->setPriority(priCrossSectionGeo); m_crossSectionFaces = part; @@ -328,11 +328,11 @@ void RivCrossSectionPartMgr::generatePartGeometry() } cvf::ref part = new cvf::Part; - part->setName("Cross Section mesh" ); + part->setName("Cross Section mesh"); part->setDrawable(geoMesh.p()); part->updateBoundingBox(); - part->setEnableMask(meshSurfaceBit); + part->setEnableMask(meshFaultBit); part->setPriority(priMesh); m_crossSectionGridLines = part; From a42b0d2c8e6bd808ca61883b5540dbb80c72fa2e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 12:17:50 +0100 Subject: [PATCH 158/290] (#667) Added Grids to project tree below Info Box Fixed update issue related to missing time step texts in animation toolbar --- .../ProjectDataModel/CMakeLists_files.cmake | 2 + .../ProjectDataModel/RimEclipseView.cpp | 1 + .../ProjectDataModel/RimGeoMechView.cpp | 1 + .../ProjectDataModel/RimGridCollection.cpp | 76 +++++++++++++++++++ .../ProjectDataModel/RimGridCollection.h | 45 +++++++++++ ApplicationCode/ProjectDataModel/RimView.cpp | 8 ++ ApplicationCode/ProjectDataModel/RimView.h | 10 ++- 7 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 ApplicationCode/ProjectDataModel/RimGridCollection.cpp create mode 100644 ApplicationCode/ProjectDataModel/RimGridCollection.h diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index c276e011c4..9e8067c291 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -75,6 +75,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.h ${CEE_CURRENT_LIST_DIR}RimCrossSection.h ${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.h ${CEE_CURRENT_LIST_DIR}RimContextCommandBuilder.h +${CEE_CURRENT_LIST_DIR}RimGridCollection.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -148,6 +149,7 @@ ${CEE_CURRENT_LIST_DIR}RimWellLogFileCurve.cpp ${CEE_CURRENT_LIST_DIR}RimCrossSection.cpp ${CEE_CURRENT_LIST_DIR}RimCrossSectionCollection.cpp ${CEE_CURRENT_LIST_DIR}RimContextCommandBuilder.cpp +${CEE_CURRENT_LIST_DIR}RimGridCollection.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index a425773b06..fffbd6bb8a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1299,6 +1299,7 @@ void RimEclipseView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { uiTreeOrdering.add(m_overlayInfoConfig()); + uiTreeOrdering.add(m_gridCollection()); uiTreeOrdering.add(cellResult()); uiTreeOrdering.add(cellEdgeResult()); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 6616625e1f..45da1665c3 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -650,6 +650,7 @@ void RimGeoMechView::axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::S void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { uiTreeOrdering.add(m_overlayInfoConfig()); + uiTreeOrdering.add(m_gridCollection()); uiTreeOrdering.add(cellResult()); diff --git a/ApplicationCode/ProjectDataModel/RimGridCollection.cpp b/ApplicationCode/ProjectDataModel/RimGridCollection.cpp new file mode 100644 index 0000000000..3bdc0a67e6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGridCollection.cpp @@ -0,0 +1,76 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimGridCollection.h" +#include "RimView.h" + + +CAF_PDM_SOURCE_INIT(RimGridCollection, "GridCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCollection::RimGridCollection() +{ + CAF_PDM_InitObject("Grids", ":/draw_style_faults_24x24.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Show grid cells", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCollection::~RimGridCollection() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimGridCollection::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + CVF_ASSERT(rimView); + + rimView->setShowFaultsOnly(!m_isActive); + + updateUiIconFromState(m_isActive); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCollection::initAfterRead() +{ + updateUiIconFromState(m_isActive); +} diff --git a/ApplicationCode/ProjectDataModel/RimGridCollection.h b/ApplicationCode/ProjectDataModel/RimGridCollection.h new file mode 100644 index 0000000000..cd2bd6696f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGridCollection.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmField.h" +#include "cafPdmObject.h" + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimGridCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimGridCollection(); + virtual ~RimGridCollection(); + + virtual caf::PdmFieldHandle* objectToggleField(); + +protected: + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + virtual void initAfterRead(); + +private: + caf::PdmField m_isActive; +}; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 14b5e4f081..2b5aa401b3 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -10,6 +10,7 @@ #include "RimCrossSectionCollection.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" +#include "RimGridCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimPropertyFilterCollection.h" @@ -121,6 +122,10 @@ RimView::RimView(void) crossSectionCollection.uiCapability()->setUiHidden(true); crossSectionCollection = new RimCrossSectionCollection(); + CAF_PDM_InitFieldNoDefault(&m_gridCollection, "GridCollection", "GridCollection", "", "", ""); + m_gridCollection.uiCapability()->setUiHidden(true); + m_gridCollection = new RimGridCollection(); + m_previousGridModeMeshLinesWasFaults = false; m_crossSectionVizModel = new cvf::ModelBasicList; @@ -478,6 +483,7 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV createDisplayModel(); updateDisplayModelVisibility(); RiuMainWindow::instance()->refreshDrawStyleActions(); + RiuMainWindow::instance()->refreshAnimationActions(); } else if (changedField == &scaleZ) { @@ -524,6 +530,7 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV createDisplayModel(); updateDisplayModelVisibility(); RiuMainWindow::instance()->refreshDrawStyleActions(); + RiuMainWindow::instance()->refreshAnimationActions(); } else if (changedField == &showGridBox) { @@ -533,6 +540,7 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV { createDisplayModel(); RiuMainWindow::instance()->refreshDrawStyleActions(); + RiuMainWindow::instance()->refreshAnimationActions(); } else if (changedField == &name) { diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index d82ded7848..f3a5abc104 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -40,11 +40,11 @@ class Rim3dOverlayInfoConfig; class RimCase; class RimCellRangeFilter; class RimCellRangeFilterCollection; -class RiuViewer; -class RimViewLinker; -class RimViewController; -class RimPropertyFilterCollection; class RimCrossSectionCollection; +class RimPropertyFilterCollection; +class RimViewController; +class RimViewLinker; +class RiuViewer; namespace cvf { @@ -194,6 +194,8 @@ class RimView : public caf::PdmObject caf::PdmChildField m_rangeFilterCollection; caf::PdmChildField m_overrideRangeFilterCollection; + caf::PdmChildField m_gridCollection; + // Overridden PDM methods: virtual void setupBeforeSave(); From f33a3174ee7a959d16a026774b781a3499b133c8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 13:45:02 +0100 Subject: [PATCH 159/290] (#667) Make Grids toggle follow toggle button in toolbar Renamed toolbar text to "Hide Grid Cells" --- .../ProjectDataModel/RimEclipseView.cpp | 1 + .../ProjectDataModel/RimGeoMechView.cpp | 1 + .../ProjectDataModel/RimGridCollection.cpp | 14 +++++++------- .../ProjectDataModel/RimGridCollection.h | 4 ++-- ApplicationCode/ProjectDataModel/RimView.cpp | 8 ++++++-- ApplicationCode/ProjectDataModel/RimView.h | 5 +++-- ApplicationCode/UserInterface/RiuMainWindow.cpp | 8 ++++---- ApplicationCode/UserInterface/RiuMainWindow.h | 2 +- 8 files changed, 25 insertions(+), 18 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index fffbd6bb8a..6d890ddf8c 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -40,6 +40,7 @@ #include "RimEclipseWell.h" #include "RimEclipseWellCollection.h" #include "RimFaultCollection.h" +#include "RimGridCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimTernaryLegendConfig.h" diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 45da1665c3..c2240a4227 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -34,6 +34,7 @@ #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechPropertyFilterCollection.h" +#include "RimGridCollection.h" #include "RimLegendConfig.h" #include "RimViewLinker.h" diff --git a/ApplicationCode/ProjectDataModel/RimGridCollection.cpp b/ApplicationCode/ProjectDataModel/RimGridCollection.cpp index 3bdc0a67e6..59e5738bcb 100644 --- a/ApplicationCode/ProjectDataModel/RimGridCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimGridCollection.cpp @@ -30,8 +30,8 @@ RimGridCollection::RimGridCollection() { CAF_PDM_InitObject("Grids", ":/draw_style_faults_24x24.png", "", ""); - CAF_PDM_InitField(&m_isActive, "IsActive", true, "Show grid cells", "", "", ""); - m_isActive.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&isActive, "IsActive", true, "Show grid cells", "", "", ""); + isActive.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -47,7 +47,7 @@ RimGridCollection::~RimGridCollection() //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* RimGridCollection::objectToggleField() { - return &m_isActive; + return &isActive; } //-------------------------------------------------------------------------------------------------- @@ -55,15 +55,15 @@ caf::PdmFieldHandle* RimGridCollection::objectToggleField() //-------------------------------------------------------------------------------------------------- void RimGridCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { - if (changedField == &m_isActive) + if (changedField == &isActive) { RimView* rimView = NULL; this->firstAnchestorOrThisOfType(rimView); CVF_ASSERT(rimView); - rimView->setShowFaultsOnly(!m_isActive); + rimView->showGridCells(isActive); - updateUiIconFromState(m_isActive); + updateUiIconFromState(isActive); } } @@ -72,5 +72,5 @@ void RimGridCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField //-------------------------------------------------------------------------------------------------- void RimGridCollection::initAfterRead() { - updateUiIconFromState(m_isActive); + updateUiIconFromState(isActive); } diff --git a/ApplicationCode/ProjectDataModel/RimGridCollection.h b/ApplicationCode/ProjectDataModel/RimGridCollection.h index cd2bd6696f..4f04b0565e 100644 --- a/ApplicationCode/ProjectDataModel/RimGridCollection.h +++ b/ApplicationCode/ProjectDataModel/RimGridCollection.h @@ -36,10 +36,10 @@ class RimGridCollection : public caf::PdmObject virtual caf::PdmFieldHandle* objectToggleField(); + caf::PdmField isActive; + protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void initAfterRead(); -private: - caf::PdmField m_isActive; }; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 2b5aa401b3..02ba600a1e 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -432,9 +432,9 @@ void RimView::setSurfOnlyDrawstyle() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimView::setShowFaultsOnly(bool showFaults) +void RimView::showGridCells(bool enableGridCells) { - if (showFaults) + if (!enableGridCells) { m_previousGridModeMeshLinesWasFaults = meshMode() == FAULTS_MESH; if (surfaceMode() != NO_SURFACE) surfaceMode.uiCapability()->setValueFromUi(FAULTS); @@ -445,6 +445,10 @@ void RimView::setShowFaultsOnly(bool showFaults) if (surfaceMode() != NO_SURFACE) surfaceMode.uiCapability()->setValueFromUi(SURFACE); if (meshMode() != NO_MESH) meshMode.uiCapability()->setValueFromUi(m_previousGridModeMeshLinesWasFaults ? FAULTS_MESH : FULL_MESH); } + + m_gridCollection->isActive = enableGridCells; + m_gridCollection->updateConnectedEditors(); + m_gridCollection->updateUiIconFromState(enableGridCells); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index f3a5abc104..124f20ce75 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -39,6 +39,7 @@ class Rim3dOverlayInfoConfig; class RimCase; class RimCellRangeFilter; +class RimGridCollection; class RimCellRangeFilterCollection; class RimCrossSectionCollection; class RimPropertyFilterCollection; @@ -121,7 +122,7 @@ class RimView : public caf::PdmObject void disableLighting(bool disable); bool isLightingDisabled() const; - void setShowFaultsOnly(bool showFaults); + void showGridCells(bool enableHideGridCells); bool isGridVisualizationMode() const; void setScaleZAndUpdate(double scaleZ); @@ -194,7 +195,7 @@ class RimView : public caf::PdmObject caf::PdmChildField m_rangeFilterCollection; caf::PdmChildField m_overrideRangeFilterCollection; - caf::PdmChildField m_gridCollection; + caf::PdmChildField m_gridCollection; // Overridden PDM methods: virtual void setupBeforeSave(); diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index a2d81f6e74..8b5fff3588 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -350,9 +350,9 @@ void RiuMainWindow::createActions() connect(m_disableLightingAction, SIGNAL(toggled(bool)), SLOT(slotDisableLightingAction(bool))); - m_drawStyleToggleFaultsAction = new QAction( QIcon(":/draw_style_faults_24x24.png"), "&Show Faults Only", this); + m_drawStyleToggleFaultsAction = new QAction( QIcon(":/draw_style_faults_24x24.png"), "&Hide Grid Cells", this); m_drawStyleToggleFaultsAction->setCheckable(true); - connect(m_drawStyleToggleFaultsAction, SIGNAL(toggled(bool)), SLOT(slotToggleFaultsAction(bool))); + connect(m_drawStyleToggleFaultsAction, SIGNAL(toggled(bool)), SLOT(slotToggleHideGridCellsAction(bool))); m_toggleFaultsLabelAction = new QAction( QIcon(":/draw_style_faults_label_24x24.png"), "&Show Fault Labels", this); m_toggleFaultsLabelAction->setCheckable(true); @@ -1861,11 +1861,11 @@ void RiuMainWindow::slotDrawStyleChanged(QAction* activatedAction) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuMainWindow::slotToggleFaultsAction(bool showFaults) +void RiuMainWindow::slotToggleHideGridCellsAction(bool hideGridCells) { if (!RiaApplication::instance()->activeReservoirView()) return; - RiaApplication::instance()->activeReservoirView()->setShowFaultsOnly(showFaults); + RiaApplication::instance()->activeReservoirView()->showGridCells(!hideGridCells); } diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index 88d034a6ca..8196034384 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -240,7 +240,7 @@ private slots: void slotScaleChanged(int scaleValue); void slotDrawStyleChanged(QAction* activatedAction); - void slotToggleFaultsAction(bool); + void slotToggleHideGridCellsAction(bool); void slotToggleFaultLabelsAction(bool); void slotDisableLightingAction(bool); From 39ae89b07beb78db4f743f719b66cd483105d9ac Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 13:46:41 +0100 Subject: [PATCH 160/290] (#667) Move intersections above range filters in tree view --- ApplicationCode/ProjectDataModel/RimEclipseView.cpp | 2 +- ApplicationCode/ProjectDataModel/RimGeoMechView.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 6d890ddf8c..e6a3108a2f 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1308,10 +1308,10 @@ void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(wellCollection()); uiTreeOrdering.add(faultCollection()); + uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); - uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index c2240a4227..2b7e2ec571 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -654,10 +654,11 @@ void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_gridCollection()); uiTreeOrdering.add(cellResult()); + + uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); - uiTreeOrdering.add(crossSectionCollection()); uiTreeOrdering.setForgetRemainingFields(true); } From 9f0c9d13b9bfeee4df79f93a3d690a3655d2ed4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 13:32:12 +0100 Subject: [PATCH 161/290] Whitespace --- ApplicationCode/ReservoirDataModel/RigCaseData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ReservoirDataModel/RigCaseData.h b/ApplicationCode/ReservoirDataModel/RigCaseData.h index 220bd5f9a0..7ab31b2be4 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseData.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseData.h @@ -56,7 +56,7 @@ class RigCaseData : public cvf::Object RigGridBase* grid(size_t index); size_t gridCount() const; - RigCaseCellResultsData* results(RifReaderInterface::PorosityModelResultType porosityModel); + RigCaseCellResultsData* results(RifReaderInterface::PorosityModelResultType porosityModel); const RigCaseCellResultsData* results(RifReaderInterface::PorosityModelResultType porosityModel) const; RigActiveCellInfo* activeCellInfo(RifReaderInterface::PorosityModelResultType porosityModel); From 0bda8e9a2fc49251afa1d04b4cc6e84041619be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 13:35:17 +0100 Subject: [PATCH 162/290] (#679) Inactive cells can be toggled from the intersection --- .../RivCrossSectionGeometryGenerator.cpp | 14 +++++++++++--- .../RivCrossSectionGeometryGenerator.h | 7 +++++-- .../ModelVisualization/RivCrossSectionPartMgr.cpp | 2 +- .../ProjectDataModel/RimCrossSection.cpp | 7 ++++++- ApplicationCode/ProjectDataModel/RimCrossSection.h | 1 + 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 5fa806c61d..b015b8e92d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1201,11 +1201,17 @@ const RimCrossSection* RivCrossSectionGeometryGenerator::crossSection() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- +#include "RigActiveCellInfo.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivEclipseCrossSectionGrid::RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid) : m_mainGrid(mainGrid) +RivEclipseCrossSectionGrid::RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid, + const RigActiveCellInfo* activeCellInfo, + bool showInactiveCells) + : m_mainGrid(mainGrid), + m_activeCellInfo(activeCellInfo), + m_showInactiveCells(showInactiveCells) { } @@ -1240,8 +1246,10 @@ void RivEclipseCrossSectionGrid::findIntersectingCells(const cvf::BoundingBox& i bool RivEclipseCrossSectionGrid::useCell(size_t cellIndex) const { const RigCell& cell = m_mainGrid->globalCellArray()[cellIndex]; - - return !(cell.isInvalid() || (cell.subGrid() != NULL)); + if (m_showInactiveCells) + return !(cell.isInvalid() || (cell.subGrid() != NULL)); + else + return m_activeCellInfo->isActive(cellIndex) && (cell.subGrid() == NULL); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 77e6526460..fab8524f6c 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -30,6 +30,7 @@ #include class RigMainGrid; +class RigActiveCellInfo; class RigResultAccessor; class RimCrossSection; @@ -56,7 +57,7 @@ class RivCrossSectionHexGridIntf : public cvf::Object class RivEclipseCrossSectionGrid : public RivCrossSectionHexGridIntf { public: - RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid); + RivEclipseCrossSectionGrid(const RigMainGrid * mainGrid, const RigActiveCellInfo* activeCellInfo, bool showInactiveCells); virtual cvf::Vec3d displayOffset() const; virtual cvf::BoundingBox boundingBox() const; @@ -66,7 +67,9 @@ class RivEclipseCrossSectionGrid : public RivCrossSectionHexGridIntf virtual void cellCornerIndices(size_t cellIndex, size_t cornerIndices[8]) const; private: - cvf::cref m_mainGrid; + cvf::cref m_mainGrid; + cvf::cref m_activeCellInfo; + bool m_showInactiveCells; }; class RigFemPart; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index dab62ffa4e..ec7da56874 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -435,7 +435,7 @@ cvf::ref RivCrossSectionPartMgr::createHexGridInterf { RigMainGrid* grid = NULL; grid = eclipseView->eclipseCase()->reservoirData()->mainGrid(); - return new RivEclipseCrossSectionGrid(grid); + return new RivEclipseCrossSectionGrid(grid, eclipseView->currentActiveCellInfo(), m_rimCrossSection->showInactiveCells()); } RimGeoMechView* geoView; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 56dcb132c7..66477756dd 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -74,6 +74,8 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); + CAF_PDM_InitField (&showInactiveCells, "ShowInactiveCells", false, "Inactive Cells", "", "", ""); + uiCapability()->setUiChildrenHidden(true); } @@ -89,7 +91,8 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, changedField == &wellPath || changedField == &simulationWell || changedField == &m_branchIndex || - changedField == &m_extentLength) + changedField == &m_extentLength || + changedField == &showInactiveCells) { m_crossSectionPartMgr = NULL; @@ -149,6 +152,8 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& // User defined poly line } + uiOrdering.add(&showInactiveCells); + updateWellExtentDefaultValue(); uiOrdering.setForgetRemainingFields(true); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 01db56fa44..6557e86e8d 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -64,6 +64,7 @@ class RimCrossSection : public caf::PdmObject caf::PdmField< caf::AppEnum< CrossSectionEnum > > type; caf::PdmField< caf::AppEnum< CrossSectionDirEnum > > direction; + caf::PdmField< bool > showInactiveCells; caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; From 6fdc97546487121ec7c663e23e6feccdc3575097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 13:50:31 +0100 Subject: [PATCH 163/290] Intersection: Reorganized gui a bit --- .../ProjectDataModel/RimCrossSection.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 66477756dd..3eadcb6540 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -70,7 +70,7 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitFieldNoDefault(&type, "Type", "Type", "", "", ""); CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); - CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path", "", "", ""); + CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path ", "", "", ""); CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); @@ -129,30 +129,32 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&name); - uiOrdering.add(&type); - uiOrdering.add(&direction); + caf::PdmUiGroup* geometryGroup = uiOrdering.addNewGroup("Intersecting Geometry"); + geometryGroup->add(&type); if (type == CS_WELL_PATH) { - uiOrdering.add(&wellPath); - uiOrdering.add(&m_extentLength); + geometryGroup->add(&wellPath); } else if (type == CS_SIMULATION_WELL) { - uiOrdering.add(&simulationWell); + geometryGroup->add(&simulationWell); updateWellCenterline(); if (simulationWell() && m_wellBranchCenterlines.size() > 1) { - uiOrdering.add(&m_branchIndex); + geometryGroup->add(&m_branchIndex); } - uiOrdering.add(&m_extentLength); } else { // User defined poly line } - uiOrdering.add(&showInactiveCells); + caf::PdmUiGroup* optionsGroup = uiOrdering.addNewGroup("Options"); + + optionsGroup->add(&direction); + optionsGroup->add(&m_extentLength); + optionsGroup->add(&showInactiveCells); updateWellExtentDefaultValue(); From 7b9f2b41ed8c6bfc1960e32e124843030c0ef4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 27 Nov 2015 16:37:26 +0100 Subject: [PATCH 164/290] CppCheck fixes, Errors Warnings and performance --- ApplicationCode/Application/RiaApplication.cpp | 10 +++++----- .../FileInterface/RifReaderEclipseOutput.cpp | 4 ++-- .../FileInterface/RifReaderMockModel.cpp | 2 +- .../RivCellEdgeGeometryUtils.cpp | 6 ++---- .../RivCrossSectionGeometryGenerator.cpp | 10 +++++----- .../ModelVisualization/RivFaultPartMgr.h | 1 - .../ModelVisualization/RivWellPathPartMgr.cpp | 2 +- .../ModelVisualization/RivWellPipesPartMgr.cpp | 2 +- .../ProjectDataModel/Rim3dOverlayInfoConfig.cpp | 2 ++ .../RigCaseCellResultsData.cpp | 10 +++++----- .../RigSingleWellResultsData.cpp | 6 +++--- .../ReservoirDataModel/RigWellLogExtractor.cpp | 2 +- .../ReservoirDataModel/RigWellLogFile.cpp | 2 +- .../ReservoirDataModel/cvfGeometryTools.cpp | 16 +++++++++------- .../UserInterface/RiuSimpleHistogramWidget.cpp | 3 ++- .../UserInterface/RiuViewerCommands.cpp | 6 +++++- 16 files changed, 45 insertions(+), 39 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index cbcf2c327a..51816a9c01 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1346,7 +1346,7 @@ void RiaApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitStatu } // If multiple cases are present, invoke launchProcess() which will set next current case, and run script on this case - if (m_currentCaseIds.size() > 0) + if (!m_currentCaseIds.empty()) { launchProcess(m_currentProgram, m_currentArguments); } @@ -1365,7 +1365,7 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar if (m_workerProcess == NULL) { // If multiple cases are present, pop the first case ID from the list and set as current case - if (m_currentCaseIds.size() > 0) + if (!m_currentCaseIds.empty()) { int nextCaseId = m_currentCaseIds.front(); m_currentCaseIds.pop_front(); @@ -2170,16 +2170,16 @@ void RiaApplication::executeCommandObjects() { toBeRemoved->redo(); - it++; + ++it; m_commandQueue.remove(toBeRemoved); } else { - it++; + ++it; } } - if (m_commandQueue.size() > 0) + if (!m_commandQueue.empty()) { std::list< RimCommandObject* >::iterator it = m_commandQueue.begin(); diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp index ccd23d12ae..2ae9551118 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp @@ -920,7 +920,7 @@ RigWellResultPoint RifReaderEclipseOutput::createWellResultPoint(const RigGridBa /// Inverse distance interpolation of the supplied points and distance weights for /// the contributing points which are closest above, and closest below //-------------------------------------------------------------------------------------------------- -cvf::Vec3d interpolate3DPosition(const std::vector positions) +cvf::Vec3d interpolate3DPosition(const std::vector& positions) { std::vector filteredPositions; filteredPositions.reserve(positions.size()); @@ -1480,7 +1480,7 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid, boo while (posContribIt != segmentIdToPositionContrib.end()) { bottomPositions[posContribIt->first] = interpolate3DPosition(posContribIt->second); - posContribIt++; + ++posContribIt; } // Distribute the positions to the resultpoints stored in the wellResultBranch.m_branchResultPoints diff --git a/ApplicationCode/FileInterface/RifReaderMockModel.cpp b/ApplicationCode/FileInterface/RifReaderMockModel.cpp index b12a2281ba..c0da5973e2 100644 --- a/ApplicationCode/FileInterface/RifReaderMockModel.cpp +++ b/ApplicationCode/FileInterface/RifReaderMockModel.cpp @@ -122,7 +122,7 @@ bool RifReaderMockModel::dynamicResult(const QString& result, RifReaderInterface //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RifReaderMockModel::RifReaderMockModel() +RifReaderMockModel::RifReaderMockModel() : m_reservoir(NULL) { /* m_cellResults.push_back("Dummy results"); diff --git a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp index da0269aec9..ce3409c162 100644 --- a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp +++ b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp @@ -144,10 +144,9 @@ void RivCellEdgeGeometryUtils::addCellEdgeResultsToDrawableGeo( } - float edgeColor; for (size_t cubeFaceIdx = 0; cubeFaceIdx < 6; cubeFaceIdx++) { - edgeColor = -1.0f; // Undefined texture coord. Shader handles this. + float edgeColor = -1.0f; // Undefined texture coord. Shader handles this. double scalarValue = cellEdgeResultAccessor->cellFaceScalar(cellIndex, static_cast(cubeFaceIdx)); @@ -244,10 +243,9 @@ void RivCellEdgeGeometryUtils::addTernaryCellEdgeResultsToDrawableGeo(size_t tim size_t cellIndex = quadToCellFaceMapper->cellIndex(quadIdx); - float edgeColor; for (size_t cubeFaceIdx = 0; cubeFaceIdx < 6; cubeFaceIdx++) { - edgeColor = -1.0f; // Undefined texture coord. Shader handles this. + float edgeColor = -1.0f; // Undefined texture coord. Shader handles this. double scalarValue = cellEdgeResultAccessor->cellFaceScalar(cellIndex, static_cast(cubeFaceIdx)); diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index b015b8e92d..7013264370 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1028,11 +1028,11 @@ void RivCrossSectionGeometryGenerator::calculateArrays() m_hexGrid->cellCornerVertices(globalCellIdx, cellCorners); m_hexGrid->cellCornerIndices(globalCellIdx, cornerIndices); - int triangleCount = planeHexIntersectionMC(plane, - cellCorners, - cornerIndices, - &hexPlaneCutTriangleVxes, - &isTriangleEdgeCellContour); + planeHexIntersectionMC(plane, + cellCorners, + cornerIndices, + &hexPlaneCutTriangleVxes, + &isTriangleEdgeCellContour); std::vector clippedTriangleVxes; std::vector isClippedTriEdgeCellContour; diff --git a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h index 5d58f30f93..0f2c2dc3e3 100644 --- a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h @@ -83,7 +83,6 @@ class RivFaultPartMgr : public cvf::Object float m_opacityLevel; cvf::Color3f m_defaultColor; - bool m_showNativeFaces; bool m_showOppositeFaces; bool m_showLabel; diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp index ae7f0e41e5..0182ab3ccf 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -244,7 +244,7 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* m } std::list::iterator it; - for (it = m_wellBranches.begin(); it != m_wellBranches.end(); it++) + for (it = m_wellBranches.begin(); it != m_wellBranches.end(); ++it) { if (it->m_surfacePart.notNull()) { diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index 61bd77ec8b..715c134786 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -180,7 +180,7 @@ void RivWellPipesPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* if (m_needsTransformUpdate) buildWellPipeParts(); std::list::iterator it; - for (it = m_wellBranches.begin(); it != m_wellBranches.end(); it++) + for (it = m_wellBranches.begin(); it != m_wellBranches.end(); ++it) { if (it->m_surfacePart.notNull()) { diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 3889bc75e2..f7f0969899 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -93,6 +93,8 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsCellRange, "StatisticsCellRange", "Statistics Cell Range", "", "", ""); //m_statisticsCellRange.uiCapability()->setUiHidden(true); + + m_isVisCellStatUpToDate = false; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 4a84bd599a..7834e8d3ed 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -33,7 +33,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigCaseCellResultsData::RigCaseCellResultsData(RigMainGrid* ownerGrid) +RigCaseCellResultsData::RigCaseCellResultsData(RigMainGrid* ownerGrid) : m_activeCellInfo(NULL) { CVF_ASSERT(ownerGrid != NULL); m_ownerMainGrid = ownerGrid; @@ -182,7 +182,7 @@ std::vector& RigCaseCellResultsData::cellScalarResults(size_t scalarResu size_t RigCaseCellResultsData::findScalarResultIndex(RimDefines::ResultCatType type, const QString& resultName) const { std::vector::const_iterator it; - for (it = m_resultInfos.begin(); it != m_resultInfos.end(); it++) + for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) { if (it->m_resultType == type && it->m_resultName == resultName) { @@ -313,7 +313,7 @@ QStringList RigCaseCellResultsData::resultNames(RimDefines::ResultCatType resTyp { QStringList varList; std::vector::const_iterator it; - for (it = m_resultInfos.begin(); it != m_resultInfos.end(); it++) + for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) { if (it->m_resultType == resType ) { @@ -497,7 +497,7 @@ RifReaderInterface::PorosityModelResultType RigCaseCellResultsData::convertFromP bool RigCaseCellResultsData::mustBeCalculated(size_t scalarResultIndex) const { std::vector::const_iterator it; - for (it = m_resultInfos.begin(); it != m_resultInfos.end(); it++) + for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) { if (it->m_gridScalarResultIndex == scalarResultIndex) { @@ -514,7 +514,7 @@ bool RigCaseCellResultsData::mustBeCalculated(size_t scalarResultIndex) const void RigCaseCellResultsData::setMustBeCalculated(size_t scalarResultIndex) { std::vector::iterator it; - for (it = m_resultInfos.begin(); it != m_resultInfos.end(); it++) + for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) { if (it->m_gridScalarResultIndex == scalarResultIndex) { diff --git a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp index d62cacd574..3b178eb0cb 100644 --- a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp @@ -156,14 +156,14 @@ void RigSingleWellResultsData::computeStaticWellCellPath() std::list< RigWellResultPoint >& stBranch = staticWellBranches[branchId]; std::list< RigWellResultPoint >::iterator sEndIt; - size_t rStartIdx; - size_t rEndIdx; + size_t rStartIdx = -1; + size_t rEndIdx = -1; // First detect if we have cells on the start of the result frame, that is not in the static frame { sEndIt = stBranch.begin(); bool found = false; - if (stBranch.size()) + if (!stBranch.empty()) { for (rEndIdx = 0; !found && rEndIdx < resBranch.size(); ++rEndIdx) { diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogExtractor.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogExtractor.cpp index ff3742806d..8786191416 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogExtractor.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogExtractor.cpp @@ -214,7 +214,7 @@ void RigWellLogExtractor::populateReturnArrays(std::mapfirst.measuredDepth))); // Found that 10 to 11 is not connected, and not 10 to 12 either - it1++; // Discard 10 and jump to 11 and hope that recovers us + ++it1; // Discard 10 and jump to 11 and hope that recovers us continue; } diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index 6148816dac..f481377698 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -106,7 +106,7 @@ bool RigWellLogFile::open(const QString& fileName, QString* errorMessage) const std::map >& contLogs = well->GetContLog(); std::map >::const_iterator itCL; - for (itCL = contLogs.begin(); itCL != contLogs.end(); itCL++) + for (itCL = contLogs.begin(); itCL != contLogs.end(); ++itCL) { QString logName = QString::fromStdString(itCL->first); wellLogNames.append(logName); diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp index 59d2322949..9bcd485893 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp @@ -198,7 +198,7 @@ GeometryTools::IntersectionStatus inPlaneLineIntersect( } double normDist32 = e12*p32 / length34; - double normDist31 = -e12*p13 / length34; + //double normDist31 = -e12*p13 / length34; // Set up fractions along lines to the edge2 vertex actually touching edge 1. /// if two, select the one furthest from the start @@ -471,8 +471,8 @@ cvf::Vec3d GeometryTools::barycentricCoords(const cvf::Vec3d& t0, const cvf::Ve cvf::Vec3d m = (t1 - t0 ^ t2 - t0); // Absolute components for determining projection plane - int X = 0, Y = 1, Z = 2; - Z = findClosestAxis(m); + int X = 0, Y = 1; + int Z = findClosestAxis(m); switch (Z) { case 0: X = 1; Y = 2; break; // x is largest, project to the yz plane @@ -590,6 +590,8 @@ void GeometryTools::addMidEdgeNodes(std::list >* poly polygon->insert(polygon->end(), std::make_pair((cvf::uint)midPointIndex, true)); ++it; + + if (it == polygon->end()) break; } } @@ -745,7 +747,7 @@ bool EarClipTesselator::calculateTriangles( std::vector* triangleIndices while (numVertices > 2) { // if we loop, it is probably a non-simple polygon - if (count <= 0 ) + if (count == 0 ) { // Triangulate: ERROR - probable bad polygon! return false; @@ -877,7 +879,7 @@ double EarClipTesselator::calculateProjectedPolygonArea() const A += (*m_nodeCoords)[*p][m_X] * (*m_nodeCoords)[*q][m_Y] - (*m_nodeCoords)[*q][m_X]*(*m_nodeCoords)[*p][m_Y]; p = q; - q++; + ++q; } return A*0.5; @@ -975,10 +977,10 @@ bool FanEarClipTesselator::calculateTriangles(std::vector* triangles) std::list< std::list > restPolygons; bool wasPreviousTriangleValid = true; - for (it1 = m_polygonIndices.begin(); it1 != m_polygonIndices.end(); it1++) + for (it1 = m_polygonIndices.begin(); it1 != m_polygonIndices.end(); ++it1) { it2 = it1; - it2++; + ++it2; if (it2 == m_polygonIndices.end()) it2 = m_polygonIndices.begin(); diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp index 11eb954553..e74ebc6658 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp @@ -11,7 +11,8 @@ QWidget(parent, f) m_minPercentile = HUGE_VAL; m_maxPercentile = HUGE_VAL; m_mean = HUGE_VAL; - + m_min = HUGE_VAL; + m_max = -HUGE_VAL; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 5307026e49..132df57ab3 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -91,7 +91,11 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) : QObject(ownerViewer), m_viewer(ownerViewer) +RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) + : QObject(ownerViewer), + m_viewer(ownerViewer), + m_currentGridIdx(-1), + m_currentCellIndex(-1) { } From 7cd4394102877825505f109c1c3980b4db7432c9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 17:14:21 +0100 Subject: [PATCH 165/290] Guard against polylines with less than two points --- .../ModelVisualization/RivCrossSectionGeometryGenerator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 7013264370..5cc7804ab2 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -981,6 +981,9 @@ void RivCrossSectionGeometryGenerator::calculateArrays() for (size_t pLineIdx = 0; pLineIdx < m_polyLines.size(); ++pLineIdx) { const std::vector& m_polyLine = m_polyLines[pLineIdx]; + + if (m_polyLine.size() < 2) continue; + std::vector m_adjustedPolyline; adjustPolyline(m_polyLine, m_extrusionDirection, &m_adjustedPolyline); From bd2a65acb42963141254dbf8771629475de1ca40 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 27 Nov 2015 17:18:30 +0100 Subject: [PATCH 166/290] (#641) Create user defined polyline by clicking on reservoir cells --- .../Commands/CMakeLists_files.cmake | 2 + .../CMakeLists_files.cmake | 2 + .../RicNewPolylineCrossSectionFeature.cpp | 155 ++++++++++++++++++ .../RicNewPolylineCrossSectionFeature.h | 83 ++++++++++ ApplicationCode/Commands/RicCommandFeature.h | 33 ++++ .../ProjectDataModel/RimCrossSection.cpp | 136 +++++++++++++-- .../ProjectDataModel/RimCrossSection.h | 13 +- ApplicationCode/UserInterface/RiuViewer.cpp | 17 ++ ApplicationCode/UserInterface/RiuViewer.h | 4 + .../UserInterface/RiuViewerCommands.cpp | 30 ++++ .../UserInterface/RiuViewerCommands.h | 6 + 11 files changed, 462 insertions(+), 19 deletions(-) create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp create mode 100644 ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h create mode 100644 ApplicationCode/Commands/RicCommandFeature.h diff --git a/ApplicationCode/Commands/CMakeLists_files.cmake b/ApplicationCode/Commands/CMakeLists_files.cmake index ad862791ef..55fd011998 100644 --- a/ApplicationCode/Commands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CMakeLists_files.cmake @@ -49,6 +49,8 @@ ${CEE_CURRENT_LIST_DIR}RicExportToLasFileFeature.h ${CEE_CURRENT_LIST_DIR}RicDeleteItemExec.h ${CEE_CURRENT_LIST_DIR}RicDeleteItemExecData.h ${CEE_CURRENT_LIST_DIR}RicDeleteItemFeature.h + +${CEE_CURRENT_LIST_DIR}RicCommandFeature.h ) set (SOURCE_GROUP_SOURCE_FILES diff --git a/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake index 8bf1591780..1ca86b0f08 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CrossSectionCommands/CMakeLists_files.cmake @@ -8,12 +8,14 @@ set (SOURCE_GROUP_HEADER_FILES ${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.h ${CEE_CURRENT_LIST_DIR}RicNewSimWellCrossSectionFeature.h ${CEE_CURRENT_LIST_DIR}RicNewWellPathCrossSectionFeature.h +${CEE_CURRENT_LIST_DIR}RicNewPolylineCrossSectionFeature.h ) set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RicAppendCrossSectionFeature.cpp ${CEE_CURRENT_LIST_DIR}RicNewSimWellCrossSectionFeature.cpp ${CEE_CURRENT_LIST_DIR}RicNewWellPathCrossSectionFeature.cpp +${CEE_CURRENT_LIST_DIR}RicNewPolylineCrossSectionFeature.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp new file mode 100644 index 0000000000..c38008403c --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp @@ -0,0 +1,155 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewPolylineCrossSectionFeature.h" + +#include "RiaApplication.h" + +#include "RimCase.h" +#include "RimCrossSection.h" +#include "RimCrossSectionCollection.h" +#include "RimView.h" + +#include "RiuMainWindow.h" +#include "RiuSelectionManager.h" + +#include "cafCmdExecCommandManager.h" +#include "cafSelectionManager.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT(RicNewPolylineCrossSectionFeature, "RicNewPolylineCrossSectionFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewPolylineCrossSectionFeature::RicNewPolylineCrossSectionFeature() +{ +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewPolylineCrossSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineCrossSectionFeature::onActionTriggered(bool isChecked) +{ + RimView* activeView = RiaApplication::instance()->activeReservoirView(); + if (!activeView) return; + + RicNewPolylineCrossSectionFeatureCmd* cmd = new RicNewPolylineCrossSectionFeatureCmd(activeView->crossSectionCollection); + caf::CmdExecCommandManager::instance()->processExecuteCommand(cmd); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineCrossSectionFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/CrossSection16x16.png")); + actionToSetup->setText("New Polyline Intersection"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewPolylineCrossSectionFeature::handleUiEvent(cvf::Object* uiEventObject) +{ + std::vector selection; + caf::SelectionManager::instance()->objectsByType(&selection); + + if (selection.size() == 1) + { + RicPolylineUiEvent* polylineUiEvent = dynamic_cast(uiEventObject); + if (polylineUiEvent) + { + RimCrossSection* crossSection = selection[0]; + + RimCase* rimCase = NULL; + crossSection->firstAnchestorOrThisOfType(rimCase); + CVF_ASSERT(rimCase); + + crossSection->appendPointToPolyLine(rimCase->displayModelOffset() + polylineUiEvent->localIntersectionPoint); + + // Further Ui processing is stopped when true is returned + return true; + } + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewPolylineCrossSectionFeatureCmd::RicNewPolylineCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection) + : CmdExecuteCommand(NULL), + m_crossSectionCollection(crossSectionCollection) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicNewPolylineCrossSectionFeatureCmd::~RicNewPolylineCrossSectionFeatureCmd() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicNewPolylineCrossSectionFeatureCmd::name() +{ + return "Start Polyline Intersection"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineCrossSectionFeatureCmd::redo() +{ + CVF_ASSERT(m_crossSectionCollection); + + RimCrossSection* crossSection = new RimCrossSection(); + crossSection->name = "Polyline"; + crossSection->type = RimCrossSection::CS_POLYLINE; + m_crossSectionCollection->appendCrossSection(crossSection); + + crossSection->updateActiveUiCommandFeature(); + + RiuSelectionManager::instance()->deleteAllItems(); + + RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineCrossSectionFeatureCmd::undo() +{ +} diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h new file mode 100644 index 0000000000..b2288f69f3 --- /dev/null +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h @@ -0,0 +1,83 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RicCommandFeature.h" + +#include "cafCmdExecuteCommand.h" +#include "cafPdmPointer.h" + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +class RimCrossSectionCollection; + +class RicPolylineUiEvent : public cvf::Object +{ +public: + RicPolylineUiEvent(cvf::Vec3d localIntersectionPoint) + : localIntersectionPoint(localIntersectionPoint) + { + } + + cvf::Vec3d localIntersectionPoint; +}; + + +//================================================================================================== +/// +//================================================================================================== +class RicNewPolylineCrossSectionFeatureCmd : public caf::CmdExecuteCommand +{ +public: + RicNewPolylineCrossSectionFeatureCmd(RimCrossSectionCollection* crossSectionCollection); + virtual ~RicNewPolylineCrossSectionFeatureCmd(); + + virtual QString name(); + virtual void redo(); + virtual void undo(); + +private: + caf::PdmPointer m_crossSectionCollection; +}; + + + +//================================================================================================== +/// +//================================================================================================== +class RicNewPolylineCrossSectionFeature : public RicCommandFeature +{ + CAF_CMD_HEADER_INIT; + +public: + RicNewPolylineCrossSectionFeature(); + +protected: + // Overrides + virtual bool isCommandEnabled(); + virtual void onActionTriggered( bool isChecked ); + virtual void setupActionLook( QAction* actionToSetup ); + + virtual bool handleUiEvent(cvf::Object* uiEventObject); +}; + + diff --git a/ApplicationCode/Commands/RicCommandFeature.h b/ApplicationCode/Commands/RicCommandFeature.h new file mode 100644 index 0000000000..b86c9a848c --- /dev/null +++ b/ApplicationCode/Commands/RicCommandFeature.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +namespace cvf +{ + class Object; +} + +class RicCommandFeature : public caf::CmdFeature +{ +public: + virtual bool handleUiEvent(cvf::Object* uiEventObject) = 0; +}; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 3eadcb6540..caaed04dbe 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -21,16 +21,25 @@ #include "RiaApplication.h" +#include "RicCommandFeature.h" + +#include "RigSimulationWellCenterLineCalculator.h" + +#include "RimCase.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimEclipseWellCollection.h" #include "RimOilField.h" #include "RimProject.h" +#include "RimView.h" #include "RimWellPath.h" +#include "RiuViewer.h" #include "RivCrossSectionPartMgr.h" -#include "RigSimulationWellCenterLineCalculator.h" -#include "RimCase.h" + +#include "cafCmdFeature.h" +#include "cafCmdFeatureManager.h" +#include "cafPdmUiPushButtonEditor.h" namespace caf { @@ -40,7 +49,7 @@ void caf::AppEnum< RimCrossSection::CrossSectionEnum >::setUp() { addItem(RimCrossSection::CS_WELL_PATH, "CS_WELL_PATH", "Well Path"); addItem(RimCrossSection::CS_SIMULATION_WELL, "CS_SIMULATION_WELL", "Simulation Well"); -// addItem(RimCrossSection::CS_USER_DEFINED, "CS_USER_DEFINED", "User defined"); + addItem(RimCrossSection::CS_POLYLINE, "CS_POLYLINE", "Polyline"); setDefault(RimCrossSection::CS_WELL_PATH); } @@ -72,10 +81,18 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path ", "", "", ""); CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_userDefinedPolyline, "Points", "Selected points", "", "", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); CAF_PDM_InitField (&showInactiveCells, "ShowInactiveCells", false, "Inactive Cells", "", "", ""); - + + CAF_PDM_InitFieldNoDefault(&m_activateUiAppendPointsCommand, "m_activateUiAppendPointsCommand", "", "", "", ""); + m_activateUiAppendPointsCommand.xmlCapability()->setIOWritable(false); + m_activateUiAppendPointsCommand.xmlCapability()->setIOReadable(false); + m_activateUiAppendPointsCommand.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + m_activateUiAppendPointsCommand.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + + m_activateUiAppendPointsCommand = false; uiCapability()->setUiChildrenHidden(true); } @@ -94,14 +111,7 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, changedField == &m_extentLength || changedField == &showInactiveCells) { - m_crossSectionPartMgr = NULL; - - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - if (rimView) - { - rimView->scheduleCreateDisplayModelAndRedraw(); - } + rebuildGeometryAndScheduleCreateDisplayModel(); } if (changedField == &simulationWell @@ -121,6 +131,17 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateName(); } + if (changedField == &m_activateUiAppendPointsCommand) + { + updateActiveUiCommandFeature(); + + m_activateUiAppendPointsCommand = false; + } + + if (changedField == &m_userDefinedPolyline) + { + rebuildGeometryAndScheduleCreateDisplayModel(); + } } //-------------------------------------------------------------------------------------------------- @@ -145,9 +166,10 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& geometryGroup->add(&m_branchIndex); } } - else + else if (type == CS_POLYLINE) { - // User defined poly line + uiOrdering.add(&m_userDefinedPolyline); + uiOrdering.add(&m_activateUiAppendPointsCommand); } caf::PdmUiGroup* optionsGroup = uiOrdering.addNewGroup("Options"); @@ -286,9 +308,9 @@ std::vector< std::vector > RimCrossSection::polyLines() const } } } - else + else if (type == CS_POLYLINE) { - + lines.push_back(m_userDefinedPolyline); } if (type == CS_WELL_PATH || type == CS_SIMULATION_WELL) @@ -387,8 +409,6 @@ void RimCrossSection::addExtents(std::vector &polyLine) const polyLine.insert(polyLine.begin(), newStart); } - - } //-------------------------------------------------------------------------------------------------- @@ -475,3 +495,83 @@ void RimCrossSection::clipToReservoir(std::vector &polyLine) const polyLine.swap(clippedPolyLine); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_activateUiAppendPointsCommand) + { + caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); + + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + CVF_ASSERT(rimView); + + if (rimView->viewer()->activeUiCommandFeature()) + { + attrib->m_buttonText = "End point input"; + } + else + { + attrib->m_buttonText = "Start point input"; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::appendPointToPolyLine(const cvf::Vec3d& point) +{ + m_userDefinedPolyline.v().push_back(point); + + m_userDefinedPolyline.uiCapability()->updateConnectedEditors(); + + rebuildGeometryAndScheduleCreateDisplayModel(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::updateActiveUiCommandFeature() +{ + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + CVF_ASSERT(rimView); + + if (!rimView->viewer()) return; + + if (rimView->viewer()->activeUiCommandFeature()) + { + rimView->viewer()->setActiveUiCommandFeature(NULL); + } + else + { + caf::CmdFeature* cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicNewPolylineCrossSectionFeature"); + CVF_ASSERT(cmdFeature); + + RicCommandFeature* riCommandFeature = dynamic_cast(cmdFeature); + CVF_ASSERT(riCommandFeature); + + rimView->viewer()->setActiveUiCommandFeature(riCommandFeature); + } + + updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCrossSection::rebuildGeometryAndScheduleCreateDisplayModel() +{ + m_crossSectionPartMgr = NULL; + + RimView* rimView = NULL; + this->firstAnchestorOrThisOfType(rimView); + if (rimView) + { + rimView->scheduleCreateDisplayModelAndRedraw(); + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 6557e86e8d..81d5b5fedf 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -21,6 +21,7 @@ #include "cafAppEnum.h" #include "cafPdmField.h" +#include "cafPdmFieldCvfVec3d.h" #include "cafPdmObject.h" #include "cafPdmPtrField.h" @@ -47,7 +48,7 @@ class RimCrossSection : public caf::PdmObject { CS_WELL_PATH, CS_SIMULATION_WELL, - CS_USER_DEFINED + CS_POLYLINE }; enum CrossSectionDirEnum @@ -72,18 +73,27 @@ class RimCrossSection : public caf::PdmObject std::vector< std::vector > polyLines() const; RivCrossSectionPartMgr* crossSectionPartMgr(); + void appendPointToPolyLine(const cvf::Vec3d& point); + void updateActiveUiCommandFeature(); + protected: virtual caf::PdmFieldHandle* userDescriptionField(); virtual caf::PdmFieldHandle* objectToggleField(); virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); + virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); private: caf::PdmField m_branchIndex; caf::PdmField m_extentLength; + + caf::PdmField< std::vector< cvf::Vec3d> > m_userDefinedPolyline; + caf::PdmField< bool > m_activateUiAppendPointsCommand; RimEclipseWellCollection* simulationWellCollection(); void updateWellCenterline() const; @@ -91,6 +101,7 @@ class RimCrossSection : public caf::PdmObject void addExtents(std::vector &polyLine) const; void clipToReservoir(std::vector &polyLine) const; void updateName(); + void rebuildGeometryAndScheduleCreateDisplayModel(); private: cvf::ref m_crossSectionPartMgr; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 4be74f84ea..4417adbc06 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -649,3 +649,20 @@ cvf::Color3f RiuViewer::computeContrastColor() const return contrastColor; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature) +{ + CVF_ASSERT(m_viewerCommands); + m_viewerCommands->setActiveUiCommandFeature(uiCommandFeature); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCommandFeature* RiuViewer::activeUiCommandFeature() const +{ + return m_viewerCommands->activeUiCommandFeature(); +} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 9adceb68e5..4cd8cda7a5 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -28,6 +28,7 @@ #include "cafMouseState.h" #include "cvfStructGrid.h" +class RicCommandFeature; class RimView; class RiuSimpleHistogramWidget; class RiuViewerCommands; @@ -88,6 +89,9 @@ class RiuViewer : public caf::Viewer void setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel); + void setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature); + RicCommandFeature* activeUiCommandFeature() const; + public slots: virtual void slotSetCurrentFrame(int frameIndex); virtual void slotEndAnimation(); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 132df57ab3..f69f571034 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -23,6 +23,7 @@ #include "RicGeoMechPropertyFilterNewExec.h" #include "RicRangeFilterNewExec.h" +#include "CrossSectionCommands/RicNewPolylineCrossSectionFeature.h" #include "CrossSectionCommands/RicNewSimWellCrossSectionFeature.h" #include "CrossSectionCommands/RicNewWellPathCrossSectionFeature.h" #include "WellLogCommands/RicNewWellLogCurveExtractionFeature.h" @@ -277,6 +278,8 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) commandIds << "RicSetMasterViewFeature"; } + commandIds << "RicNewPolylineCrossSectionFeature"; + RimContextCommandBuilder::appendCommandsToMenu(commandIds, &menu); if (menu.actions().size() > 0) @@ -439,6 +442,17 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM if (m_viewer->rayPick(winPosX, winPosY, &hitItems)) { extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &firstPartTriangleIndex, &firstNncHitPart, &nncPartTriangleIndex); + + if (!m_activeUiCommandFeature.isNull()) + { + cvf::ref uiEventObj = new RicPolylineUiEvent(localIntersectionPoint); + + if (m_activeUiCommandFeature->handleUiEvent(uiEventObj.p())) + { + return; + } + } + updateSelectionFromPickedPart(firstHitPart); } @@ -564,6 +578,22 @@ void RiuViewerCommands::findCellAndGridIndex(const RivCrossSectionSourceInfo* cr } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature) +{ + m_activeUiCommandFeature = uiCommandFeature; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicCommandFeature* RiuViewerCommands::activeUiCommandFeature() const +{ + return m_activeUiCommandFeature; +} + //-------------------------------------------------------------------------------------------------- /// Perform picking and return the index of the face that was hit, if a drawable geo was hit //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index e7bc42825d..40c61dc8bd 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -31,6 +31,7 @@ class RimGeoMechView; class RimView; class RiuViewer; class RivCrossSectionSourceInfo; +class RicCommandFeature; class QMouseEvent; @@ -54,6 +55,9 @@ class RiuViewerCommands: public QObject void findCellAndGridIndex(const RivCrossSectionSourceInfo* crossSectionSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex); + void setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature); + RicCommandFeature* activeUiCommandFeature() const; + private slots: void slotRangeFilterI(); @@ -78,6 +82,8 @@ private slots: caf::PdmPointer m_currentCrossSection; QPointer m_viewer; + + QPointer m_activeUiCommandFeature; }; From 707e8c68ab5e3ed8470c88f40660eaa5ac68cccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 30 Nov 2015 14:02:52 +0100 Subject: [PATCH 167/290] (#163) Sort simulation wells by name --- ApplicationCode/ProjectDataModel/RimEclipseView.cpp | 2 ++ .../ProjectDataModel/RimEclipseWellCollection.cpp | 13 +++++++++++++ .../ProjectDataModel/RimEclipseWellCollection.h | 4 +++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index e6a3108a2f..87b6c3eaff 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1138,6 +1138,8 @@ void RimEclipseView::syncronizeWellsWithResults() { this->wellCollection()->wells()[wIdx]->setReservoirView(this); } + + this->wellCollection()->sortWellsByName(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp index 63331d829a..4f8aad5dee 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp @@ -333,3 +333,16 @@ void RimEclipseWellCollection::calculateIsWellPipesVisible(size_t frameIndex) m_isWellPipesVisible[frameIndex][i] = wells[i]->calculateWellPipeVisibility(frameIndex); } } + +bool lessEclipseWell(const caf::PdmPointer& w1, const caf::PdmPointer& w2) +{ + return (w1->name() < w2->name()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseWellCollection::sortWellsByName() +{ + std::sort(wells.begin(), wells.end(), lessEclipseWell); +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h index dc4b4ca7b9..9822f693ca 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h @@ -104,13 +104,15 @@ class RimEclipseWellCollection : public caf::PdmObject caf::PdmChildArrayField wells; - RimEclipseWell* findWell(QString name); + RimEclipseWell* findWell(QString name); bool hasVisibleWellCells(); bool hasVisibleWellPipes(); + void sortWellsByName(); const std::vector& isWellPipesVisible(size_t frameIndex); void scheduleIsWellPipesVisibleRecalculation(); +protected: virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); virtual caf::PdmFieldHandle* objectToggleField(); From d637248ae9f9ac7e6eb0616db0631e506b270248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 30 Nov 2015 14:32:34 +0100 Subject: [PATCH 168/290] (#655) Sort the wells in the Wells folder by name --- .../RimWellPathCollection.cpp | 19 +++++++++++++++++++ .../ProjectDataModel/RimWellPathCollection.h | 4 +++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp index 182d553334..53ee50dba1 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp @@ -164,6 +164,8 @@ void RimWellPathCollection::readWellPathFiles() progress.setProgressDescription(QString("Reading file %1").arg(wellPaths[wpIdx]->name)); progress.incrementProgress(); } + + this->sortWellsByName(); } @@ -258,6 +260,8 @@ void RimWellPathCollection::readAndAddWellPaths(std::vector& wellP progress.incrementProgress(); } + + this->sortWellsByName(); } @@ -282,6 +286,8 @@ void RimWellPathCollection::addWellLogs(const QStringList& filePaths) wellPath->setLogFileInfo(logFileInfo); } } + + this->sortWellsByName(); } //-------------------------------------------------------------------------------------------------- @@ -381,6 +387,19 @@ void RimWellPathCollection::removeWellPath(RimWellPath* wellPath) } } +bool lessWellPath(const caf::PdmPointer& w1, const caf::PdmPointer& w2) +{ + return (w1->name() < w2->name()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCollection::sortWellsByName() +{ + std::sort(wellPaths.begin(), wellPaths.end(), lessWellPath); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.h b/ApplicationCode/ProjectDataModel/RimWellPathCollection.h index df00e852a7..27f6b661d5 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.h +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.h @@ -89,16 +89,18 @@ class RimWellPathCollection : public caf::PdmObject RimWellPath* wellPathByName(const QString& wellPathName) const; void addWellLogs(const QStringList& filePaths); - virtual void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ); void scheduleGeometryRegenAndRedrawViews(); void updateFilePathsFromProjectPath(); +protected: + virtual void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ); private: virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ); virtual caf::PdmFieldHandle* objectToggleField(); void readAndAddWellPaths(std::vector& wellPathArray); + void sortWellsByName(); caf::PdmPointer m_project; cvf::ref m_wellPathCollectionPartManager; From 9d9ff798a999599bcebece06786e4cbba4616a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 30 Nov 2015 14:50:16 +0100 Subject: [PATCH 169/290] (#655)(#163) Guard against null ptrs in name comparisons --- .../ProjectDataModel/RimEclipseWellCollection.cpp | 7 ++++++- ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp index 4f8aad5dee..e01da35ac5 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp @@ -336,7 +336,12 @@ void RimEclipseWellCollection::calculateIsWellPipesVisible(size_t frameIndex) bool lessEclipseWell(const caf::PdmPointer& w1, const caf::PdmPointer& w2) { - return (w1->name() < w2->name()); + if (w1.notNull() && w2.notNull()) + return (w1->name() < w2->name()); + else if (w1.notNull()) + return true; + else + return false; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp index 53ee50dba1..b2459dd78d 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp @@ -389,7 +389,12 @@ void RimWellPathCollection::removeWellPath(RimWellPath* wellPath) bool lessWellPath(const caf::PdmPointer& w1, const caf::PdmPointer& w2) { - return (w1->name() < w2->name()); + if (w1.notNull() && w2.notNull()) + return (w1->name() < w2->name()); + else if (w1.notNull()) + return true; + else + return false; } //-------------------------------------------------------------------------------------------------- From 704f4fa42b92bdc90dfab228cfad78b957e250a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 30 Nov 2015 15:07:54 +0100 Subject: [PATCH 170/290] (#672) Avoid deleting and hiding WellLogPlot and Wells folders when they have no children --- ApplicationCode/ProjectDataModel/RimOilField.cpp | 1 + ApplicationCode/ProjectDataModel/RimProject.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimOilField.cpp b/ApplicationCode/ProjectDataModel/RimOilField.cpp index 69d2345dc9..7a9440b24a 100644 --- a/ApplicationCode/ProjectDataModel/RimOilField.cpp +++ b/ApplicationCode/ProjectDataModel/RimOilField.cpp @@ -37,6 +37,7 @@ RimOilField::RimOilField(void) CAF_PDM_InitFieldNoDefault(&wellPathCollection, "WellPathCollection", "Well Paths", ":/WellCollection.png", "", ""); analysisModels = new RimEclipseCaseCollection(); + wellPathCollection = new RimWellPathCollection(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index e4628d2bb1..58226c7018 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -139,7 +139,11 @@ RimProject::~RimProject(void) //-------------------------------------------------------------------------------------------------- void RimProject::close() { - if (mainPlotCollection()) delete mainPlotCollection(); + if (mainPlotCollection() && mainPlotCollection()->wellLogPlotCollection()) + { + mainPlotCollection()->wellLogPlotCollection()->wellLogPlots.deleteAllChildObjects(); + } + oilFields.deleteAllChildObjects(); oilFields.push_back(new RimOilField); @@ -723,10 +727,7 @@ void RimProject::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QS { if (mainPlotCollection->wellLogPlotCollection()) { - if (mainPlotCollection->wellLogPlotCollection()->wellLogPlots().size() > 0) - { - uiTreeOrdering.add(mainPlotCollection->wellLogPlotCollection()); - } + uiTreeOrdering.add(mainPlotCollection->wellLogPlotCollection()); } } From ee11d4fde7be51742f65cbe6b4f70ae690f30877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 1 Dec 2015 12:27:19 +0100 Subject: [PATCH 171/290] (#672) Refactoring and Fix of side effects introduced by 704f4fa --- .../Application/RiaApplication.cpp | 3 -- .../ProjectDataModel/RimProject.cpp | 1 - .../ProjectDataModel/RimWellPath.cpp | 20 ++++++++----- .../ProjectDataModel/RimWellPath.h | 8 ++--- .../RimWellPathCollection.cpp | 30 ++++--------------- .../ProjectDataModel/RimWellPathCollection.h | 1 - 6 files changed, 21 insertions(+), 42 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 51816a9c01..3c6c144e74 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -351,7 +351,6 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi { //printf("Create well path collection for oil field %i in loadProject.\n", oilFieldIdx); oilField->wellPathCollection = new RimWellPathCollection(); - oilField->wellPathCollection->setProject(m_project); } if (oilField->wellPathCollection) oilField->wellPathCollection->readWellPathFiles(); @@ -474,7 +473,6 @@ void RiaApplication::addWellPathsToModel(QList wellPathFilePaths) { //printf("Create well path collection.\n"); oilField->wellPathCollection = new RimWellPathCollection(); - oilField->wellPathCollection->setProject(m_project); m_project->updateConnectedEditors(); } @@ -497,7 +495,6 @@ void RiaApplication::addWellLogsToModel(const QList& wellLogFilePaths) if (oilField->wellPathCollection == NULL) { oilField->wellPathCollection = new RimWellPathCollection(); - oilField->wellPathCollection->setProject(m_project); m_project->updateConnectedEditors(); } diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index 58226c7018..da7e75beb5 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -306,7 +306,6 @@ void RimProject::initAfterRead() { RimOilField* oilField = oilFields[oilFieldIdx]; if (oilField == NULL || oilField->wellPathCollection == NULL) continue; - oilField->wellPathCollection->setProject(this); } } diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.cpp b/ApplicationCode/ProjectDataModel/RimWellPath.cpp index b813e3a6a8..e6d0797d55 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPath.cpp @@ -91,7 +91,6 @@ RimWellPath::RimWellPath() m_wellLogFile.uiCapability()->setUiHidden(true); m_wellPath = NULL; - m_project = NULL; } @@ -148,7 +147,9 @@ RivWellPathPartMgr* RimWellPath::partMgr() { if (m_wellPathPartMgr.isNull()) { - m_wellPathPartMgr = new RivWellPathPartMgr(m_wellPathCollection, this); + RimWellPathCollection* wpColl; + this->firstAnchestorOrThisOfType(wpColl); + if (wpColl) m_wellPathPartMgr = new RivWellPathPartMgr(wpColl, this); } return m_wellPathPartMgr.p(); @@ -161,7 +162,10 @@ RivWellPathPartMgr* RimWellPath::partMgr() void RimWellPath::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { partMgr()->scheduleGeometryRegen(); - if (m_project) m_project->createDisplayModelAndRedrawAllViews(); + + RimProject* proj; + this->firstAnchestorOrThisOfType(proj); + if (proj) proj->createDisplayModelAndRedrawAllViews(); } @@ -177,7 +181,7 @@ caf::PdmFieldHandle* RimWellPath::objectToggleField() //-------------------------------------------------------------------------------------------------- /// Read JSON or ascii file containing well path data //-------------------------------------------------------------------------------------------------- -bool RimWellPath::readWellPathFile(QString* errorMessage) +bool RimWellPath::readWellPathFile(QString* errorMessage, RifWellPathAsciiFileReader* asciiReader) { QFileInfo fileInf(filepath()); @@ -189,7 +193,7 @@ bool RimWellPath::readWellPathFile(QString* errorMessage) } else { - this->readAsciiWellPathFile(); + this->readAsciiWellPathFile(asciiReader); } return true; @@ -254,9 +258,11 @@ void RimWellPath::readJsonWellPathFile() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellPath::readAsciiWellPathFile() +void RimWellPath::readAsciiWellPathFile(RifWellPathAsciiFileReader* asciiReader) { - RifWellPathAsciiFileReader::WellData wpData = m_wellPathCollection->asciiFileReader()->readWellData(filepath(), wellPathIndexInFile()); + CVF_ASSERT(asciiReader); + + RifWellPathAsciiFileReader::WellData wpData = asciiReader->readWellData(filepath(), wellPathIndexInFile()); this->name = wpData.m_name; setWellPathGeometry(wpData.m_wellPathGeometry.p()); diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.h b/ApplicationCode/ProjectDataModel/RimWellPath.h index 18e814d095..2d38dd0917 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.h +++ b/ApplicationCode/ProjectDataModel/RimWellPath.h @@ -49,8 +49,6 @@ class RimWellPath : public caf::PdmObject RimWellPath(); virtual ~RimWellPath(); - void setProject(RimProject* project) { m_project = project; } - void setCollection(RimWellPathCollection* collection) { m_wellPathCollection = collection; } void setLogFileInfo(RimWellLogFile* logFileInfo); virtual caf::PdmFieldHandle* userDescriptionField(); @@ -74,7 +72,7 @@ class RimWellPath : public caf::PdmObject RigWellPath* wellPathGeometry() { return m_wellPath.p(); } RivWellPathPartMgr* partMgr(); - bool readWellPathFile(QString * errorMessage); + bool readWellPathFile(QString * errorMessage, RifWellPathAsciiFileReader* asciiReader); void updateFilePathsFromProjectPath(); @@ -83,7 +81,7 @@ class RimWellPath : public caf::PdmObject void setWellPathGeometry(RigWellPath* wellPathModel) { m_wellPath = wellPathModel; } void readJsonWellPathFile(); - void readAsciiWellPathFile(); + void readAsciiWellPathFile(RifWellPathAsciiFileReader* asciiReader); QString surveyType() { return m_surveyType; } void setSurveyType(QString surveyType); @@ -104,6 +102,4 @@ class RimWellPath : public caf::PdmObject cvf::ref m_wellPath; cvf::ref m_wellPathPartMgr; - caf::PdmPointer m_wellPathCollection; - RimProject* m_project; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp index b2459dd78d..d48ec74914 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp @@ -82,7 +82,6 @@ RimWellPathCollection::RimWellPathCollection() wellPaths.uiCapability()->setUiHidden(true); m_wellPathCollectionPartManager = new RivWellPathCollectionPartMgr(this); - m_project = NULL; m_asciiFileReader = new RifWellPathAsciiFileReader; } @@ -107,20 +106,6 @@ void RimWellPathCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedF } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimWellPathCollection::setProject( RimProject* project ) -{ - m_project = project; - for (size_t wellPathIdx = 0; wellPathIdx < wellPaths.size(); wellPathIdx++) - { - wellPaths[wellPathIdx]->setProject(m_project); - wellPaths[wellPathIdx]->setCollection(this); - } -} - - //-------------------------------------------------------------------------------------------------- /// Read JSON files containing well path data //-------------------------------------------------------------------------------------------------- @@ -133,7 +118,7 @@ void RimWellPathCollection::readWellPathFiles() if (!wellPaths[wpIdx]->filepath().isEmpty()) { QString errorMessage; - if (!wellPaths[wpIdx]->readWellPathFile(&errorMessage)) + if (!wellPaths[wpIdx]->readWellPathFile(&errorMessage, this->asciiFileReader())) { QMessageBox::warning(RiuMainWindow::instance(), "File open error", @@ -203,8 +188,6 @@ void RimWellPathCollection::addWellPaths( QStringList filePaths ) if (fi.suffix().compare("json") == 0) { RimWellPath* wellPath = new RimWellPath(); - wellPath->setProject(m_project); - wellPath->setCollection(this); wellPath->filepath = filePath; wellPathArray.push_back(wellPath); } @@ -215,8 +198,6 @@ void RimWellPathCollection::addWellPaths( QStringList filePaths ) for (size_t i = 0; i < wellPathCount; ++i) { RimWellPath* wellPath = new RimWellPath(); - wellPath->setProject(m_project); - wellPath->setCollection(this); wellPath->filepath = filePath; wellPath->wellPathIndexInFile = static_cast(i); wellPathArray.push_back(wellPath); @@ -239,7 +220,7 @@ void RimWellPathCollection::readAndAddWellPaths(std::vector& wellP for (size_t wpIdx = 0; wpIdx < wellPathArray.size(); wpIdx++) { RimWellPath* wellPath = wellPathArray[wpIdx]; - wellPath->readWellPathFile(NULL); + wellPath->readWellPathFile(NULL, this->asciiFileReader()); progress.setProgressDescription(QString("Reading file %1").arg(wellPath->name)); @@ -249,7 +230,7 @@ void RimWellPathCollection::readAndAddWellPaths(std::vector& wellP { existingWellPath->filepath = wellPath->filepath; existingWellPath->wellPathIndexInFile = wellPath->wellPathIndexInFile; - existingWellPath->readWellPathFile(NULL); + existingWellPath->readWellPathFile(NULL, this->asciiFileReader()); delete wellPath; } @@ -279,7 +260,6 @@ void RimWellPathCollection::addWellLogs(const QStringList& filePaths) if (!wellPath) { wellPath = new RimWellPath(); - wellPath->setCollection(this); wellPaths.push_back(wellPath); } @@ -322,7 +302,9 @@ caf::PdmFieldHandle* RimWellPathCollection::objectToggleField() void RimWellPathCollection::scheduleGeometryRegenAndRedrawViews() { m_wellPathCollectionPartManager->scheduleGeometryRegen(); - if (m_project) m_project->createDisplayModelAndRedrawAllViews(); + RimProject* proj; + this->firstAnchestorOrThisOfType(proj); + if (proj) proj->createDisplayModelAndRedrawAllViews(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.h b/ApplicationCode/ProjectDataModel/RimWellPathCollection.h index 27f6b661d5..19f4cbe079 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.h +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.h @@ -102,7 +102,6 @@ class RimWellPathCollection : public caf::PdmObject void readAndAddWellPaths(std::vector& wellPathArray); void sortWellsByName(); - caf::PdmPointer m_project; cvf::ref m_wellPathCollectionPartManager; RifWellPathAsciiFileReader* m_asciiFileReader; From 1208c2f4688d52d29dc911b29b0dc8f1d85b6304 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 08:10:10 +0100 Subject: [PATCH 172/290] (#641) Show user defined polyline using magenta, also visible when mesh is turned off --- .../RivCrossSectionGeometryGenerator.cpp | 45 +++++++++++++++++++ .../RivCrossSectionGeometryGenerator.h | 1 + .../RivCrossSectionPartMgr.cpp | 40 +++++++++++++++++ .../RivCrossSectionPartMgr.h | 1 + 4 files changed, 87 insertions(+) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 5cc7804ab2..a24be7c6a9 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -26,6 +26,7 @@ #include "cvfDrawableGeo.h" #include "cvfPrimitiveSetDirect.h" +#include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" @@ -1149,6 +1150,50 @@ cvf::ref RivCrossSectionGeometryGenerator::createMeshDrawable( return geo; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivCrossSectionGeometryGenerator::createLineAlongPolylineDrawable() +{ + std::vector lineIndices; + std::vector vertices; + + cvf::Vec3d displayOffset = m_hexGrid->displayOffset(); + + for (size_t pLineIdx = 0; pLineIdx < m_polyLines.size(); ++pLineIdx) + { + const std::vector& m_polyLine = m_polyLines[pLineIdx]; + if (m_polyLine.size() < 2) continue; + + for (size_t i = 0; i < m_polyLine.size(); ++i) + { + vertices.push_back(cvf::Vec3f(m_polyLine[i] - displayOffset)); + if (i < m_polyLine.size() - 1) + { + lineIndices.push_back(static_cast(i)); + lineIndices.push_back(static_cast(i + 1)); + } + } + } + + if (vertices.size() == 0) return NULL; + + cvf::ref vx = new cvf::Vec3fArray; + vx->assign(vertices); + cvf::ref idxes = new cvf::UIntArray; + idxes->assign(lineIndices); + + cvf::ref prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); + prim->setIndices(idxes.p()); + + cvf::ref polylineGeo = new cvf::DrawableGeo; + polylineGeo->setVertexArray(vx.p()); + polylineGeo->addPrimitiveSet(prim.p()); + + return polylineGeo; +} + //-------------------------------------------------------------------------------------------------- /// Remove the lines from the polyline that is nearly parallel to the extrusion direction //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index fab8524f6c..39acac96ee 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -141,6 +141,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object // Generate geometry cvf::ref generateSurface(); cvf::ref createMeshDrawable(); + cvf::ref createLineAlongPolylineDrawable(); // Mapping between cells and geometry const std::vector& triangleToCellIndex() const; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index ec7da56874..3ec883618d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -46,6 +46,8 @@ #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfPrimitiveSetDirect.h" +#include "cvfRenderState_FF.h" +#include "cvfRenderStateDepth.h" //-------------------------------------------------------------------------------------------------- @@ -339,6 +341,38 @@ void RivCrossSectionPartMgr::generatePartGeometry() } } + // Highlight line + { + cvf::ref polylineGeo = m_crossSectionGenerator->createLineAlongPolylineDrawable(); + if (polylineGeo.notNull()) + { + if (useBufferObjects) + { + polylineGeo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); + } + + cvf::ref part = new cvf::Part; + part->setName("Cross Section Polyline"); + part->setDrawable(polylineGeo.p()); + + part->updateBoundingBox(); + //part->setEnableMask(meshFaultBit); + //part->setPriority(priMesh); + + cvf::ref eff; + caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); + eff = lineEffGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + + part->setEffect(eff.p()); + + m_highlightLineAlongPolyline = part; + } + } + updatePartEffect(); } @@ -407,6 +441,12 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod m_crossSectionGridLines->setTransform(scaleTransform); model->addPart(m_crossSectionGridLines.p()); } + + if (m_highlightLineAlongPolyline.notNull()) + { + m_highlightLineAlongPolyline->setTransform(scaleTransform); + model->addPart(m_highlightLineAlongPolyline.p()); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 28f1332ab7..3bb2db294d 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -84,4 +84,5 @@ class RivCrossSectionPartMgr : public cvf::Object cvf::ref m_crossSectionGridLines; cvf::ref m_crossSectionFacesTextureCoords; + cvf::ref m_highlightLineAlongPolyline; }; From 40c9b711c213512eaed16440173226513ba1d517 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 08:21:42 +0100 Subject: [PATCH 173/290] (#641) Use large priority to make sure the highlight part is rendered after reservoir parts --- ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 3ec883618d..b199afa52c 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -356,8 +356,10 @@ void RivCrossSectionPartMgr::generatePartGeometry() part->setDrawable(polylineGeo.p()); part->updateBoundingBox(); + part->setPriority(10000); + + // Always show this part, also when mesh is turned off //part->setEnableMask(meshFaultBit); - //part->setPriority(priMesh); cvf::ref eff; caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); From 8b3adf0f5b32972aab61b05792440ed264ca138b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 10:00:06 +0100 Subject: [PATCH 174/290] (#641) Refactoring to improve readability --- .../RicNewPolylineCrossSectionFeature.cpp | 2 +- .../RicNewPolylineCrossSectionFeature.h | 11 ------- ApplicationCode/Commands/RicCommandFeature.h | 20 +++++++++--- .../ProjectDataModel/RimCrossSection.cpp | 32 +++++++++---------- .../ProjectDataModel/RimCrossSection.h | 4 +-- .../UserInterface/RiuViewerCommands.cpp | 23 +++---------- 6 files changed, 39 insertions(+), 53 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp index c38008403c..114f8bf47a 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp @@ -85,7 +85,7 @@ bool RicNewPolylineCrossSectionFeature::handleUiEvent(cvf::Object* uiEventObject if (selection.size() == 1) { - RicPolylineUiEvent* polylineUiEvent = dynamic_cast(uiEventObject); + RicLocalIntersectionUiEvent* polylineUiEvent = dynamic_cast(uiEventObject); if (polylineUiEvent) { RimCrossSection* crossSection = selection[0]; diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h index b2288f69f3..6900672c4e 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h @@ -30,17 +30,6 @@ class RimCrossSectionCollection; -class RicPolylineUiEvent : public cvf::Object -{ -public: - RicPolylineUiEvent(cvf::Vec3d localIntersectionPoint) - : localIntersectionPoint(localIntersectionPoint) - { - } - - cvf::Vec3d localIntersectionPoint; -}; - //================================================================================================== /// diff --git a/ApplicationCode/Commands/RicCommandFeature.h b/ApplicationCode/Commands/RicCommandFeature.h index b86c9a848c..aed7624bf5 100644 --- a/ApplicationCode/Commands/RicCommandFeature.h +++ b/ApplicationCode/Commands/RicCommandFeature.h @@ -21,13 +21,25 @@ #include "cafCmdFeature.h" -namespace cvf -{ - class Object; -} +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + class RicCommandFeature : public caf::CmdFeature { public: virtual bool handleUiEvent(cvf::Object* uiEventObject) = 0; }; + +class RicLocalIntersectionUiEvent : public cvf::Object +{ +public: + RicLocalIntersectionUiEvent(cvf::Vec3d localIntersectionPoint) + : localIntersectionPoint(localIntersectionPoint) + { + } + + cvf::Vec3d localIntersectionPoint; +}; + diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index caaed04dbe..8cae73472d 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -81,18 +81,18 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path ", "", "", ""); CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_userDefinedPolyline, "Points", "Selected points", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_userPolyline, "Points", "Points", "", "", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); CAF_PDM_InitField (&showInactiveCells, "ShowInactiveCells", false, "Inactive Cells", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_activateUiAppendPointsCommand, "m_activateUiAppendPointsCommand", "", "", "", ""); - m_activateUiAppendPointsCommand.xmlCapability()->setIOWritable(false); - m_activateUiAppendPointsCommand.xmlCapability()->setIOReadable(false); - m_activateUiAppendPointsCommand.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); - m_activateUiAppendPointsCommand.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + CAF_PDM_InitFieldNoDefault(&m_activateAppendPointsCommand, "m_activateUiAppendPointsCommand", "", "", "", ""); + m_activateAppendPointsCommand.xmlCapability()->setIOWritable(false); + m_activateAppendPointsCommand.xmlCapability()->setIOReadable(false); + m_activateAppendPointsCommand.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + m_activateAppendPointsCommand.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); - m_activateUiAppendPointsCommand = false; + m_activateAppendPointsCommand = false; uiCapability()->setUiChildrenHidden(true); } @@ -131,14 +131,14 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateName(); } - if (changedField == &m_activateUiAppendPointsCommand) + if (changedField == &m_activateAppendPointsCommand) { updateActiveUiCommandFeature(); - m_activateUiAppendPointsCommand = false; + m_activateAppendPointsCommand = false; } - if (changedField == &m_userDefinedPolyline) + if (changedField == &m_userPolyline) { rebuildGeometryAndScheduleCreateDisplayModel(); } @@ -168,8 +168,8 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& } else if (type == CS_POLYLINE) { - uiOrdering.add(&m_userDefinedPolyline); - uiOrdering.add(&m_activateUiAppendPointsCommand); + geometryGroup->add(&m_userPolyline); + geometryGroup->add(&m_activateAppendPointsCommand); } caf::PdmUiGroup* optionsGroup = uiOrdering.addNewGroup("Options"); @@ -310,7 +310,7 @@ std::vector< std::vector > RimCrossSection::polyLines() const } else if (type == CS_POLYLINE) { - lines.push_back(m_userDefinedPolyline); + lines.push_back(m_userPolyline); } if (type == CS_WELL_PATH || type == CS_SIMULATION_WELL) @@ -500,7 +500,7 @@ void RimCrossSection::clipToReservoir(std::vector &polyLine) const //-------------------------------------------------------------------------------------------------- void RimCrossSection::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) { - if (field == &m_activateUiAppendPointsCommand) + if (field == &m_activateAppendPointsCommand) { caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); @@ -524,9 +524,9 @@ void RimCrossSection::defineEditorAttribute(const caf::PdmFieldHandle* field, QS //-------------------------------------------------------------------------------------------------- void RimCrossSection::appendPointToPolyLine(const cvf::Vec3d& point) { - m_userDefinedPolyline.v().push_back(point); + m_userPolyline.v().push_back(point); - m_userDefinedPolyline.uiCapability()->updateConnectedEditors(); + m_userPolyline.uiCapability()->updateConnectedEditors(); rebuildGeometryAndScheduleCreateDisplayModel(); } diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 81d5b5fedf..c72fded556 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -92,8 +92,8 @@ class RimCrossSection : public caf::PdmObject caf::PdmField m_branchIndex; caf::PdmField m_extentLength; - caf::PdmField< std::vector< cvf::Vec3d> > m_userDefinedPolyline; - caf::PdmField< bool > m_activateUiAppendPointsCommand; + caf::PdmField< std::vector< cvf::Vec3d> > m_userPolyline; + caf::PdmField< bool > m_activateAppendPointsCommand; RimEclipseWellCollection* simulationWellCollection(); void updateWellCenterline() const; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index f69f571034..7585d69061 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -19,45 +19,30 @@ #include "RiuViewerCommands.h" +#include "RicCommandFeature.h" #include "RicEclipsePropertyFilterNewExec.h" #include "RicGeoMechPropertyFilterNewExec.h" #include "RicRangeFilterNewExec.h" -#include "CrossSectionCommands/RicNewPolylineCrossSectionFeature.h" -#include "CrossSectionCommands/RicNewSimWellCrossSectionFeature.h" -#include "CrossSectionCommands/RicNewWellPathCrossSectionFeature.h" -#include "WellLogCommands/RicNewWellLogCurveExtractionFeature.h" -#include "WellLogCommands/RicNewWellLogFileCurveFeature.h" - #include "RigCaseData.h" +#include "RigFault.h" #include "RigFemPartCollection.h" #include "RigFemPartGrid.h" #include "RigGeoMechCaseData.h" -#include "RigTimeHistoryResultAccessor.h" -#include "RimCellRangeFilter.h" -#include "RimCellRangeFilterCollection.h" #include "RimContextCommandBuilder.h" #include "RimCrossSection.h" +#include "RimDefines.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" -#include "RimEclipsePropertyFilter.h" -#include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimFaultCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" -#include "RimGeoMechPropertyFilter.h" -#include "RimGeoMechPropertyFilterCollection.h" #include "RimGeoMechView.h" -#include "RimOilField.h" -#include "RimProject.h" -#include "RimView.h" #include "RimViewController.h" -#include "RimWellLogFile.h" #include "RimWellPath.h" -#include "RimWellPathCollection.h" #include "RiuMainWindow.h" #include "RiuSelectionColors.h" @@ -445,7 +430,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM if (!m_activeUiCommandFeature.isNull()) { - cvf::ref uiEventObj = new RicPolylineUiEvent(localIntersectionPoint); + cvf::ref uiEventObj = new RicLocalIntersectionUiEvent(localIntersectionPoint); if (m_activeUiCommandFeature->handleUiEvent(uiEventObj.p())) { From 3eade62961e5e6fcc75f23eaec6cec24574835d3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 13:23:11 +0100 Subject: [PATCH 175/290] (#641) Use checkable button for point input from viewer --- .../RicNewPolylineCrossSectionFeature.cpp | 20 +++--- .../ProjectDataModel/RimCrossSection.cpp | 62 ++++--------------- .../ProjectDataModel/RimCrossSection.h | 4 +- ApplicationCode/UserInterface/RiuViewer.cpp | 17 ----- ApplicationCode/UserInterface/RiuViewer.h | 3 - .../UserInterface/RiuViewerCommands.cpp | 23 +++---- .../UserInterface/RiuViewerCommands.h | 4 -- 7 files changed, 33 insertions(+), 100 deletions(-) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp index 114f8bf47a..a626f71209 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp @@ -89,15 +89,17 @@ bool RicNewPolylineCrossSectionFeature::handleUiEvent(cvf::Object* uiEventObject if (polylineUiEvent) { RimCrossSection* crossSection = selection[0]; + if (crossSection->inputFromViewerEnabled()) + { + RimCase* rimCase = NULL; + crossSection->firstAnchestorOrThisOfType(rimCase); + CVF_ASSERT(rimCase); - RimCase* rimCase = NULL; - crossSection->firstAnchestorOrThisOfType(rimCase); - CVF_ASSERT(rimCase); + crossSection->appendPointToPolyLine(rimCase->displayModelOffset() + polylineUiEvent->localIntersectionPoint); - crossSection->appendPointToPolyLine(rimCase->displayModelOffset() + polylineUiEvent->localIntersectionPoint); - - // Further Ui processing is stopped when true is returned - return true; + // Further Ui processing is stopped when true is returned + return true; + } } } @@ -138,9 +140,9 @@ void RicNewPolylineCrossSectionFeatureCmd::redo() RimCrossSection* crossSection = new RimCrossSection(); crossSection->name = "Polyline"; crossSection->type = RimCrossSection::CS_POLYLINE; - m_crossSectionCollection->appendCrossSection(crossSection); + crossSection->inputFromViewerEnabled = true; - crossSection->updateActiveUiCommandFeature(); + m_crossSectionCollection->appendCrossSection(crossSection); RiuSelectionManager::instance()->deleteAllItems(); diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 8cae73472d..5bfd82f743 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -86,13 +86,13 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); CAF_PDM_InitField (&showInactiveCells, "ShowInactiveCells", false, "Inactive Cells", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_activateAppendPointsCommand, "m_activateUiAppendPointsCommand", "", "", "", ""); - m_activateAppendPointsCommand.xmlCapability()->setIOWritable(false); - m_activateAppendPointsCommand.xmlCapability()->setIOReadable(false); - m_activateAppendPointsCommand.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); - m_activateAppendPointsCommand.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + CAF_PDM_InitFieldNoDefault(&inputFromViewerEnabled, "m_activateUiAppendPointsCommand", "", "", "", ""); + inputFromViewerEnabled.xmlCapability()->setIOWritable(false); + inputFromViewerEnabled.xmlCapability()->setIOReadable(false); + inputFromViewerEnabled.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + inputFromViewerEnabled.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); - m_activateAppendPointsCommand = false; + inputFromViewerEnabled = false; uiCapability()->setUiChildrenHidden(true); } @@ -131,11 +131,9 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateName(); } - if (changedField == &m_activateAppendPointsCommand) + if (changedField == &inputFromViewerEnabled) { - updateActiveUiCommandFeature(); - - m_activateAppendPointsCommand = false; + // TODO rebuild geo and div } if (changedField == &m_userPolyline) @@ -169,7 +167,7 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& else if (type == CS_POLYLINE) { geometryGroup->add(&m_userPolyline); - geometryGroup->add(&m_activateAppendPointsCommand); + geometryGroup->add(&inputFromViewerEnabled); } caf::PdmUiGroup* optionsGroup = uiOrdering.addNewGroup("Options"); @@ -221,7 +219,6 @@ QList RimCrossSection::calculateValueOptions(const caf:: { options.push_back(caf::PdmOptionItemInfo(eclWells[i]->name(), QVariant::fromValue(caf::PdmPointer(eclWells[i])), false, simWellIcon)); } - } if (options.size() == 0) @@ -500,21 +497,17 @@ void RimCrossSection::clipToReservoir(std::vector &polyLine) const //-------------------------------------------------------------------------------------------------- void RimCrossSection::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) { - if (field == &m_activateAppendPointsCommand) + if (field == &inputFromViewerEnabled) { caf::PdmUiPushButtonEditorAttribute* attrib = dynamic_cast (attribute); - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - CVF_ASSERT(rimView); - - if (rimView->viewer()->activeUiCommandFeature()) + if (inputFromViewerEnabled) { - attrib->m_buttonText = "End point input"; + attrib->m_buttonText = "Stop picking points"; } else { - attrib->m_buttonText = "Start point input"; + attrib->m_buttonText = "Start picking points"; } } } @@ -531,35 +524,6 @@ void RimCrossSection::appendPointToPolyLine(const cvf::Vec3d& point) rebuildGeometryAndScheduleCreateDisplayModel(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimCrossSection::updateActiveUiCommandFeature() -{ - RimView* rimView = NULL; - this->firstAnchestorOrThisOfType(rimView); - CVF_ASSERT(rimView); - - if (!rimView->viewer()) return; - - if (rimView->viewer()->activeUiCommandFeature()) - { - rimView->viewer()->setActiveUiCommandFeature(NULL); - } - else - { - caf::CmdFeature* cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicNewPolylineCrossSectionFeature"); - CVF_ASSERT(cmdFeature); - - RicCommandFeature* riCommandFeature = dynamic_cast(cmdFeature); - CVF_ASSERT(riCommandFeature); - - rimView->viewer()->setActiveUiCommandFeature(riCommandFeature); - } - - updateConnectedEditors(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index c72fded556..64b8241c3b 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -70,11 +70,12 @@ class RimCrossSection : public caf::PdmObject caf::PdmPtrField wellPath; caf::PdmPtrField simulationWell; + caf::PdmField< bool > inputFromViewerEnabled; + std::vector< std::vector > polyLines() const; RivCrossSectionPartMgr* crossSectionPartMgr(); void appendPointToPolyLine(const cvf::Vec3d& point); - void updateActiveUiCommandFeature(); protected: virtual caf::PdmFieldHandle* userDescriptionField(); @@ -93,7 +94,6 @@ class RimCrossSection : public caf::PdmObject caf::PdmField m_extentLength; caf::PdmField< std::vector< cvf::Vec3d> > m_userPolyline; - caf::PdmField< bool > m_activateAppendPointsCommand; RimEclipseWellCollection* simulationWellCollection(); void updateWellCenterline() const; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 4417adbc06..4be74f84ea 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -649,20 +649,3 @@ cvf::Color3f RiuViewer::computeContrastColor() const return contrastColor; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewer::setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature) -{ - CVF_ASSERT(m_viewerCommands); - m_viewerCommands->setActiveUiCommandFeature(uiCommandFeature); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicCommandFeature* RiuViewer::activeUiCommandFeature() const -{ - return m_viewerCommands->activeUiCommandFeature(); -} diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 4cd8cda7a5..97dc692686 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -89,9 +89,6 @@ class RiuViewer : public caf::Viewer void setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel); - void setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature); - RicCommandFeature* activeUiCommandFeature() const; - public slots: virtual void slotSetCurrentFrame(int frameIndex); virtual void slotEndAnimation(); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 7585d69061..fcc21b805a 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -57,6 +57,7 @@ #include "RivWellPipeSourceInfo.h" #include "cafCmdExecCommandManager.h" +#include "cafCmdFeatureManager.h" #include "cafPdmUiTreeView.h" #include "cafSelectionManager.h" @@ -83,7 +84,13 @@ RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) m_currentGridIdx(-1), m_currentCellIndex(-1) { + caf::CmdFeature* cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicNewPolylineCrossSectionFeature"); + CVF_ASSERT(cmdFeature); + RicCommandFeature* riCommandFeature = dynamic_cast(cmdFeature); + CVF_ASSERT(riCommandFeature); + + m_activeUiCommandFeature = riCommandFeature; } //-------------------------------------------------------------------------------------------------- @@ -563,22 +570,6 @@ void RiuViewerCommands::findCellAndGridIndex(const RivCrossSectionSourceInfo* cr } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature) -{ - m_activeUiCommandFeature = uiCommandFeature; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicCommandFeature* RiuViewerCommands::activeUiCommandFeature() const -{ - return m_activeUiCommandFeature; -} - //-------------------------------------------------------------------------------------------------- /// Perform picking and return the index of the face that was hit, if a drawable geo was hit //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 40c61dc8bd..ab2e117266 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -55,10 +55,6 @@ class RiuViewerCommands: public QObject void findCellAndGridIndex(const RivCrossSectionSourceInfo* crossSectionSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex); - void setActiveUiCommandFeature(RicCommandFeature* uiCommandFeature); - RicCommandFeature* activeUiCommandFeature() const; - - private slots: void slotRangeFilterI(); void slotRangeFilterJ(); From dc03844a55b3befbbb2b05e4c18f32abbb241ca1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 13:54:56 +0100 Subject: [PATCH 176/290] (#641) Added polyline point visualization --- .../RivCrossSectionGeometryGenerator.cpp | 34 ++++++++++ .../RivCrossSectionGeometryGenerator.h | 1 + .../RivCrossSectionPartMgr.cpp | 65 +++++++++++++++++-- .../RivCrossSectionPartMgr.h | 2 + .../ProjectDataModel/RimCrossSection.cpp | 8 +-- .../RimCrossSectionCollection.cpp | 5 ++ 6 files changed, 104 insertions(+), 11 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index a24be7c6a9..03797b15bb 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1194,6 +1194,40 @@ cvf::ref RivCrossSectionGeometryGenerator::createLineAlongPoly return polylineGeo; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivCrossSectionGeometryGenerator::createPointsFromPolylineDrawable() +{ + std::vector vertices; + + cvf::Vec3d displayOffset = m_hexGrid->displayOffset(); + + for (size_t pLineIdx = 0; pLineIdx < m_polyLines.size(); ++pLineIdx) + { + const std::vector& m_polyLine = m_polyLines[pLineIdx]; + for (size_t i = 0; i < m_polyLine.size(); ++i) + { + vertices.push_back(cvf::Vec3f(m_polyLine[i] - displayOffset)); + } + } + + if (vertices.size() == 0) return NULL; + + cvf::ref primSet = new cvf::PrimitiveSetDirect(cvf::PT_POINTS); + primSet->setStartIndex(0); + primSet->setIndexCount(vertices.size()); + + cvf::ref geo = new cvf::DrawableGeo; + + cvf::ref vx = new cvf::Vec3fArray(vertices); + geo->setVertexArray(vx.p()); + geo->addPrimitiveSet(primSet.p()); + + return geo; +} + + //-------------------------------------------------------------------------------------------------- /// Remove the lines from the polyline that is nearly parallel to the extrusion direction //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index 39acac96ee..ae65f3bc35 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -142,6 +142,7 @@ class RivCrossSectionGeometryGenerator : public cvf::Object cvf::ref generateSurface(); cvf::ref createMeshDrawable(); cvf::ref createLineAlongPolylineDrawable(); + cvf::ref createPointsFromPolylineDrawable(); // Mapping between cells and geometry const std::vector& triangleToCellIndex() const; diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index b199afa52c..d24ec8008c 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -48,6 +48,7 @@ #include "cvfPrimitiveSetDirect.h" #include "cvfRenderState_FF.h" #include "cvfRenderStateDepth.h" +#include "cvfRenderStatePoint.h" //-------------------------------------------------------------------------------------------------- @@ -342,18 +343,56 @@ void RivCrossSectionPartMgr::generatePartGeometry() } // Highlight line + + m_highlightLineAlongPolyline = NULL; + m_highlightPointsForPolyline = NULL; + + if (m_rimCrossSection->type == RimCrossSection::CS_POLYLINE) { - cvf::ref polylineGeo = m_crossSectionGenerator->createLineAlongPolylineDrawable(); - if (polylineGeo.notNull()) + { + cvf::ref polylineGeo = m_crossSectionGenerator->createLineAlongPolylineDrawable(); + if (polylineGeo.notNull()) + { + if (useBufferObjects) + { + polylineGeo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); + } + + cvf::ref part = new cvf::Part; + part->setName("Cross Section Polyline"); + part->setDrawable(polylineGeo.p()); + + part->updateBoundingBox(); + part->setPriority(10000); + + // Always show this part, also when mesh is turned off + //part->setEnableMask(meshFaultBit); + + cvf::ref eff; + caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); + eff = lineEffGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + + part->setEffect(eff.p()); + + m_highlightLineAlongPolyline = part; + } + } + + cvf::ref polylinePointsGeo = m_crossSectionGenerator->createPointsFromPolylineDrawable(); + if (polylinePointsGeo.notNull()) { if (useBufferObjects) { - polylineGeo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); + polylinePointsGeo->setRenderMode(cvf::DrawableGeo::BUFFER_OBJECT); } cvf::ref part = new cvf::Part; part->setName("Cross Section Polyline"); - part->setDrawable(polylineGeo.p()); + part->setDrawable(polylinePointsGeo.p()); part->updateBoundingBox(); part->setPriority(10000); @@ -369,9 +408,13 @@ void RivCrossSectionPartMgr::generatePartGeometry() depth->enableDepthTest(false); eff->setRenderState(depth.p()); + cvf::ref pointRendState = new cvf::RenderStatePoint(cvf::RenderStatePoint::FIXED_SIZE); + pointRendState->setSize(5.0f); + eff->setRenderState(pointRendState.p()); + part->setEffect(eff.p()); - m_highlightLineAlongPolyline = part; + m_highlightPointsForPolyline = part; } } @@ -443,12 +486,24 @@ void RivCrossSectionPartMgr::appendMeshLinePartsToModel(cvf::ModelBasicList* mod m_crossSectionGridLines->setTransform(scaleTransform); model->addPart(m_crossSectionGridLines.p()); } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivCrossSectionPartMgr::appendPolylinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform) +{ if (m_highlightLineAlongPolyline.notNull()) { m_highlightLineAlongPolyline->setTransform(scaleTransform); model->addPart(m_highlightLineAlongPolyline.p()); } + if (m_highlightPointsForPolyline.notNull()) + { + m_highlightPointsForPolyline->setTransform(scaleTransform); + model->addPart(m_highlightPointsForPolyline.p()); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h index 3bb2db294d..979145f058 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.h @@ -55,6 +55,7 @@ class RivCrossSectionPartMgr : public cvf::Object void appendNativeCrossSectionFacesToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); void appendMeshLinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); + void appendPolylinePartsToModel(cvf::ModelBasicList* model, cvf::Transform* scaleTransform); private: void updatePartEffect(); @@ -85,4 +86,5 @@ class RivCrossSectionPartMgr : public cvf::Object cvf::ref m_crossSectionFacesTextureCoords; cvf::ref m_highlightLineAlongPolyline; + cvf::ref m_highlightPointsForPolyline; }; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 5bfd82f743..e77728cc81 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -131,12 +131,8 @@ void RimCrossSection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateName(); } - if (changedField == &inputFromViewerEnabled) - { - // TODO rebuild geo and div - } - - if (changedField == &m_userPolyline) + if (changedField == &inputFromViewerEnabled + || changedField == &m_userPolyline) { rebuildGeometryAndScheduleCreateDisplayModel(); } diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 7b8f54d3fb..1a1e5e6463 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -93,6 +93,11 @@ void RimCrossSectionCollection::appendPartsToModel(cvf::ModelBasicList* model, c { cs->crossSectionPartMgr()->appendNativeCrossSectionFacesToModel(model, scaleTransform); cs->crossSectionPartMgr()->appendMeshLinePartsToModel(model, scaleTransform); + + if (cs->inputFromViewerEnabled) + { + cs->crossSectionPartMgr()->appendPolylinePartsToModel(model, scaleTransform); + } } } } From 512701ce1101824ec75db71019926d3f42fe2a18 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 14:01:13 +0100 Subject: [PATCH 177/290] (#641) Hide extent lenth for polyline --- ApplicationCode/ProjectDataModel/RimCrossSection.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index e77728cc81..2ffece2102 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -172,6 +172,15 @@ void RimCrossSection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& optionsGroup->add(&m_extentLength); optionsGroup->add(&showInactiveCells); + if (type == CS_POLYLINE) + { + m_extentLength.uiCapability()->setUiReadOnly(true); + } + else + { + m_extentLength.uiCapability()->setUiReadOnly(false); + } + updateWellExtentDefaultValue(); uiOrdering.setForgetRemainingFields(true); From 709d993cc69aebe270b2289d925c4f06f56e8c2a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 30 Nov 2015 15:12:00 +0100 Subject: [PATCH 178/290] (#641) Use color in QListView to indicate input point mode --- .../ProjectDataModel/RimCrossSection.cpp | 9 ++++++ .../TapCvfSpecialization.cpp | 29 +++++++++++++++++++ .../TapCvfSpecialization.h | 7 +++++ .../cafUserInterface/cafPdmUiListEditor.cpp | 14 +++++++-- .../cafUserInterface/cafPdmUiListEditor.h | 11 +++++++ 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 2ffece2102..fbd2a71512 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -39,6 +39,7 @@ #include "cafCmdFeature.h" #include "cafCmdFeatureManager.h" +#include "cafPdmUiListEditor.h" #include "cafPdmUiPushButtonEditor.h" @@ -515,6 +516,14 @@ void RimCrossSection::defineEditorAttribute(const caf::PdmFieldHandle* field, QS attrib->m_buttonText = "Start picking points"; } } + else if (field == &m_userPolyline) + { + caf::PdmUiListEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr && inputFromViewerEnabled) + { + myAttr->m_baseColor.setRgb(255, 220, 255); + } + } } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index d11f8ae999..de8d1eef06 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -1,5 +1,7 @@ #include "TapCvfSpecialization.h" +#include "cafPdmUiListEditor.h" + CAF_PDM_SOURCE_INIT(TapCvfSpecialization, "TapCvfSpecialization"); @@ -20,3 +22,30 @@ TapCvfSpecialization::TapCvfSpecialization() m_vecArrayField.v().push_back(cvf::Vec3d(1, 2, 3)); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void TapCvfSpecialization::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &m_colorField) + { + updateConnectedEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void TapCvfSpecialization::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_vecArrayField) + { + caf::PdmUiListEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->m_backgroundColor.setRgbF(m_colorField().r(), m_colorField().g(), m_colorField().b()); + } + } +} + diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h index 6b3f9e994b..2ca8a1c269 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.h @@ -24,6 +24,7 @@ class TapCvfSpecialization : public caf::PdmObject TapCvfSpecialization(); + caf::PdmField m_testField; caf::PdmField m_colorField; @@ -31,5 +32,11 @@ class TapCvfSpecialization : public caf::PdmObject caf::PdmField m_matrixField; caf::PdmField< std::vector< cvf::Vec3d> > m_vecArrayField; + +public: + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + +protected: + virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp index e89f1fa61e..bbac77cfbf 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp @@ -139,9 +139,17 @@ void PdmUiListEditor::configureAndUpdateUi(const QString& uiConfigName) m_listView->setEnabled(!field()->isUiReadOnly(uiConfigName)); m_listView->setToolTip(field()->uiToolTip(uiConfigName)); - /// Demo code Not used yet - // PdmUiListEditorAttribute attributes; - // field()->ownerObject()->editorAttribute(field(), uiConfigName, &attributes); + PdmUiListEditorAttribute attributes; + caf::PdmUiObjectHandle* uiObject = uiObj(field()->fieldHandle()->ownerObject()); + if (uiObject) + { + uiObject->editorAttribute(field()->fieldHandle(), uiConfigName, &attributes); + + QPalette myPalette(m_listView->palette()); + myPalette.setColor(QPalette::Base, attributes.m_baseColor); + + m_listView->setPalette(myPalette); + } MyStringListModel* strListModel = dynamic_cast(m_model.data()); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h index a8530a14aa..47873ca306 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h @@ -54,6 +54,17 @@ namespace caf //================================================================================================== class PdmUiListEditorAttribute : public PdmUiEditorAttribute { +public: + PdmUiListEditorAttribute() + : m_baseColor(Qt::white) + { + QPalette myPalette; + + m_baseColor = myPalette.color(QPalette::Active, QPalette::Base); + } + +public: + QColor m_baseColor; }; From f07f9cba3e23e03af2aec9957753ba8a31b70041 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 12:34:10 +0100 Subject: [PATCH 179/290] (#641) Show empty label to make push button smaller --- ApplicationCode/ProjectDataModel/RimCrossSection.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index fbd2a71512..ea91c81377 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -91,7 +91,6 @@ RimCrossSection::RimCrossSection() inputFromViewerEnabled.xmlCapability()->setIOWritable(false); inputFromViewerEnabled.xmlCapability()->setIOReadable(false); inputFromViewerEnabled.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); - inputFromViewerEnabled.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); inputFromViewerEnabled = false; From 50cd9250c4f5fc1ed8598841434f85ba530b3fd1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 13:28:44 +0100 Subject: [PATCH 180/290] (#659) Sort well paths when downloading from SSI-hub --- .../RiuWellImportWizard.cpp | 37 +++++++++++++++++++ .../RiuWellImportWizard.h | 13 ++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp index 4a47a0aab9..e02b1115b3 100644 --- a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp +++ b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp @@ -890,6 +890,8 @@ void WellSelectionPage::buildWellTreeView() fieldGroup->objects.push_back(wellPathCopy); } + + sortObjectsByDescription(fieldGroup); } } } @@ -956,7 +958,42 @@ void WellSelectionPage::selectedWellPathEntries(std::vector& dow } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool lessByDescription(const caf::PdmPointer& obj1, const caf::PdmPointer& obj2) +{ + caf::PdmUiFieldHandle* uiFieldHandle1 = NULL; + caf::PdmUiFieldHandle* uiFieldHandle2 = NULL; + + if (obj1.notNull() && obj1->uiCapability() && obj1->uiCapability()->userDescriptionField()) + { + uiFieldHandle1 = obj1->uiCapability()->userDescriptionField()->uiCapability(); + } + + if (obj2.notNull() && obj2->uiCapability() && obj2->uiCapability()->userDescriptionField()) + { + uiFieldHandle2 = obj2->uiCapability()->userDescriptionField()->uiCapability(); + } + + if (uiFieldHandle1 && uiFieldHandle2) + { + QString string1 = uiFieldHandle1->uiValue().toString(); + QString string2 = uiFieldHandle2->uiValue().toString(); + + return string1 < string2; + } + + return true; +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void WellSelectionPage::sortObjectsByDescription(caf::PdmObjectCollection* objects) +{ + std::sort(objects->objects.begin(), objects->objects.end(), lessByDescription); +} //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h index 75ff77487d..92043c5cf4 100644 --- a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h +++ b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h @@ -131,15 +131,16 @@ class WellSelectionPage : public QWizardPage ~WellSelectionPage(); virtual void initializePage(); - void buildWellTreeView(); + void buildWellTreeView(); - - void selectedWellPathEntries(std::vector& downloadEntities, caf::PdmObjectHandle* objHandle); + void selectedWellPathEntries(std::vector& downloadEntities, caf::PdmObjectHandle* objHandle); +private: + void sortObjectsByDescription(caf::PdmObjectCollection* objects); private: - ObjectGroupWithHeaders* m_regionsWithVisibleWells; - RimWellPathImport* m_wellPathImportObject; - caf::PdmUiTreeView* m_wellSelectionTreeView; + ObjectGroupWithHeaders* m_regionsWithVisibleWells; + RimWellPathImport* m_wellPathImportObject; + caf::PdmUiTreeView* m_wellSelectionTreeView; }; From 3469c8bfb7da962784a7f1a32d31d4a089e726d4 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 05:19:49 -0800 Subject: [PATCH 181/290] Fixed missing include and signed/unsigned compare (Linux) --- ApplicationCode/ProjectDataModel/RimCrossSection.cpp | 6 +++--- .../WellPathImportSsihub/RiuWellImportWizard.cpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index ea91c81377..5fb80f61a8 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -239,7 +239,7 @@ QList RimCrossSection::calculateValueOptions(const caf:: options.push_back(caf::PdmOptionItemInfo("All", -1)); - for (int bIdx = 0; bIdx < branchCount; ++bIdx) + for (size_t bIdx = 0; bIdx < branchCount; ++bIdx) { options.push_back(caf::PdmOptionItemInfo(QString::number(bIdx + 1), QVariant::fromValue(bIdx))); } @@ -299,7 +299,7 @@ std::vector< std::vector > RimCrossSection::polyLines() const { updateWellCenterline(); - if (0 <= m_branchIndex && m_branchIndex < m_wellBranchCenterlines.size()) + if (0 <= m_branchIndex && m_branchIndex < static_cast(m_wellBranchCenterlines.size())) { lines.push_back(m_wellBranchCenterlines[m_branchIndex]); } @@ -317,7 +317,7 @@ std::vector< std::vector > RimCrossSection::polyLines() const if (type == CS_WELL_PATH || type == CS_SIMULATION_WELL) { - for (int lIdx = 0; lIdx < lines.size(); ++lIdx) + for (size_t lIdx = 0; lIdx < lines.size(); ++lIdx) { std::vector& polyLine = lines[lIdx]; addExtents(polyLine); diff --git a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp index e02b1115b3..c2cbd9dddb 100644 --- a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp +++ b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp @@ -34,6 +34,7 @@ #include #include +#include //-------------------------------------------------------------------------------------------------- /// From 19d156e8ffb6bb35294244c9689b56c56efce6e0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 14:38:47 +0100 Subject: [PATCH 182/290] [Fwk] Fixed missing rename in test app --- .../cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp index de8d1eef06..b580788ea1 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/TapCvfSpecialization.cpp @@ -44,7 +44,7 @@ void TapCvfSpecialization::defineEditorAttribute(const caf::PdmFieldHandle* fiel caf::PdmUiListEditorAttribute* myAttr = dynamic_cast(attribute); if (myAttr) { - myAttr->m_backgroundColor.setRgbF(m_colorField().r(), m_colorField().g(), m_colorField().b()); + myAttr->m_baseColor.setRgbF(m_colorField().r(), m_colorField().g(), m_colorField().b()); } } } From 2f6bd07ff0da4607665c4a5bf2d04a5a44b56bca Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 15:25:06 +0100 Subject: [PATCH 183/290] (#641) Added support for copy / paste of points --- .../ProjectDataModel/RimCrossSection.cpp | 2 +- .../cafUserInterface/cafPdmUiListEditor.cpp | 67 +++++++++++++++++-- .../cafUserInterface/cafPdmUiListEditor.h | 4 ++ 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index 5fb80f61a8..dfb0d01450 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -82,7 +82,7 @@ RimCrossSection::RimCrossSection() CAF_PDM_InitFieldNoDefault(&direction, "Direction", "Direction", "", "", ""); CAF_PDM_InitFieldNoDefault(&wellPath, "WellPath", "Well Path ", "", "", ""); CAF_PDM_InitFieldNoDefault(&simulationWell, "SimulationWell", "Simulation Well", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_userPolyline, "Points", "Points", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_userPolyline, "Points", "Points", "", "Use Ctrl-C for copy and Ctrl-V for paste", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent length", "", "", ""); CAF_PDM_InitField (&showInactiveCells, "ShowInactiveCells", false, "Inactive Cells", "", "", ""); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp index bbac77cfbf..3e0a52dd53 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp @@ -44,18 +44,21 @@ #include "cafFactory.h" -#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include -#include #include -#include +#include #include -#include -#include + //================================================================================================== /// Helper class used to override flags to disable editable items @@ -312,6 +315,33 @@ void PdmUiListEditor::slotListItemEdited(const QModelIndex&, const QModelIndex&) this->setValueToField(result); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString PdmUiListEditor::contentAsString() const +{ + QString str; + + if (m_model) + { + QStringList uiList = m_model->stringList(); + + str = uiList.join("\n"); + } + + return str; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiListEditor::pasteFromString(const QString& content) +{ + QStringList strList = content.split("\n"); + + this->setValueToField(strList); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -349,6 +379,31 @@ bool PdmUiListEditor::eventFilter(QObject * listView, QEvent * event) } return true; } + else if (keyEv->modifiers() & Qt::ControlModifier) + { + if (keyEv->key() == Qt::Key_C) + { + QClipboard* clipboard = QApplication::clipboard(); + if (clipboard) + { + QString content = contentAsString(); + clipboard->setText(content); + + return true; + } + } + else if (keyEv->key() == Qt::Key_V) + { + QClipboard* clipboard = QApplication::clipboard(); + if (clipboard) + { + QString content = clipboard->text(); + pasteFromString(content); + + return true; + } + } + } } return false; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h index 47873ca306..b68133c632 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h @@ -90,6 +90,10 @@ protected slots: void slotSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); void slotListItemEdited(const QModelIndex&, const QModelIndex&); +private: + QString contentAsString() const; + void pasteFromString(const QString& content); + private: QPointer m_listView; QPointer m_label; From 1150b122134a9824dbf65a16526ba71ca049ff97 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 1 Dec 2015 16:22:18 +0100 Subject: [PATCH 184/290] (#532) WLP: Added line thickness --- .../ProjectDataModel/RimWellLogCurve.cpp | 40 +++++++++++++++++-- .../ProjectDataModel/RimWellLogCurve.h | 3 ++ .../RimWellLogExtractionCurve.cpp | 4 ++ .../ProjectDataModel/RimWellLogFileCurve.cpp | 4 ++ 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 1ff66f5720..8cb9543277 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -26,6 +26,8 @@ #include "RiuLineSegmentQwtPlotCurve.h" #include "RiuWellLogTrack.h" +#include "cafPdmUiComboBoxEditor.h" + #include "cvfAssert.h" // NB! Special macro for pure virtual class @@ -49,6 +51,9 @@ RimWellLogCurve::RimWellLogCurve() CAF_PDM_InitField(&m_curveColor, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", ""); + CAF_PDM_InitField(&m_curveThickness, "Thickness", 1.0f, "Thickness", "", "", ""); + m_curveThickness.uiCapability()->setUiEditorTypeName(caf::PdmUiComboBoxEditor::uiEditorTypeName()); + m_qwtPlotCurve = new RiuLineSegmentQwtPlotCurve; m_qwtPlotCurve->setXAxis(QwtPlot::xTop); m_qwtPlotCurve->setYAxis(QwtPlot::yLeft); @@ -84,9 +89,10 @@ void RimWellLogCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, m_customCurveName = m_curveName; updatePlotTitle(); } - else if (&m_curveColor == changedField) + else if (&m_curveColor == changedField + || &m_curveThickness == changedField) { - m_qwtPlotCurve->setPen(QPen(QColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()))); + updateCurvePen(); } else if (changedField == &m_autoName) { @@ -150,7 +156,7 @@ void RimWellLogCurve::updatePlotConfiguration() this->updateCurveName(); this->updatePlotTitle(); - m_qwtPlotCurve->setPen(QPen(QColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()))); + updateCurvePen(); // Todo: Rest of the curve setup controlled from this class } @@ -312,3 +318,31 @@ const RigWellLogCurveData* RimWellLogCurve::curveData() const { return m_curveData.p(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogCurve::updateCurvePen() +{ + CVF_ASSERT(m_qwtPlotCurve); + m_qwtPlotCurve->setPen(QColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()), m_curveThickness); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimWellLogCurve::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_curveThickness) + { + for (size_t i = 0; i < 10; i++) + { + options.push_back(caf::PdmOptionItemInfo(QString::number(i + 1), QVariant::fromValue(i + 1))); + } + } + + return options; +} + diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index c7ff0a6e43..b1966c0ea0 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -73,12 +73,14 @@ class RimWellLogCurve : public caf::PdmObject void updateCurveVisibility(); void zoomAllOwnerTrackAndPlot(); void updateOptionSensitivity(); + void updateCurvePen(); // Overridden PDM methods virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); virtual caf::PdmFieldHandle* objectToggleField(); virtual caf::PdmFieldHandle* userDescriptionField(); virtual void initAfterRead(); + virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly); QPointer m_ownerQwtTrack; @@ -91,4 +93,5 @@ class RimWellLogCurve : public caf::PdmObject caf::PdmField m_autoName; caf::PdmField m_curveColor; + caf::PdmField m_curveThickness; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index fc7ffc48cb..dbac2db4a9 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -271,6 +271,9 @@ QList RimWellLogExtractionCurve::calculateValueOptions(c { QList optionList; + optionList = RimWellLogCurve::calculateValueOptions(fieldNeedingOptions, useOptionsOnly); + if (optionList.size() > 0) return optionList; + if (fieldNeedingOptions == &m_wellPath) { RimProject* proj = RiaApplication::instance()->project(); @@ -360,6 +363,7 @@ void RimWellLogExtractionCurve::defineUiOrdering(QString uiConfigName, caf::PdmU caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); + appearanceGroup->add(&m_curveThickness); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); if (m_autoName) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index d7678531f8..51e746ed9c 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -169,6 +169,7 @@ void RimWellLogFileCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); + appearanceGroup->add(&m_curveThickness); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); } @@ -188,6 +189,9 @@ QList RimWellLogFileCurve::calculateValueOptions(const c { QList optionList; + optionList = RimWellLogCurve::calculateValueOptions(fieldNeedingOptions, useOptionsOnly); + if (optionList.size() > 0) return optionList; + if (fieldNeedingOptions == &m_wellPath) { RimProject* proj = RiaApplication::instance()->project(); From 219fdc66039a7d48527bc86bf9a98423356a677c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 1 Dec 2015 16:07:42 +0100 Subject: [PATCH 185/290] (#345) Well name alone on a line is now accepted. "#" and "--" at start of a line tags the line as comment Several lines of text between wells are handled. Last none-empty line is used as well name. --- .../RimWellPathCollection.cpp | 112 ++++++++++++------ 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp index d48ec74914..05a72d77a3 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathCollection.cpp @@ -402,14 +402,17 @@ void RifWellPathAsciiFileReader::readAllWellData(QString filePath) // Create the data container std::vector& fileWellDataArray = m_fileNameToWellDataGroupMap[filePath]; - + std::ifstream stream(filePath.toLatin1().data()); double x(HUGE_VAL), y(HUGE_VAL), tvd(HUGE_VAL), md(HUGE_VAL); - while(stream.good()) + bool hasReadWellPointInCurrentWell = false; + + while (stream.good()) { + // First check if we can read a number stream >> x; - if (stream.good()) + if (stream.good()) // If we can, assume this line is a well point entry { stream >> y >> tvd >> md; if (!stream.good()) @@ -424,7 +427,7 @@ void RifWellPathAsciiFileReader::readAllWellData(QString filePath) } else { - if (!fileWellDataArray.size() ) + if (!fileWellDataArray.size()) { fileWellDataArray.push_back(WellData()); fileWellDataArray.back().m_wellPathGeometry = new RigWellPath(); @@ -438,6 +441,8 @@ void RifWellPathAsciiFileReader::readAllWellData(QString filePath) y = HUGE_VAL; tvd = HUGE_VAL; md = HUGE_VAL; + + hasReadWellPointInCurrentWell = true; } } else @@ -448,50 +453,85 @@ void RifWellPathAsciiFileReader::readAllWellData(QString filePath) std::string line; std::getline(stream, line, '\n'); - size_t quoteStartIdx = line.find_first_of("'`´’‘"); - size_t quoteEndIdx = line.find_last_of("'`´’‘"); - - std::string wellName; - - if (quoteStartIdx < line.size() -1 ) + // Skip possible comment lines (-- is used in eclipse, so Haakon Høgstøl considered it smart to skip these here as well) + // The first "-" is eaten by the stream >> x above + if (line.find("-") == 0 || line.find("#") == 0) { - // Extract the text between the quotes - wellName = line.substr(quoteStartIdx + 1, quoteEndIdx - 1 - quoteStartIdx); + // Comment line, just ignore } - else if (quoteStartIdx > line.length() && quoteEndIdx > line.length()) + else { - // Did not find any quotes - // Supported alternatives are - // name WellNameA - // wellname: WellNameA - std::string lineLowerCase = line; - transform(lineLowerCase.begin(), lineLowerCase.end(), lineLowerCase.begin(), ::tolower ); - - std::string tokenName = "name"; - std::size_t foundNameIdx = lineLowerCase.find(tokenName); - if (foundNameIdx != std::string::npos) + // Find the first and the last position of any quotes (and do not care to match quotes) + size_t quoteStartIdx = line.find_first_of("'`´’‘"); + size_t quoteEndIdx = line.find_last_of("'`´’‘"); + + std::string wellName; + bool haveAPossibleWellStart = false; + + if (quoteStartIdx < line.size() -1) + { + // Extract the text between the quotes + wellName = line.substr(quoteStartIdx + 1, quoteEndIdx - 1 - quoteStartIdx); + haveAPossibleWellStart = true; + } + else if (quoteStartIdx > line.length()) { - std::string tokenColon = ":"; - std::size_t foundColonIdx = lineLowerCase.find(tokenColon, foundNameIdx); - if (foundColonIdx != std::string::npos) + // We did not find any quotes + + // Supported alternatives are + // name + // wellname: + std::string lineLowerCase = line; + transform(lineLowerCase.begin(), lineLowerCase.end(), lineLowerCase.begin(), ::tolower); + + std::string tokenName = "name"; + std::size_t foundNameIdx = lineLowerCase.find(tokenName); + if (foundNameIdx != std::string::npos) { - wellName = line.substr(foundColonIdx + tokenColon.length()); + std::string tokenColon = ":"; + std::size_t foundColonIdx = lineLowerCase.find(tokenColon, foundNameIdx); + if (foundColonIdx != std::string::npos) + { + wellName = line.substr(foundColonIdx + tokenColon.length()); + } + else + { + wellName = line.substr(foundNameIdx + tokenName.length()); + } + + haveAPossibleWellStart = true; } else { - wellName = line.substr(foundNameIdx + tokenName.length()); + // Interpret the whole line as the well name. + + QString name = line.c_str(); + if (!name.trimmed().isEmpty()) + { + wellName = name.trimmed().toStdString(); + haveAPossibleWellStart = true; + } } } - } - if (wellName.size() > 0) - { - // Create a new Well data - fileWellDataArray.push_back(WellData()); - fileWellDataArray.back().m_wellPathGeometry = new RigWellPath(); + if (haveAPossibleWellStart) + { + // Create a new Well data if we have read some data into the previous one. + // if not, just overwrite the name + if (hasReadWellPointInCurrentWell || fileWellDataArray.size() == 0) + { + fileWellDataArray.push_back(WellData()); + fileWellDataArray.back().m_wellPathGeometry = new RigWellPath(); + } - QString name = wellName.c_str(); - fileWellDataArray.back().m_name = name.trimmed(); + QString name = wellName.c_str(); + if (!name.trimmed().isEmpty()) + { + // Do not overwrite the name aquired from a line above, if this line is empty + fileWellDataArray.back().m_name = name.trimmed(); + } + hasReadWellPointInCurrentWell = false; + } } } } From dac0db0fb94a73c505e832aebd5517aa09066df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 1 Dec 2015 16:51:51 +0100 Subject: [PATCH 186/290] (#654) Added autoscale toggle to WellLog Tracks. --- .../Commands/RicDeleteItemExec.cpp | 2 +- .../ProjectDataModel/RimWellLogTrack.cpp | 21 ++++++++++++++++--- .../ProjectDataModel/RimWellLogTrack.h | 3 ++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 30db7a11a3..5df31a61d5 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -132,7 +132,7 @@ void RicDeleteItemExec::redo() parentObj->firstAnchestorOrThisOfType(wellLogPlotTrack); if (wellLogPlotTrack) { - wellLogPlotTrack->zoomAllXAxis(); + wellLogPlotTrack->zoomAllXAxisIfAutoScale(); } // Update due to delete plots diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 8532280db0..758e78eb3c 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -54,7 +54,9 @@ RimWellLogTrack::RimWellLogTrack() curves.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&m_visibleXRangeMin, "VisibleXRangeMin", RI_LOGPLOTTRACK_MINX_DEFAULT, "Min", "", "", ""); - CAF_PDM_InitField(&m_visibleXRangeMax, "VisibleXRangeMax", RI_LOGPLOTTRACK_MAXX_DEFAULT, "Max", "", "", ""); + CAF_PDM_InitField(&m_visibleXRangeMax, "VisibleXRangeMax", RI_LOGPLOTTRACK_MAXX_DEFAULT, "Max", "", "", ""); + + CAF_PDM_InitField(&m_isAutoScaleXEnabled, "AutoScaleX", true, "Auto Scale", "", "", ""); } //-------------------------------------------------------------------------------------------------- @@ -98,6 +100,15 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, { m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); m_wellLogTrackPlotWidget->replot(); + m_isAutoScaleXEnabled = false; + } + else if (changedField == &m_isAutoScaleXEnabled ) + { + if (m_isAutoScaleXEnabled()) + { + this->zoomAllXAxisIfAutoScale(); + if (m_wellLogTrackPlotWidget) m_wellLogTrackPlotWidget->replot(); + } } } @@ -260,7 +271,7 @@ void RimWellLogTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() wellLogPlot->zoomAllDepth(); } - zoomAllXAxis(); + zoomAllXAxisIfAutoScale(); m_wellLogTrackPlotWidget->replot(); } @@ -269,8 +280,10 @@ void RimWellLogTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::zoomAllXAxis() +void RimWellLogTrack::zoomAllXAxisIfAutoScale() { + if (!m_isAutoScaleXEnabled()) return; + double minValue = HUGE_VAL; double maxValue = -HUGE_VAL; @@ -331,8 +344,10 @@ void RimWellLogTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering.add(&m_userName); caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Visible X Axis Range"); + gridGroup->add(&m_isAutoScaleXEnabled); gridGroup->add(&m_visibleXRangeMin); gridGroup->add(&m_visibleXRangeMax); + } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index b15b3cf7b7..1f9b615978 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -58,7 +58,7 @@ class RimWellLogTrack : public caf::PdmObject void availableDepthRange(double* minimumDepth, double* maximumDepth); void zoomAllXAndZoomAllDepthOnOwnerPlot(); - void zoomAllXAxis(); + void zoomAllXAxisIfAutoScale(); RiuWellLogTrack* viewer(); @@ -79,6 +79,7 @@ class RimWellLogTrack : public caf::PdmObject caf::PdmChildArrayField curves; caf::PdmField m_visibleXRangeMin; caf::PdmField m_visibleXRangeMax; + caf::PdmField m_isAutoScaleXEnabled; QPointer m_wellLogTrackPlotWidget; }; From 8047b9e92e5359b3070cf86eec2fc8b1aeaffdee Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 08:29:28 +0100 Subject: [PATCH 187/290] (#617) Improved wheel zoom on curves The scroll bar was updated as part of the wheel zoom event, and a signal from this update caused a panning of the curve --- ApplicationCode/UserInterface/RiuWellLogPlot.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index d3e88d8720..2ffc6f003d 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -199,11 +199,15 @@ void RiuWellLogPlot::updateScrollBar(double minDepth, double maxDepth) double visibleDepth = maxDepth - minDepth; - m_scrollBar->setRange((int) availableMinDepth, (int) (ceil(availableMaxDepth - visibleDepth))); - m_scrollBar->setPageStep((int) visibleDepth); - m_scrollBar->setValue((int) minDepth); + m_scrollBar->blockSignals(true); + { + m_scrollBar->setRange((int) availableMinDepth, (int) (ceil(availableMaxDepth - visibleDepth))); + m_scrollBar->setPageStep((int) visibleDepth); + m_scrollBar->setValue((int) minDepth); - m_scrollBar->setVisible(true); + m_scrollBar->setVisible(true); + } + m_scrollBar->blockSignals(false); } //-------------------------------------------------------------------------------------------------- From aebf776408052ddfa8e92bb2654cdb8d482b950e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 10:32:59 +0100 Subject: [PATCH 188/290] (#164) Sort parameter list for cell results --- .../RimEclipseFaultColors.cpp | 8 ---- .../ProjectDataModel/RimEclipseFaultColors.h | 2 - .../RimEclipseResultDefinition.cpp | 48 ++++++++++++------- .../RimEclipseResultDefinition.h | 10 ++-- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp index d72b46d636..7a28274b07 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp @@ -123,14 +123,6 @@ void RimEclipseFaultColors::defineUiOrdering(QString uiConfigName, caf::PdmUiOrd group1->add(&(m_customFaultResultColors->m_resultVariableUiField)); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList RimEclipseFaultColors::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) -{ - return m_customFaultResultColors->calculateValueOptionsForSpecifiedDerivedListPosition(true, fieldNeedingOptions, useOptionsOnly); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.h b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.h index 96e0c411f0..1e821228f4 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.h @@ -48,8 +48,6 @@ class RimEclipseFaultColors : public caf::PdmObject void updateFieldVisibility(); - virtual QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly ); - protected: virtual void initAfterRead(); virtual caf::PdmFieldHandle* objectToggleField(); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp index 7d59856114..b21398df1f 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -192,7 +192,13 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha //-------------------------------------------------------------------------------------------------- QList RimEclipseResultDefinition::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) { - QList optionItems = calculateValueOptionsForSpecifiedDerivedListPosition(false, fieldNeedingOptions, useOptionsOnly); + bool showPerFaceResultsFirst = false; + + RimEclipseFaultColors* rimEclipseFaultColors = NULL; + this->firstAnchestorOrThisOfType(rimEclipseFaultColors); + if (rimEclipseFaultColors) showPerFaceResultsFirst = true; + + QList optionItems = calculateValueOptionsForSpecifiedDerivedListPosition(showPerFaceResultsFirst, fieldNeedingOptions, useOptionsOnly); RimWellLogCurve* curve = NULL; this->firstAnchestorOrThisOfType(curve); @@ -215,42 +221,53 @@ QList RimEclipseResultDefinition::calculateValueOptionsF { if (this->currentGridCellResults()) { - QStringList varList = getResultVariableListForCurrentUIFieldSettings(); - QList optionList; - QList perCellFaceOptionList; - for (int i = 0; i < varList.size(); ++i) + + QStringList cellCenterResultNames; + QStringList cellFaceResultNames; + + foreach(QString s, getResultVariableListForCurrentUIFieldSettings()) { - if (RimDefines::isPerCellFaceResult(varList[i])) + if (RimDefines::isPerCellFaceResult(s)) { - // Move combined per cell face results to top of list - perCellFaceOptionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i])); + cellFaceResultNames.push_back(s); } else { - optionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i])); + cellCenterResultNames.push_back(s); } } + cellCenterResultNames.sort(); + cellFaceResultNames.sort(); + + // Cell Center result names + foreach(QString s, cellCenterResultNames) + { + optionList.push_back(caf::PdmOptionItemInfo(s, s)); + } + + // Ternary Result bool hasAtLeastOneTernaryComponent = false; - if (varList.contains("SOIL")) hasAtLeastOneTernaryComponent = true; - else if (varList.contains("SGAS")) hasAtLeastOneTernaryComponent = true; - else if (varList.contains("SWAT")) hasAtLeastOneTernaryComponent = true; + if (cellCenterResultNames.contains("SOIL")) hasAtLeastOneTernaryComponent = true; + else if (cellCenterResultNames.contains("SGAS")) hasAtLeastOneTernaryComponent = true; + else if (cellCenterResultNames.contains("SWAT")) hasAtLeastOneTernaryComponent = true; if (m_resultTypeUiField == RimDefines::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent) { optionList.push_front(caf::PdmOptionItemInfo(RimDefines::ternarySaturationResultName(), RimDefines::ternarySaturationResultName())); } - for (int i = 0; i < perCellFaceOptionList.size(); i++) + // Cell Face result names + foreach(QString s, cellFaceResultNames) { if (showDerivedResultsFirstInList) { - optionList.push_front(perCellFaceOptionList[i]); + optionList.push_front(caf::PdmOptionItemInfo(s, s)); } else { - optionList.push_back(perCellFaceOptionList[i]); + optionList.push_back(caf::PdmOptionItemInfo(s, s)); } } @@ -295,7 +312,6 @@ void RimEclipseResultDefinition::loadResult() updateFieldVisibility(); } - //-------------------------------------------------------------------------------------------------- /// Returns whether the result requested by the definition is a single frame result /// The result needs to be loaded before asking diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h index 3e8606fcbd..aad514465a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h @@ -81,16 +81,12 @@ class RimEclipseResultDefinition : public caf::PdmObject caf::PdmPointer m_eclipseCase; - protected: void updateFieldVisibility(); - QList calculateValueOptionsForSpecifiedDerivedListPosition(bool showDerivedResultsFirstInList, const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); - - - private: - QStringList getResultVariableListForCurrentUIFieldSettings(); - static void removePerCellFaceOptionItems(QList& optionItems); + QList calculateValueOptionsForSpecifiedDerivedListPosition(bool showDerivedResultsFirstInList, const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly); + QStringList getResultVariableListForCurrentUIFieldSettings(); + static void removePerCellFaceOptionItems(QList& optionItems); }; From fa83513ac60e67392f734e6c4f39fcc6a108aa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 2 Dec 2015 12:22:19 +0100 Subject: [PATCH 189/290] Made scrollbar inactive on zoom all. Made zoom all depth show the endpoint of the plot. --- ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp | 2 +- ApplicationCode/UserInterface/RiuWellLogPlot.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index b2627f34b4..6ca6fd7bc7 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -432,7 +432,7 @@ void RimWellLogPlot::zoomAllDepth() { if (hasAvailableDepthRange()) { - setDepthZoomMinMax(m_minAvailableDepth, m_maxAvailableDepth); + setDepthZoomMinMax(m_minAvailableDepth, m_maxAvailableDepth + 0.01*(m_maxAvailableDepth - m_minAvailableDepth)); } else { diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index 2ffc6f003d..55d939628b 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -196,12 +196,13 @@ void RiuWellLogPlot::updateScrollBar(double minDepth, double maxDepth) double availableMinDepth; double availableMaxDepth; m_plotDefinition->availableDepthRange(&availableMinDepth, &availableMaxDepth); + availableMaxDepth += 0.01*(availableMaxDepth-availableMinDepth); double visibleDepth = maxDepth - minDepth; m_scrollBar->blockSignals(true); { - m_scrollBar->setRange((int) availableMinDepth, (int) (ceil(availableMaxDepth - visibleDepth))); + m_scrollBar->setRange((int) availableMinDepth, (int) ((availableMaxDepth - visibleDepth))); m_scrollBar->setPageStep((int) visibleDepth); m_scrollBar->setValue((int) minDepth); From 76a90b04c8518bb9ed37c89c2607fc60290e9947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 2 Dec 2015 13:58:10 +0100 Subject: [PATCH 190/290] (#616) Removed the legend scrollbars completely by keeping the legend with at required size. --- ApplicationCode/UserInterface/RiuWellLogPlot.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index 55d939628b..5438b41224 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -291,8 +291,8 @@ void RiuWellLogPlot::placeChildWidgets(int height, int width) realTrackWidth += 1; --trackWidthExtra; } - - m_legends[tIdx]->setGeometry(trackX, 0, realTrackWidth, maxLegendHeight); + int realLegendWidth = std::max(realTrackWidth, m_legends[tIdx]->sizeHint().width()); + m_legends[tIdx]->setGeometry(trackX, 0, realLegendWidth, maxLegendHeight); m_trackPlots[tIdx]->setGeometry(trackX, maxLegendHeight, realTrackWidth, trackHeight); trackX += realTrackWidth; @@ -301,7 +301,6 @@ void RiuWellLogPlot::placeChildWidgets(int height, int width) } if (m_scrollBar->isVisible()) m_scrollBar->setGeometry(trackX, maxLegendHeight, scrollBarWidth, trackHeight); - } //-------------------------------------------------------------------------------------------------- From fe261560bd1c5348d9fdd2ab9e40bf524033ad1a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 12:19:35 +0100 Subject: [PATCH 191/290] (#538) Added DepthUnitType enum containing meter and feet --- .../ProjectDataModel/RimDefines.cpp | 8 +++++++ ApplicationCode/ProjectDataModel/RimDefines.h | 6 +++++ .../RimWellLogExtractionCurve.cpp | 14 +++++++++-- .../ProjectDataModel/RimWellLogFileCurve.cpp | 4 ++-- .../RigWellLogCurveData.cpp | 15 +++++++++++- .../ReservoirDataModel/RigWellLogCurveData.h | 11 ++++++++- .../ReservoirDataModel/RigWellLogFile.cpp | 23 +++++++++++++++---- .../ReservoirDataModel/RigWellLogFile.h | 7 ++++-- 8 files changed, 76 insertions(+), 12 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimDefines.cpp b/ApplicationCode/ProjectDataModel/RimDefines.cpp index 56161163dd..6ac2275aaa 100644 --- a/ApplicationCode/ProjectDataModel/RimDefines.cpp +++ b/ApplicationCode/ProjectDataModel/RimDefines.cpp @@ -44,6 +44,14 @@ namespace caf setDefault(RimDefines::MATRIX_MODEL); } + template<> + void caf::AppEnum< RimDefines::DepthUnitType >::setUp() + { + addItem(RimDefines::UNIT_METER, "UNIT_METER", "Meter"); + addItem(RimDefines::UNIT_FEET, "UNIT_FEET", "Feet"); + + setDefault(RimDefines::UNIT_METER); + } } diff --git a/ApplicationCode/ProjectDataModel/RimDefines.h b/ApplicationCode/ProjectDataModel/RimDefines.h index 21c0addb60..609a6ceb49 100644 --- a/ApplicationCode/ProjectDataModel/RimDefines.h +++ b/ApplicationCode/ProjectDataModel/RimDefines.h @@ -71,5 +71,11 @@ class RimDefines static QString mockModelCustomized() { return "Result Mock Debug Model Customized"; } static QString mockModelBasicInputCase() { return "Input Mock Debug Model Simple"; } + enum DepthUnitType + { + UNIT_METER, + UNIT_FEET + }; + }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index dbac2db4a9..c360734832 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -199,6 +199,8 @@ void RimWellLogExtractionCurve::updatePlotData() std::vector measuredDepthValues; std::vector tvDepthValues; + RimDefines::DepthUnitType depthUnit = RimDefines::UNIT_METER; + if (eclExtractor.notNull()) { RimWellLogPlot* wellLogPlot; @@ -224,6 +226,14 @@ void RimWellLogExtractionCurve::updatePlotData() { eclExtractor->curveData(resAcc.p(), &values); } + + RigCaseData::UnitsType eclipseUnitsType = eclipseCase->reservoirData()->unitsType(); + if (eclipseUnitsType == RigCaseData::UNITS_FIELD) + { + // See https://github.com/OPM/ResInsight/issues/538 + + depthUnit = RimDefines::UNIT_FEET; + } } else if (geomExtractor.notNull()) // geomExtractor { @@ -247,11 +257,11 @@ void RimWellLogExtractionCurve::updatePlotData() { if (!tvDepthValues.size()) { - m_curveData->setValuesAndMD(values, measuredDepthValues, true); + m_curveData->setValuesAndMD(values, measuredDepthValues, depthUnit, true); } else { - m_curveData->setValuesWithTVD(values, measuredDepthValues, tvDepthValues); + m_curveData->setValuesWithTVD(values, measuredDepthValues, tvDepthValues, depthUnit); } } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index 51e746ed9c..d4468f9ea8 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -103,7 +103,7 @@ void RimWellLogFileCurve::updatePlotData() if (values.size() == depthValues.size()) { - m_curveData->setValuesAndMD(values, depthValues, false); + m_curveData->setValuesAndMD(values, depthValues, wellLogFile->depthUnit(), false); } } @@ -257,7 +257,7 @@ QString RimWellLogFileCurve::createCurveName() RigWellLogFile* wellLogFile = logFileInfo ? logFileInfo->wellLogFile() : NULL; if (wellLogFile) { - QString unitName = wellLogFile->wellLogChannelUnit(m_wellLogChannnelName); + QString unitName = wellLogFile->wellLogChannelUnitString(m_wellLogChannnelName); if (!unitName.isEmpty()) { txt += QString(" [%1]").arg(unitName); diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp index 79971dbcee..8bd6deae8a 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp @@ -32,6 +32,7 @@ RigWellLogCurveData::RigWellLogCurveData() { m_isExtractionCurve = false; + m_depthUnit = RimDefines::UNIT_METER; } //-------------------------------------------------------------------------------------------------- @@ -46,6 +47,7 @@ RigWellLogCurveData::~RigWellLogCurveData() //-------------------------------------------------------------------------------------------------- void RigWellLogCurveData::setValuesAndMD(const std::vector& xValues, const std::vector& measuredDepths, + RimDefines::DepthUnitType depthUnit, bool isExtractionCurve) { CVF_ASSERT(xValues.size() == measuredDepths.size()); @@ -53,6 +55,7 @@ void RigWellLogCurveData::setValuesAndMD(const std::vector& xValues, m_xValues = xValues; m_measuredDepths = measuredDepths; m_tvDepths.clear(); + m_depthUnit = depthUnit; // Disable depth value filtering is intended to be used for // extraction curve data @@ -66,13 +69,15 @@ void RigWellLogCurveData::setValuesAndMD(const std::vector& xValues, //-------------------------------------------------------------------------------------------------- void RigWellLogCurveData::setValuesWithTVD(const std::vector& xValues, const std::vector& measuredDepths, - const std::vector& tvDepths) + const std::vector& tvDepths, + RimDefines::DepthUnitType depthUnit) { CVF_ASSERT(xValues.size() == measuredDepths.size()); m_xValues = xValues; m_measuredDepths = measuredDepths; m_tvDepths = tvDepths; + m_depthUnit = depthUnit; // Always use value filtering when TVD is present m_isExtractionCurve = true; @@ -243,3 +248,11 @@ bool RigWellLogCurveData::calculateMDRange(double* minimumDepth, double* maximum return false; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimDefines::DepthUnitType RigWellLogCurveData::depthUnit() const +{ + return m_depthUnit; +} diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h index 6ce38c8026..a9e57fb749 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h @@ -19,6 +19,8 @@ #pragma once +#include "RimDefines.h" + #include "cvfBase.h" #include "cvfObject.h" @@ -37,15 +39,20 @@ class RigWellLogCurveData : public cvf::Object void setValuesAndMD(const std::vector& xValues, const std::vector& measuredDepths, + RimDefines::DepthUnitType depthUnit, bool isExtractionCurve); + void setValuesWithTVD(const std::vector& xValues, const std::vector& measuredDepths, - const std::vector& tvDepths ); + const std::vector& tvDepths, + RimDefines::DepthUnitType depthUnit); const std::vector& xValues() const; const std::vector& measuredDepths() const; bool calculateMDRange(double* minMD, double* maxMD) const; + RimDefines::DepthUnitType depthUnit() const; + std::vector xPlotValues() const; std::vector depthPlotValues() const; std::vector< std::pair > polylineStartStopIndices() const; @@ -63,5 +70,7 @@ class RigWellLogCurveData : public cvf::Object bool m_isExtractionCurve; std::vector< std::pair > m_intervalsOfContinousValidValues; + + RimDefines::DepthUnitType m_depthUnit; }; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index f481377698..f5eaed1157 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -172,7 +172,7 @@ std::vector RigWellLogFile::values(const QString& name) const if (m_wellLogFile->HasContLog(name.toStdString())) { - if (name == m_depthLogName && (depthUnit().toUpper() == "F" || depthUnit().toUpper() == "FT")) + if (name == m_depthLogName && (depthUnitString().toUpper() == "F" || depthUnitString().toUpper() == "FT")) { std::vector footValues = m_wellLogFile->GetContLog(name.toStdString()); @@ -207,7 +207,7 @@ std::vector RigWellLogFile::values(const QString& name) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RigWellLogFile::depthUnit() const +QString RigWellLogFile::depthUnitString() const { QString unit; @@ -223,7 +223,7 @@ QString RigWellLogFile::depthUnit() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RigWellLogFile::wellLogChannelUnit(const QString& wellLogChannelName) const +QString RigWellLogFile::wellLogChannelUnitString(const QString& wellLogChannelName) const { QString unit; @@ -234,7 +234,7 @@ QString RigWellLogFile::wellLogChannelUnit(const QString& wellLogChannelName) co } // Special handling of depth unit - we convert depth to meter - if (unit == depthUnit()) + if (unit == depthUnitString()) { return "m"; } @@ -298,3 +298,18 @@ bool RigWellLogFile::exportToLasFile(const RimWellLogCurve* curve, const QString return true; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimDefines::DepthUnitType RigWellLogFile::depthUnit() const +{ + RimDefines::DepthUnitType unitType = RimDefines::UNIT_METER; + + if (depthUnitString().toUpper() == "F" || depthUnitString().toUpper() == "FT") + { + unitType = RimDefines::UNIT_FEET; + } + + return unitType; +} diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h index 6db1694344..3d83d94f88 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h @@ -19,6 +19,8 @@ #pragma once +#include "RimDefines.h" + #include "cvfBase.h" #include "cvfObject.h" @@ -49,8 +51,9 @@ class RigWellLogFile : public cvf::Object std::vector depthValues() const; std::vector values(const QString& name) const; - QString depthUnit() const; - QString wellLogChannelUnit(const QString& wellLogChannelName) const; + QString depthUnitString() const; + QString wellLogChannelUnitString(const QString& wellLogChannelName) const; + RimDefines::DepthUnitType depthUnit() const; static bool exportToLasFile(const RimWellLogCurve* curve, const QString& fileName); From d18e8f7bd3d69eca8bb9bff81bbdf4b9221ad542 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 13:39:16 +0100 Subject: [PATCH 192/290] (#538) Added depth unit and conversion between meter and feet --- ApplicationCode/ProjectDataModel/RimDefines.h | 1 + .../RimWellLogExtractionCurve.cpp | 11 ++- .../ProjectDataModel/RimWellLogFileCurve.cpp | 8 ++- .../ProjectDataModel/RimWellLogPlot.cpp | 25 ++++++- .../ProjectDataModel/RimWellLogPlot.h | 9 ++- .../RigWellLogCurveData.cpp | 69 ++++++++++++++++++- .../ReservoirDataModel/RigWellLogCurveData.h | 8 ++- 7 files changed, 121 insertions(+), 10 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimDefines.h b/ApplicationCode/ProjectDataModel/RimDefines.h index 609a6ceb49..fa326307a2 100644 --- a/ApplicationCode/ProjectDataModel/RimDefines.h +++ b/ApplicationCode/ProjectDataModel/RimDefines.h @@ -77,5 +77,6 @@ class RimDefines UNIT_FEET }; + static double feetPerMeter() { return 3.2808399; } }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index c360734832..76a5dee24f 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -265,7 +265,16 @@ void RimWellLogExtractionCurve::updatePlotData() } } - m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues().data(), static_cast(m_curveData->xPlotValues().size())); + RimDefines::DepthUnitType displayUnit = RimDefines::UNIT_METER; + + RimWellLogPlot* wellLogPlot; + firstAnchestorOrThisOfType(wellLogPlot); + if (wellLogPlot) + { + displayUnit = wellLogPlot->depthUnit(); + } + + m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues(displayUnit).data(), static_cast(m_curveData->xPlotValues().size())); m_qwtPlotCurve->setLineSegmentStartStopIndices(m_curveData->polylineStartStopIndices()); zoomAllOwnerTrackAndPlot(); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index d4468f9ea8..d91c6bdbe2 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -114,7 +114,13 @@ void RimWellLogFileCurve::updatePlotData() } } - m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues().data(), static_cast(m_curveData->xPlotValues().size())); + RimDefines::DepthUnitType displayUnit = RimDefines::UNIT_METER; + if (wellLogPlot) + { + displayUnit = wellLogPlot->depthUnit(); + } + + m_qwtPlotCurve->setSamples(m_curveData->xPlotValues().data(), m_curveData->depthPlotValues(displayUnit).data(), static_cast(m_curveData->xPlotValues().size())); m_qwtPlotCurve->setLineSegmentStartStopIndices(m_curveData->polylineStartStopIndices()); zoomAllOwnerTrackAndPlot(); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index 6ca6fd7bc7..b4c2746ca9 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -66,6 +66,9 @@ RimWellLogPlot::RimWellLogPlot() caf::AppEnum< RimWellLogPlot::DepthTypeEnum > depthType = MEASURED_DEPTH; CAF_PDM_InitField(&m_depthType, "DepthType", depthType, "Depth type", "", "", ""); + caf::AppEnum< RimDefines::DepthUnitType > depthUnit = RimDefines::UNIT_METER; + CAF_PDM_InitField(&m_depthUnit, "DepthUnit", depthUnit, "Depth unit", "", "", ""); + CAF_PDM_InitField(&m_minVisibleDepth, "MinimumDepth", 0.0, "Min", "", "", ""); CAF_PDM_InitField(&m_maxVisibleDepth, "MaximumDepth", 1000.0, "Max", "", "", ""); @@ -150,7 +153,8 @@ void RimWellLogPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { updateViewerWidgetWindowTitle(); } - if (changedField == &m_depthType) + if (changedField == &m_depthType || + changedField == &m_depthUnit) { updateTracks(); } @@ -366,6 +370,7 @@ void RimWellLogPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& { uiOrdering.add(&m_userName); uiOrdering.add(&m_depthType); + uiOrdering.add(&m_depthUnit); caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Visible Depth Range"); gridGroup->add(&m_minVisibleDepth); @@ -509,6 +514,14 @@ RimWellLogPlot::DepthTypeEnum RimWellLogPlot::depthType() const return m_depthType.value(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimDefines::DepthUnitType RimWellLogPlot::depthUnit() const +{ + return m_depthUnit.value(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -527,7 +540,15 @@ QString RimWellLogPlot::depthPlotTitle() const break; } - depthTitle += " [m]"; + if (m_depthUnit == RimDefines::UNIT_METER) + { + depthTitle += " [m]"; + } + else if (m_depthUnit == RimDefines::UNIT_FEET) + { + depthTitle += " [ft]"; + } + return depthTitle; } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index 544c1befc3..1531926f2e 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -25,6 +25,7 @@ #include "cafAppEnum.h" #include +#include "RimDefines.h" class RiuWellLogPlot; class RimWellLogTrack; @@ -52,6 +53,7 @@ class RimWellLogPlot : public caf::PdmObject void setDescription(const QString& description); DepthTypeEnum depthType() const; + RimDefines::DepthUnitType depthUnit() const; QString depthPlotTitle() const; caf::PdmField< std::vector > windowGeometry; @@ -100,8 +102,11 @@ class RimWellLogPlot : public caf::PdmObject caf::PdmField m_showWindow; caf::PdmField m_userName; - caf::PdmField< caf::AppEnum< DepthTypeEnum > > m_depthType; - caf::PdmChildArrayField m_tracks; + + caf::PdmField< caf::AppEnum< DepthTypeEnum > > m_depthType; + caf::PdmField< caf::AppEnum< RimDefines::DepthUnitType > > m_depthUnit; + + caf::PdmChildArrayField m_tracks; caf::PdmField m_minVisibleDepth; caf::PdmField m_maxVisibleDepth; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp index 8bd6deae8a..f083080f67 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.cpp @@ -116,16 +116,32 @@ std::vector RigWellLogCurveData::xPlotValues() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RigWellLogCurveData::depthPlotValues() const +std::vector RigWellLogCurveData::depthPlotValues(RimDefines::DepthUnitType destinationDepthUnit) const { std::vector filteredValues; if (m_tvDepths.size()) { - RigCurveDataTools::getValuesByIntervals(m_tvDepths, m_intervalsOfContinousValidValues, &filteredValues); + if (destinationDepthUnit == m_depthUnit) + { + RigCurveDataTools::getValuesByIntervals(m_tvDepths, m_intervalsOfContinousValidValues, &filteredValues); + } + else + { + std::vector convertedValues = convertDepthValues(destinationDepthUnit, m_tvDepths); + RigCurveDataTools::getValuesByIntervals(convertedValues, m_intervalsOfContinousValidValues, &filteredValues); + } } else { - RigCurveDataTools::getValuesByIntervals(m_measuredDepths, m_intervalsOfContinousValidValues, &filteredValues); + if (destinationDepthUnit == m_depthUnit) + { + RigCurveDataTools::getValuesByIntervals(m_measuredDepths, m_intervalsOfContinousValidValues, &filteredValues); + } + else + { + std::vector convertedValues = convertDepthValues(destinationDepthUnit, m_measuredDepths); + RigCurveDataTools::getValuesByIntervals(convertedValues, m_intervalsOfContinousValidValues, &filteredValues); + } } return filteredValues; @@ -256,3 +272,50 @@ RimDefines::DepthUnitType RigWellLogCurveData::depthUnit() const { return m_depthUnit; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellLogCurveData::convertFromMeterToFeet(const std::vector& valuesInMeter) +{ + std::vector valuesInFeet(valuesInMeter.size()); + + for (size_t i = 0; i < valuesInMeter.size(); i++) + { + valuesInFeet[i] = valuesInMeter[i] * RimDefines::feetPerMeter(); + } + + return valuesInFeet; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellLogCurveData::convertFromFeetToMeter(const std::vector& valuesInFeet) +{ + std::vector valuesInMeter(valuesInFeet.size()); + + for (size_t i = 0; i < valuesInFeet.size(); i++) + { + valuesInMeter[i] = valuesInFeet[i] / RimDefines::feetPerMeter(); + } + + return valuesInMeter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigWellLogCurveData::convertDepthValues(RimDefines::DepthUnitType destinationDepthUnit, const std::vector& values) const +{ + CVF_ASSERT(destinationDepthUnit != m_depthUnit); + + if (destinationDepthUnit == RimDefines::UNIT_METER) + { + return convertFromFeetToMeter(values); + } + else + { + return convertFromMeterToFeet(values); + } +} diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h index a9e57fb749..30ea1200af 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogCurveData.h @@ -54,7 +54,7 @@ class RigWellLogCurveData : public cvf::Object RimDefines::DepthUnitType depthUnit() const; std::vector xPlotValues() const; - std::vector depthPlotValues() const; + std::vector depthPlotValues(RimDefines::DepthUnitType displayDepthUnit) const; std::vector< std::pair > polylineStartStopIndices() const; private: @@ -63,6 +63,12 @@ class RigWellLogCurveData : public cvf::Object static void splitIntervalAtEmptySpace(const std::vector& depthValues, size_t startIdx, size_t stopIdx, std::vector< std::pair >* intervals); + + std::vector convertDepthValues(RimDefines::DepthUnitType destinationDepthUnit, const std::vector& originalValues) const; + + static std::vector convertFromMeterToFeet(const std::vector& valuesInMeter); + static std::vector convertFromFeetToMeter(const std::vector& valuesInFeet); + private: std::vector m_xValues; std::vector m_measuredDepths; From de14b93f6b29e52f46a745c40747f75de4bfe36e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 13:49:36 +0100 Subject: [PATCH 193/290] (#538) Support both meter and feet in LAS export --- .../ProjectDataModel/RimWellLogCurve.h | 4 +- .../ReservoirDataModel/RigWellLogFile.cpp | 48 +++++++++---------- .../ReservoirDataModel/RigWellLogFile.h | 4 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index b1966c0ea0..85ab089fdd 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -83,8 +83,8 @@ class RimWellLogCurve : public caf::PdmObject virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly); - QPointer m_ownerQwtTrack; - RiuLineSegmentQwtPlotCurve* m_qwtPlotCurve; + QPointer m_ownerQwtTrack; + RiuLineSegmentQwtPlotCurve* m_qwtPlotCurve; cvf::ref m_curveData; caf::PdmField m_showCurve; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index f5eaed1157..8c3dc5d36a 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -30,8 +30,6 @@ #include #include // Needed for HUGE_VAL on Linux -#define RIG_WELL_FOOTPERMETER 3.2808399 - //-------------------------------------------------------------------------------------------------- /// Find the largest possible "ususal" value to use for absent data (-999.25, -9999.25, etc.) @@ -172,33 +170,18 @@ std::vector RigWellLogFile::values(const QString& name) const if (m_wellLogFile->HasContLog(name.toStdString())) { - if (name == m_depthLogName && (depthUnitString().toUpper() == "F" || depthUnitString().toUpper() == "FT")) - { - std::vector footValues = m_wellLogFile->GetContLog(name.toStdString()); - - std::vector meterValues; - meterValues.reserve(footValues.size()); - - for (size_t vIdx = 0; vIdx < footValues.size(); vIdx++) - { - meterValues.push_back(footValues[vIdx]/RIG_WELL_FOOTPERMETER); - } - - return meterValues; - } - - std::vector values = m_wellLogFile->GetContLog(name.toStdString()); + std::vector logValues = m_wellLogFile->GetContLog(name.toStdString()); - for (size_t vIdx = 0; vIdx < values.size(); vIdx++) + for (size_t vIdx = 0; vIdx < logValues.size(); vIdx++) { - if (m_wellLogFile->IsMissing(values[vIdx])) + if (m_wellLogFile->IsMissing(logValues[vIdx])) { // Convert missing ("NULL") values to HUGE_VAL - values[vIdx] = HUGE_VAL; + logValues[vIdx] = HUGE_VAL; } } - return values; + return logValues; } return std::vector(); @@ -279,7 +262,16 @@ bool RigWellLogFile::exportToLasFile(const RimWellLogCurve* curve, const QString NRLib::LasWell lasFile; lasFile.addWellInfo("WELL", curve->wellName().trimmed().toStdString()); lasFile.addWellInfo("DATE", wellLogDate.toStdString()); - lasFile.AddLog("DEPTH", "M", "Depth in meters", curveData->measuredDepths()); + + if (curveData->depthUnit() == RimDefines::UNIT_METER) + { + lasFile.AddLog("DEPTH", "M", "Depth in meters", curveData->measuredDepths()); + } + else if (curveData->depthUnit() == RimDefines::UNIT_FEET) + { + lasFile.AddLog("DEPTH", "FT", "Depth in feet", curveData->measuredDepths()); + } + lasFile.AddLog(wellLogChannelName.trimmed().toStdString(), "NO_UNIT", "", wellLogValues); lasFile.SetMissing(absentValue); @@ -289,7 +281,15 @@ bool RigWellLogFile::exportToLasFile(const RimWellLogCurve* curve, const QString lasFile.setStartDepth(minDepth); lasFile.setStopDepth(maxDepth); - lasFile.setDepthUnit("M"); + + if (curveData->depthUnit() == RimDefines::UNIT_METER) + { + lasFile.setDepthUnit("M"); + } + else if (curveData->depthUnit() == RimDefines::UNIT_FEET) + { + lasFile.setDepthUnit("FT"); + } lasFile.setVersionInfo("2.0"); diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h index 3d83d94f88..d269eba7d1 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h @@ -51,14 +51,14 @@ class RigWellLogFile : public cvf::Object std::vector depthValues() const; std::vector values(const QString& name) const; - QString depthUnitString() const; QString wellLogChannelUnitString(const QString& wellLogChannelName) const; RimDefines::DepthUnitType depthUnit() const; static bool exportToLasFile(const RimWellLogCurve* curve, const QString& fileName); private: - void close(); + void close(); + QString depthUnitString() const; NRLib::Well* m_wellLogFile; QStringList m_wellLogChannelNames; From a215e080ccb7f2c8b5af2021aa252af3b37d29bd Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 14:21:22 +0100 Subject: [PATCH 194/290] (#538) Display correct unit in curve name --- .../ProjectDataModel/RimWellLogFileCurve.cpp | 6 +++++- .../ReservoirDataModel/RigWellLogFile.cpp | 15 ++++++++++++--- .../ReservoirDataModel/RigWellLogFile.h | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index d91c6bdbe2..70a600074d 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -263,7 +263,11 @@ QString RimWellLogFileCurve::createCurveName() RigWellLogFile* wellLogFile = logFileInfo ? logFileInfo->wellLogFile() : NULL; if (wellLogFile) { - QString unitName = wellLogFile->wellLogChannelUnitString(m_wellLogChannnelName); + RimWellLogPlot* wellLogPlot; + firstAnchestorOrThisOfType(wellLogPlot); + CVF_ASSERT(wellLogPlot); + + QString unitName = wellLogFile->wellLogChannelUnitString(m_wellLogChannnelName, wellLogPlot->depthUnit()); if (!unitName.isEmpty()) { txt += QString(" [%1]").arg(unitName); diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp index 8c3dc5d36a..a0f787efd9 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.cpp @@ -206,7 +206,7 @@ QString RigWellLogFile::depthUnitString() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RigWellLogFile::wellLogChannelUnitString(const QString& wellLogChannelName) const +QString RigWellLogFile::wellLogChannelUnitString(const QString& wellLogChannelName, RimDefines::DepthUnitType displayDepthUnit) const { QString unit; @@ -216,10 +216,19 @@ QString RigWellLogFile::wellLogChannelUnitString(const QString& wellLogChannelNa unit = QString::fromStdString(lasWell->unitName(wellLogChannelName.toStdString())); } - // Special handling of depth unit - we convert depth to meter if (unit == depthUnitString()) { - return "m"; + if (displayDepthUnit != depthUnit()) + { + if (displayDepthUnit == RimDefines::UNIT_METER) + { + return "M"; + } + else if (displayDepthUnit == RimDefines::UNIT_FEET) + { + return "FT"; + } + } } return unit; diff --git a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h index d269eba7d1..403ae766e9 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellLogFile.h +++ b/ApplicationCode/ReservoirDataModel/RigWellLogFile.h @@ -51,7 +51,7 @@ class RigWellLogFile : public cvf::Object std::vector depthValues() const; std::vector values(const QString& name) const; - QString wellLogChannelUnitString(const QString& wellLogChannelName) const; + QString wellLogChannelUnitString(const QString& wellLogChannelName, RimDefines::DepthUnitType displayDepthUnit) const; RimDefines::DepthUnitType depthUnit() const; static bool exportToLasFile(const RimWellLogCurve* curve, const QString& fileName); From a85292ecd472f67f479fa7fe4f94fbad03f8ae6b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 14:38:18 +0100 Subject: [PATCH 195/290] Replace additional characters with _ in LAS file export --- ApplicationCode/Commands/RicExportToLasFileFeature.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp index 51c635f6b8..e558d55c8c 100644 --- a/ApplicationCode/Commands/RicExportToLasFileFeature.cpp +++ b/ApplicationCode/Commands/RicExportToLasFileFeature.cpp @@ -54,6 +54,8 @@ void RicExportToLasFileFeature::onActionTriggered(bool isChecked) QString defaultFileName = curve->name().trimmed(); defaultFileName.replace(".", "_"); defaultFileName.replace(",", "_"); + defaultFileName.replace(":", "_"); + defaultFileName.replace(";", "_"); defaultFileName.replace(" ", "_"); defaultFileName.replace(QRegExp("_+"), "_"); defaultFileName.append(".las"); From ac2a28f139266fdbba167a4ff522ef938dde1eed Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 2 Dec 2015 15:07:12 +0100 Subject: [PATCH 196/290] (#538) Initialize new plot with depth unit Removed obsolete functions --- .../RicAddWellLogToPlotFeature.cpp | 6 ++ .../RicNewWellLogCurveExtractionFeature.cpp | 14 ++++- .../RicNewWellLogPlotFeatureImpl.cpp | 55 +++++++------------ .../RicNewWellLogPlotFeatureImpl.h | 9 ++- .../RimMainPlotCollection.cpp | 11 ---- .../ProjectDataModel/RimMainPlotCollection.h | 1 - .../ProjectDataModel/RimProject.cpp | 11 ---- ApplicationCode/ProjectDataModel/RimProject.h | 2 - .../ProjectDataModel/RimWellLogPlot.cpp | 10 ++++ .../ProjectDataModel/RimWellLogPlot.h | 3 + 10 files changed, 53 insertions(+), 69 deletions(-) diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index 19cf118734..7e46439643 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -93,6 +93,12 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) RigWellLogFile* wellLogDataFile = wellLogFile->wellLogFile(); CVF_ASSERT(wellLogDataFile); + if (wlIdx == 0) + { + // Initialize plot with depth unit from the first log file + plot->setDepthUnit(wellLogDataFile->depthUnit()); + } + cvf::Color3f curveColor = RicWellLogPlotCurveFeatureImpl::curveColorFromTable(); curve->setColor(curveColor); curve->setWellPath(wellPath); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index 0da0aeeaf9..eea12500b2 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -22,12 +22,13 @@ #include "RicWellLogPlotCurveFeatureImpl.h" #include "RicNewWellLogPlotFeatureImpl.h" -#include "RimWellLogTrack.h" +#include "RimProject.h" +#include "RimView.h" #include "RimWellLogExtractionCurve.h" +#include "RimWellLogPlot.h" +#include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" -#include "RimView.h" -#include "RimProject.h" #include "RiuMainWindow.h" #include "RiaApplication.h" @@ -66,6 +67,13 @@ void RicNewWellLogCurveExtractionFeature::onActionTriggered(bool isChecked) { RimWellLogTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); RimWellLogExtractionCurve* plotCurve = addCurve(wellLogPlotTrack, RiaApplication::instance()->activeReservoirView(), wellPath); + + RimWellLogPlot* plot = NULL; + wellLogPlotTrack->firstAnchestorOrThisOfType(plot); + if (plot) + { + plot->setDepthUnit(plotCurve->curveData()->depthUnit()); + } plotCurve->updatePlotData(); plotCurve->updateConnectedEditors(); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp index f993a6b376..37164504b9 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.cpp @@ -19,50 +19,16 @@ #include "RicNewWellLogPlotFeatureImpl.h" -#include "RimProject.h" #include "RimMainPlotCollection.h" -#include "RimWellLogPlotCollection.h" +#include "RimProject.h" #include "RimWellLogPlot.h" +#include "RimWellLogPlotCollection.h" #include "RimWellLogTrack.h" #include "RiaApplication.h" #include "cvfAssert.h" -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimMainPlotCollection* RicNewWellLogPlotFeatureImpl::mainPlotCollection() -{ - RimProject* project = RiaApplication::instance()->project(); - CVF_ASSERT(project); - - RimMainPlotCollection* mainPlotColl = project->mainPlotCollection(); - if (!mainPlotColl) - { - project->recreateMainPlotCollection(); - } - - return project->mainPlotCollection(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimWellLogPlotCollection* RicNewWellLogPlotFeatureImpl::wellLogPlotCollection() -{ - RimMainPlotCollection* mainPlotColl = mainPlotCollection(); - CVF_ASSERT(mainPlotColl); - - RimWellLogPlotCollection* wellLogPlotColl = mainPlotColl->wellLogPlotCollection(); - if (!wellLogPlotColl) - { - mainPlotColl->recreateWellLogPlotCollection(); - } - - return mainPlotColl->wellLogPlotCollection(); -} - //-------------------------------------------------------------------------------------------------- /// @@ -97,3 +63,20 @@ RimWellLogTrack* RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack() return plotTrack; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellLogPlotCollection* RicNewWellLogPlotFeatureImpl::wellLogPlotCollection() +{ + RimProject* project = RiaApplication::instance()->project(); + CVF_ASSERT(project); + + RimMainPlotCollection* mainPlotColl = project->mainPlotCollection(); + CVF_ASSERT(mainPlotColl); + + RimWellLogPlotCollection* wellLogPlotColl = mainPlotColl->wellLogPlotCollection(); + CVF_ASSERT(wellLogPlotColl); + + return mainPlotColl->wellLogPlotCollection(); +} diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h index c50de7d82a..48ebdecfd8 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogPlotFeatureImpl.h @@ -19,7 +19,6 @@ #pragma once -class RimMainPlotCollection; class RimWellLogPlotCollection; class RimWellLogPlot; class RimWellLogTrack; @@ -30,9 +29,9 @@ class RimWellLogTrack; class RicNewWellLogPlotFeatureImpl { public: + static RimWellLogPlot* createWellLogPlot(); + static RimWellLogTrack* createWellLogPlotTrack(); - static RimMainPlotCollection* mainPlotCollection(); - static RimWellLogPlotCollection* wellLogPlotCollection(); - static RimWellLogPlot* createWellLogPlot(); - static RimWellLogTrack* createWellLogPlotTrack(); +private: + static RimWellLogPlotCollection* wellLogPlotCollection(); }; diff --git a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp index 1fdaafbb5d..feac205cde 100644 --- a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp @@ -65,17 +65,6 @@ caf::PdmFieldHandle* RimMainPlotCollection::objectToggleField() return &show; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimMainPlotCollection::recreateWellLogPlotCollection() -{ - if (!wellLogPlotCollection()) - { - m_wellLogPlotCollection = new RimWellLogPlotCollection(); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h index 23a6b4a890..6cd50243dc 100644 --- a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h +++ b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h @@ -38,7 +38,6 @@ class RimMainPlotCollection : public caf::PdmObject virtual ~RimMainPlotCollection(); RimWellLogPlotCollection* wellLogPlotCollection(); - void recreateWellLogPlotCollection(); protected: diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index da7e75beb5..f93e1e77cd 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -735,14 +735,3 @@ void RimProject::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QS uiTreeOrdering.setForgetRemainingFields(true); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimProject::recreateMainPlotCollection() -{ - if (!mainPlotCollection()) - { - mainPlotCollection = new RimMainPlotCollection(); - } -} - diff --git a/ApplicationCode/ProjectDataModel/RimProject.h b/ApplicationCode/ProjectDataModel/RimProject.h index 17d54e403e..4554ddfa15 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.h +++ b/ApplicationCode/ProjectDataModel/RimProject.h @@ -93,8 +93,6 @@ class RimProject : public caf::PdmDocument void actionsBasedOnSelection(QMenu& contextMenu); - void recreateMainPlotCollection(); - protected: // Overridden methods void initScriptDirectories(); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index b4c2746ca9..7eb249bb95 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -560,3 +560,13 @@ size_t RimWellLogPlot::trackIndex(RimWellLogTrack* track) return m_tracks.index(track); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogPlot::setDepthUnit(RimDefines::DepthUnitType depthUnit) +{ + m_depthUnit = depthUnit; + + updateTracks(); +} + diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index 1531926f2e..f7963d6a29 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -53,7 +53,10 @@ class RimWellLogPlot : public caf::PdmObject void setDescription(const QString& description); DepthTypeEnum depthType() const; + RimDefines::DepthUnitType depthUnit() const; + void setDepthUnit(RimDefines::DepthUnitType depthUnit); + QString depthPlotTitle() const; caf::PdmField< std::vector > windowGeometry; From 57b0e7b18d63f0f46380f2896fa381ee0a2b25e0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 07:26:19 +0100 Subject: [PATCH 197/290] (#538) Make sure curve data is populated before used --- .../RicNewWellLogCurveExtractionFeature.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index eea12500b2..012e825ecb 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -68,14 +68,15 @@ void RicNewWellLogCurveExtractionFeature::onActionTriggered(bool isChecked) RimWellLogTrack* wellLogPlotTrack = RicNewWellLogPlotFeatureImpl::createWellLogPlotTrack(); RimWellLogExtractionCurve* plotCurve = addCurve(wellLogPlotTrack, RiaApplication::instance()->activeReservoirView(), wellPath); + plotCurve->updatePlotData(); + RimWellLogPlot* plot = NULL; wellLogPlotTrack->firstAnchestorOrThisOfType(plot); - if (plot) + if (plot && plotCurve->curveData()) { plot->setDepthUnit(plotCurve->curveData()->depthUnit()); } - - plotCurve->updatePlotData(); + plotCurve->updateConnectedEditors(); } } From 5d81209b72649b31752deea464303421103bc040 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 08:26:38 +0100 Subject: [PATCH 198/290] Fixed memory leak for cross section collection --- ApplicationCode/ProjectDataModel/RimCrossSection.cpp | 8 ++++++++ ApplicationCode/ProjectDataModel/RimCrossSection.h | 1 + .../ProjectDataModel/RimCrossSectionCollection.cpp | 8 ++++++++ .../ProjectDataModel/RimCrossSectionCollection.h | 1 + ApplicationCode/ProjectDataModel/RimView.cpp | 1 + 5 files changed, 19 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index dfb0d01450..cea704e7a5 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -97,6 +97,14 @@ RimCrossSection::RimCrossSection() uiCapability()->setUiChildrenHidden(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCrossSection::~RimCrossSection() +{ + +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.h b/ApplicationCode/ProjectDataModel/RimCrossSection.h index 64b8241c3b..85e20ba85b 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.h @@ -59,6 +59,7 @@ class RimCrossSection : public caf::PdmObject public: RimCrossSection(); + ~RimCrossSection(); caf::PdmField name; caf::PdmField isActive; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index 1a1e5e6463..c3a9cc7823 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -41,6 +41,14 @@ RimCrossSectionCollection::RimCrossSectionCollection() isActive.uiCapability()->setUiHidden(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCrossSectionCollection::~RimCrossSectionCollection() +{ + m_crossSections.deleteAllChildObjects(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h index c539d1d7ac..4c8eb9ad94 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.h @@ -42,6 +42,7 @@ class RimCrossSectionCollection : public caf::PdmObject public: RimCrossSectionCollection(); + ~RimCrossSectionCollection(); caf::PdmField isActive; diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 02ba600a1e..0f0782279c 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -174,6 +174,7 @@ RimView::~RimView(void) delete m_rangeFilterCollection; delete m_overrideRangeFilterCollection; + delete crossSectionCollection; } //-------------------------------------------------------------------------------------------------- From 9ec732673585537ef41aef12138663e738cefa8a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 08:38:03 +0100 Subject: [PATCH 199/290] (#686) Enable "Hide grid" for geomech views --- ApplicationCode/UserInterface/RiuMainWindow.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 8b5fff3588..644a27c833 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1897,19 +1897,21 @@ void RiuMainWindow::refreshDrawStyleActions() m_drawStyleFaultLinesSolidAction->setEnabled(enable); m_disableLightingAction->setEnabled(enable); - RimGeoMechView* geoMechView = dynamic_cast(view); bool lightingDisabledInView = view ? view->isLightingDisabled() : false; m_disableLightingAction->blockSignals(true); m_disableLightingAction->setChecked(lightingDisabledInView); m_disableLightingAction->blockSignals(false); + if (enable) + { + m_drawStyleToggleFaultsAction->setEnabled(true); + } + RimEclipseView* eclView = dynamic_cast(view); enable = enable && eclView; - m_drawStyleToggleFaultsAction->setEnabled(enable); m_toggleFaultsLabelAction->setEnabled(enable); - m_addWellCellsToRangeFilterAction->setEnabled(enable); if (enable) From 40cf03dbd54a03de21f14bb4cdfacd8f1c0ccf2a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 08:39:08 +0100 Subject: [PATCH 200/290] Rename --- ApplicationCode/UserInterface/RiuMainWindow.cpp | 16 ++++++++-------- ApplicationCode/UserInterface/RiuMainWindow.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 644a27c833..a58bdacac3 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -350,9 +350,9 @@ void RiuMainWindow::createActions() connect(m_disableLightingAction, SIGNAL(toggled(bool)), SLOT(slotDisableLightingAction(bool))); - m_drawStyleToggleFaultsAction = new QAction( QIcon(":/draw_style_faults_24x24.png"), "&Hide Grid Cells", this); - m_drawStyleToggleFaultsAction->setCheckable(true); - connect(m_drawStyleToggleFaultsAction, SIGNAL(toggled(bool)), SLOT(slotToggleHideGridCellsAction(bool))); + m_drawStyleHideGridCellsAction = new QAction( QIcon(":/draw_style_faults_24x24.png"), "&Hide Grid Cells", this); + m_drawStyleHideGridCellsAction->setCheckable(true); + connect(m_drawStyleHideGridCellsAction, SIGNAL(toggled(bool)), SLOT(slotToggleHideGridCellsAction(bool))); m_toggleFaultsLabelAction = new QAction( QIcon(":/draw_style_faults_label_24x24.png"), "&Show Fault Labels", this); m_toggleFaultsLabelAction->setCheckable(true); @@ -549,7 +549,7 @@ void RiuMainWindow::createToolBars() m_viewToolBar->addAction(m_drawStyleSurfOnlyAction); m_viewToolBar->addAction(m_drawStyleFaultLinesSolidAction); m_viewToolBar->addAction(m_disableLightingAction); - m_viewToolBar->addAction(m_drawStyleToggleFaultsAction); + m_viewToolBar->addAction(m_drawStyleHideGridCellsAction); m_viewToolBar->addAction(m_toggleFaultsLabelAction); m_viewToolBar->addAction(m_addWellCellsToRangeFilterAction); @@ -1905,7 +1905,7 @@ void RiuMainWindow::refreshDrawStyleActions() if (enable) { - m_drawStyleToggleFaultsAction->setEnabled(true); + m_drawStyleHideGridCellsAction->setEnabled(true); } RimEclipseView* eclView = dynamic_cast(view); @@ -1916,9 +1916,9 @@ void RiuMainWindow::refreshDrawStyleActions() if (enable) { - m_drawStyleToggleFaultsAction->blockSignals(true); - m_drawStyleToggleFaultsAction->setChecked(!eclView->isGridVisualizationMode()); - m_drawStyleToggleFaultsAction->blockSignals(false); + m_drawStyleHideGridCellsAction->blockSignals(true); + m_drawStyleHideGridCellsAction->setChecked(!eclView->isGridVisualizationMode()); + m_drawStyleHideGridCellsAction->blockSignals(false); m_toggleFaultsLabelAction->blockSignals(true); m_toggleFaultsLabelAction->setChecked(eclView->faultCollection()->showFaultLabel()); diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index 8196034384..adccc5412c 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -300,7 +300,7 @@ private slots: QActionGroup* m_dsActionGroup; QAction* m_disableLightingAction; - QAction* m_drawStyleToggleFaultsAction; + QAction* m_drawStyleHideGridCellsAction; QAction* m_toggleFaultsLabelAction; QAction* m_drawStyleLinesAction; QAction* m_drawStyleLinesSolidAction; From 97b95216e99ff24c960ac303261f244877235cb9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 10:33:13 +0100 Subject: [PATCH 201/290] (#687) Moved unit tests to ApplicationCode/UnitTests --- ApplicationCode/CMakeLists.txt | 2 +- .../RimWellLogExtractionCurveImpl-Test.cpp | 0 .../ScalarMapper-Test.cpp | 0 .../WellPathAsciiFileReader-Test.cpp | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename ApplicationCode/{ProjectDataModel/ProjectDataModel_UnitTests => UnitTests}/RimWellLogExtractionCurveImpl-Test.cpp (100%) rename ApplicationCode/{ProjectDataModel/ProjectDataModel_UnitTests => UnitTests}/ScalarMapper-Test.cpp (100%) rename ApplicationCode/{ProjectDataModel/ProjectDataModel_UnitTests => UnitTests}/WellPathAsciiFileReader-Test.cpp (100%) diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 86117aa398..aabac1605d 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -114,7 +114,7 @@ set( SOCKET_INTERFACE_FILES # Using GLOB here to ease adding of new unit tests FILE ( GLOB UNIT_TEST_FILES - ProjectDataModel/ProjectDataModel_UnitTests/*.cpp + UnitTests/*.cpp ) list( APPEND CPP_SOURCES diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp b/ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp similarity index 100% rename from ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/RimWellLogExtractionCurveImpl-Test.cpp rename to ApplicationCode/UnitTests/RimWellLogExtractionCurveImpl-Test.cpp diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp b/ApplicationCode/UnitTests/ScalarMapper-Test.cpp similarity index 100% rename from ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/ScalarMapper-Test.cpp rename to ApplicationCode/UnitTests/ScalarMapper-Test.cpp diff --git a/ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/WellPathAsciiFileReader-Test.cpp b/ApplicationCode/UnitTests/WellPathAsciiFileReader-Test.cpp similarity index 100% rename from ApplicationCode/ProjectDataModel/ProjectDataModel_UnitTests/WellPathAsciiFileReader-Test.cpp rename to ApplicationCode/UnitTests/WellPathAsciiFileReader-Test.cpp From d2537a207f14dccad14212e77d8c736373cb2c0b Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 10:33:38 +0100 Subject: [PATCH 202/290] (#687) Improved launch of unit tests from command line --- .../Application/RiaApplication.cpp | 51 ++++++++++++++----- ApplicationCode/Application/RiaApplication.h | 5 +- ApplicationCode/RiaMain.cpp | 6 +++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 3c6c144e74..921c968286 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -208,6 +208,35 @@ RiaApplication* RiaApplication::instance() } +//-------------------------------------------------------------------------------------------------- +/// Return -1 if unit test is not executed, returns 0 if test passed, returns 1 if tests failed +//-------------------------------------------------------------------------------------------------- +int RiaApplication::parseArgumentsAndRunUnitTestsIfRequested() +{ + cvf::ProgramOptions progOpt; + progOpt.registerOption("unittest", "", "Execute unit tests"); + progOpt.setOptionPrefix(cvf::ProgramOptions::DOUBLE_DASH); + + QStringList arguments = QCoreApplication::arguments(); + + bool parseOk = progOpt.parse(cvfqt::Utils::toStringVector(arguments)); + if (!parseOk) + { + return -1; + } + + // Unit testing + // -------------------------------------------------------- + if (cvf::Option o = progOpt.option("unittest")) + { + int testReturnValue = launchUnitTestsWithConsole(); + + return testReturnValue; + } + + return -1; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1149,34 +1178,32 @@ bool RiaApplication::parseArguments() return false; } - // Unit testing - // -------------------------------------------------------- - if (cvf::Option o = progOpt.option("unittest")) - { - launchUnitTests(); - } - return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiaApplication::launchUnitTests() +int RiaApplication::launchUnitTests() { cvf::Assert::setReportMode(cvf::Assert::CONSOLE); int argc = QCoreApplication::argc(); testing::InitGoogleTest(&argc, QCoreApplication::argv()); - //int result = RUN_ALL_TESTS(); - RUN_ALL_TESTS(); + // Use this macro in main() to run all tests. It returns 0 if all + // tests are successful, or 1 otherwise. + // + // RUN_ALL_TESTS() should be invoked after the command line has been + // parsed by InitGoogleTest(). + + return RUN_ALL_TESTS(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiaApplication::launchUnitTestsWithConsole() +int RiaApplication::launchUnitTestsWithConsole() { // Following code is taken from cvfAssert.cpp #ifdef WIN32 @@ -1224,7 +1251,7 @@ void RiaApplication::launchUnitTestsWithConsole() } #endif - launchUnitTests(); + return launchUnitTests(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/RiaApplication.h b/ApplicationCode/Application/RiaApplication.h index e453f6514e..b2058cf436 100644 --- a/ApplicationCode/Application/RiaApplication.h +++ b/ApplicationCode/Application/RiaApplication.h @@ -72,6 +72,7 @@ class RiaApplication : public QApplication ~RiaApplication(); static RiaApplication* instance(); + int parseArgumentsAndRunUnitTestsIfRequested(); bool parseArguments(); void executeRegressionTests(const QString& regressionTestPath); @@ -159,8 +160,8 @@ class RiaApplication : public QApplication bool isRunningRegressionTests() const; - void launchUnitTests(); - void launchUnitTestsWithConsole(); + int launchUnitTests(); + int launchUnitTestsWithConsole(); private: enum ProjectLoadAction diff --git a/ApplicationCode/RiaMain.cpp b/ApplicationCode/RiaMain.cpp index 5e7d9e6950..d14d0dd18a 100644 --- a/ApplicationCode/RiaMain.cpp +++ b/ApplicationCode/RiaMain.cpp @@ -26,6 +26,12 @@ int main(int argc, char *argv[]) QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); setlocale(LC_NUMERIC,"C"); + int unitTestResult = app.parseArgumentsAndRunUnitTestsIfRequested(); + if (unitTestResult > -1) + { + return unitTestResult; + } + RiuMainWindow window; QString platform = cvf::System::is64Bit() ? "(64bit)" : "(32bit)"; window.setWindowTitle("ResInsight " + platform); From 709fce384ada4902fc5a78402f3da20fbb2b1a61 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 10:46:50 +0100 Subject: [PATCH 203/290] Fixed value rounding near texture edges --- .../RivTernaryScalarMapper-Test.cpp | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp b/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp index cf485ece75..612676a801 100644 --- a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp +++ b/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp @@ -48,41 +48,44 @@ TEST(TernaryScalarMapperTest, TextureMapping) { cvf::ref scalarMapper = new RivTernaryScalarMapper(cvf::Color3f::GRAY); + // See RivTernaryScalarMapper::mapToTextureCoord + double edgeClampDelta = 1.1 * 0.001; + // Without opacity { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(0.0, 0.0, false); - EXPECT_DOUBLE_EQ(0.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.0, texCoord.y()); + EXPECT_NEAR(0.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.0, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(1.0, 0.0, false); - EXPECT_DOUBLE_EQ(1.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.0, texCoord.y()); + EXPECT_NEAR(1.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.0, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(0.0, 1.0, false); - EXPECT_DOUBLE_EQ(0.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.5, texCoord.y()); + EXPECT_NEAR(0.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.5, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(3.0, 3.0, false); - EXPECT_DOUBLE_EQ(1.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.0, texCoord.y()); + EXPECT_NEAR(1.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.0, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(-1.0, -1.0, false); - EXPECT_DOUBLE_EQ(0.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.0, texCoord.y()); + EXPECT_NEAR(0.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.0, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(0.5, 3.0, false); - EXPECT_DOUBLE_EQ(0.5, texCoord.x()); - EXPECT_DOUBLE_EQ(0.25, texCoord.y()); + EXPECT_NEAR(0.5, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.25, texCoord.y(), edgeClampDelta); } @@ -91,13 +94,13 @@ TEST(TernaryScalarMapperTest, TextureMapping) // Opacity { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(0.0, 0.0, true); - EXPECT_DOUBLE_EQ(0.0, texCoord.x()); - EXPECT_DOUBLE_EQ(0.5, texCoord.y()); + EXPECT_NEAR(0.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(0.5, texCoord.y(), edgeClampDelta); } { cvf::Vec2f texCoord = scalarMapper->mapToTextureCoord(0.0, 1.0, true); - EXPECT_DOUBLE_EQ(0.0, texCoord.x()); - EXPECT_DOUBLE_EQ(1.0, texCoord.y()); + EXPECT_NEAR(0.0, texCoord.x(), edgeClampDelta); + EXPECT_NEAR(1.0, texCoord.y(), edgeClampDelta); } } From 563dd8c04fab786ae9aa5dafe3b0b8601b96f604 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 10:53:12 +0100 Subject: [PATCH 204/290] (#687) Moved tests from ModelVisualization into ApplicationCode/UnitTests --- .../CMakeLists.txt | 71 ------------------- .../ModelVisualization_UnitTests/main.cpp | 43 ----------- .../RivPipeGeometryGenerator-Test.cpp | 0 .../RivTernaryScalarMapper-Test.cpp | 0 CMakeLists.txt | 2 - 5 files changed, 116 deletions(-) delete mode 100644 ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/CMakeLists.txt delete mode 100644 ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/main.cpp rename ApplicationCode/{ModelVisualization/ModelVisualization_UnitTests => UnitTests}/RivPipeGeometryGenerator-Test.cpp (100%) rename ApplicationCode/{ModelVisualization/ModelVisualization_UnitTests => UnitTests}/RivTernaryScalarMapper-Test.cpp (100%) diff --git a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/CMakeLists.txt b/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/CMakeLists.txt deleted file mode 100644 index 3d3f29de52..0000000000 --- a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -cmake_minimum_required (VERSION 2.8) - -SET (ProjectName ModelVisualization_UnitTests) -project ( ${ProjectName} ) - -include_directories( - ${LibCore_SOURCE_DIR} - ${LibGeometry_SOURCE_DIR} - ${LibRender_SOURCE_DIR} - ${LibViewing_SOURCE_DIR} - - ${ResInsight_SOURCE_DIR}/ThirdParty - - ${ResInsight_SOURCE_DIR}/ApplicationCode/ModelVisualization - - ${CommonCode_SOURCE_DIR} -) - -set( MODEL_VISUALIZATION_CPP_SOURCES - ../RivPipeGeometryGenerator.cpp - ../RivTernaryScalarMapper.cpp -) - - -set( CPP_SOURCES - ${MODEL_VISUALIZATION_CPP_SOURCES} -) - -set( UNIT_TEST_CPP_SOURCES - main.cpp - RivPipeGeometryGenerator-Test.cpp - RivTernaryScalarMapper-Test.cpp -) - - -set( LINK_LIBRARIES - LibViewing - LibRender - LibGeometry - LibCore - LibGuiQt - - CommonCode - - ${OPENGL_LIBRARIES} - ${QT_LIBRARIES} - -) - - -add_executable( ${ProjectName} - ${CPP_SOURCES} - ${UNIT_TEST_CPP_SOURCES} - - ${ResInsight_SOURCE_DIR}/ThirdParty/gtest/gtest-all.cc -) - - -IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set( EXTERNAL_LINK_LIBRARIES - pthread - ) -ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set( CMAKE_CXX_FLAGS - "-DGTEST_USE_OWN_TR1_TUPLE=1" - ) -ENDIF() - -target_link_libraries( ${ProjectName} ${LINK_LIBRARIES} ${EXTERNAL_LINK_LIBRARIES}) - - diff --git a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/main.cpp b/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/main.cpp deleted file mode 100644 index 3fcf713519..0000000000 --- a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - - -#include "cvfBase.h" - -#include "gtest/gtest.h" -#include - -#include "cvfTrace.h" - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int main(int argc, char **argv) -{ - cvf::Assert::setReportMode(cvf::Assert::CONSOLE); - - testing::InitGoogleTest(&argc, argv); - - int result = RUN_ALL_TESTS(); - - std::cout << "Please press to close the window."; - std::cin.get(); - - return result; -} diff --git a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivPipeGeometryGenerator-Test.cpp b/ApplicationCode/UnitTests/RivPipeGeometryGenerator-Test.cpp similarity index 100% rename from ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivPipeGeometryGenerator-Test.cpp rename to ApplicationCode/UnitTests/RivPipeGeometryGenerator-Test.cpp diff --git a/ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp b/ApplicationCode/UnitTests/RivTernaryScalarMapper-Test.cpp similarity index 100% rename from ApplicationCode/ModelVisualization/ModelVisualization_UnitTests/RivTernaryScalarMapper-Test.cpp rename to ApplicationCode/UnitTests/RivTernaryScalarMapper-Test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b6749c4ba2..266a44bdf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,10 +260,8 @@ add_subdirectory(OctavePlugin) ################################################################################ add_subdirectory(ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests) #add_subdirectory(ApplicationCode/FileInterface/FileInterface_UnitTests) -add_subdirectory(ApplicationCode/ModelVisualization/ModelVisualization_UnitTests) set_property(TARGET - ModelVisualization_UnitTests # FileInterface_UnitTests RigReservoirDataModel_UnitTests PROPERTY FOLDER "UnitTests" From e03b6495e80fe611bf42466313897a71e5dfd36a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 10:57:10 +0100 Subject: [PATCH 205/290] (#687) Moved ReservoirDataModelUnitTests into ApplicationCode/UnitTests --- .../CMakeLists.txt | 118 ------------------ .../ReservoirDataModel_UnitTests/main.cpp | 46 ------- .../RigActiveCellInfo-Test.cpp | 0 .../RigReservoir-Test.cpp | 0 .../RigStatisticsMath-Test.cpp | 0 .../cvfGeometryTools-Test.cpp | 0 6 files changed, 164 deletions(-) delete mode 100644 ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/CMakeLists.txt delete mode 100644 ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/main.cpp rename ApplicationCode/{ReservoirDataModel/ReservoirDataModel_UnitTests => UnitTests}/RigActiveCellInfo-Test.cpp (100%) rename ApplicationCode/{ReservoirDataModel/ReservoirDataModel_UnitTests => UnitTests}/RigReservoir-Test.cpp (100%) rename ApplicationCode/{ReservoirDataModel/ReservoirDataModel_UnitTests => UnitTests}/RigStatisticsMath-Test.cpp (100%) rename ApplicationCode/{ReservoirDataModel/ReservoirDataModel_UnitTests => UnitTests}/cvfGeometryTools-Test.cpp (100%) diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/CMakeLists.txt b/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/CMakeLists.txt deleted file mode 100644 index 80115859bf..0000000000 --- a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/CMakeLists.txt +++ /dev/null @@ -1,118 +0,0 @@ -cmake_minimum_required (VERSION 2.8) - -SET (ProjectName RigReservoirDataModel_UnitTests) -project ( ${ProjectName} ) - -# Qt -find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) -include (${QT_USE_FILE}) - -include_directories( - ${LibCore_SOURCE_DIR} - ${LibGeometry_SOURCE_DIR} - ${LibRender_SOURCE_DIR} - ${LibViewing_SOURCE_DIR} - - ${ResInsight_SOURCE_DIR}/ApplicationCode - ${ResInsight_SOURCE_DIR}/ApplicationCode/ResultStatisticsCache - ${ResInsight_SOURCE_DIR}/ApplicationCode/ReservoirDataModel - ${ResInsight_SOURCE_DIR}/ApplicationCode/FileInterface - ${ResInsight_SOURCE_DIR}/ApplicationCode/ProjectDataModel - ${ResInsight_SOURCE_DIR}/ThirdParty - ${ResInsight_SOURCE_DIR}/ThirdParty/NRLib/nrlib/well - - #${ResInsight_SOURCE_DIR}/Fwk/AppFwk/cafProjectDataModel - - ${cafProjectDataModel_SOURCE_DIR} - ${cafPdmCore_SOURCE_DIR} - - ${ResInsight_SOURCE_DIR}/Fwk/AppFwk/CommonCode - - #Remove when RigStatistics is out - #${ResInsight_SOURCE_DIR}/ApplicationCode/ModelVisualization -) - -# Populate the filenames into variable lists -include ("${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists_files.cmake") - - -set( UNIT_TEST_CPP_SOURCES - - ${ResInsight_SOURCE_DIR}/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp - - main.cpp - RigActiveCellInfo-Test.cpp - RigReservoir-Test.cpp - RigStatisticsMath-Test.cpp - cvfGeometryTools-Test.cpp -) - - -############################################################################# -# Adds folders for Visual Studio solution explorer (and for Xcode explorer) -############################################################################# -source_group( "UnitTests" FILES ${UNIT_TEST_CPP_SOURCES} ) - - - -set( LINK_LIBRARIES - CommonCode - - ResultStatisticsCache - - LibViewing - LibRender - LibGeometry - LibCore - - ecl - ecl_well - ert_util - - NRLib - - ${QT_LIBRARIES} -) - - -add_executable( ${ProjectName} - ${CODE_SOURCE_FILES} - ${UNIT_TEST_CPP_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists_files.cmake - - ${ResInsight_SOURCE_DIR}/ThirdParty/gtest/gtest-all.cc -) - - - -IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set ( LINUX_LINK_LIBRARIES - pthread - ) - - # Linux specific code - set(CMAKE_CXX_FLAGS "-DCVF_LINUX -pipe -Wextra -Woverloaded-virtual -Wformat") - set(CMAKE_CXX_FLAGS_DEBUG "-g -DDEBUG -D_DEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNO_DEBUG") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ") - -ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "-DGTEST_USE_OWN_TR1_TUPLE=1") -ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - - -target_link_libraries( ${ProjectName} ${LINK_LIBRARIES} ${LINUX_LINK_LIBRARIES}) - - -# Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui QtOpenGl) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/main.cpp b/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/main.cpp deleted file mode 100644 index 543a31bbf5..0000000000 --- a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - - -#include "cvfBase.h" - -#include "gtest/gtest.h" -#include - -#include "cvfTrace.h" - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int main(int argc, char **argv) -{ - //printf("Running main() from LibCore_UnitTests.cpp\n"); - //printf("LibCore version: %s.%s-%s (%s) \n\n", CVF_MAJOR_VERSION, CVF_MINOR_VERSION, CVF_BUILD_NUMBER, CVF_SPECIAL_BUILD); - - cvf::Assert::setReportMode(cvf::Assert::CONSOLE); - - testing::InitGoogleTest(&argc, argv); - - int result = RUN_ALL_TESTS(); - - std::cout << "Please press to close the window."; - std::cin.get(); - - return result; -} diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigActiveCellInfo-Test.cpp b/ApplicationCode/UnitTests/RigActiveCellInfo-Test.cpp similarity index 100% rename from ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigActiveCellInfo-Test.cpp rename to ApplicationCode/UnitTests/RigActiveCellInfo-Test.cpp diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigReservoir-Test.cpp b/ApplicationCode/UnitTests/RigReservoir-Test.cpp similarity index 100% rename from ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigReservoir-Test.cpp rename to ApplicationCode/UnitTests/RigReservoir-Test.cpp diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigStatisticsMath-Test.cpp b/ApplicationCode/UnitTests/RigStatisticsMath-Test.cpp similarity index 100% rename from ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/RigStatisticsMath-Test.cpp rename to ApplicationCode/UnitTests/RigStatisticsMath-Test.cpp diff --git a/ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/cvfGeometryTools-Test.cpp b/ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp similarity index 100% rename from ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests/cvfGeometryTools-Test.cpp rename to ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp From c72e047b23d2cb57bd20ad11736db29906c709e8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 11:11:07 +0100 Subject: [PATCH 206/290] (#687) Moved FileInterface tests into ApplicationCode/UnitTests --- .../FileInterface_UnitTests/CMakeLists.txt | 114 ------------------ .../FileInterface_UnitTests/main.cpp | 44 ------- .../Ert-Test.cpp | 0 .../RifEclipseInputFileTools-Test.cpp | 0 .../RifReaderEclipseOutput-Test.cpp | 1 - CMakeLists.txt | 13 -- 6 files changed, 172 deletions(-) delete mode 100644 ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt delete mode 100644 ApplicationCode/FileInterface/FileInterface_UnitTests/main.cpp rename ApplicationCode/{FileInterface/FileInterface_UnitTests => UnitTests}/Ert-Test.cpp (100%) rename ApplicationCode/{FileInterface/FileInterface_UnitTests => UnitTests}/RifEclipseInputFileTools-Test.cpp (100%) rename ApplicationCode/{FileInterface/FileInterface_UnitTests => UnitTests}/RifReaderEclipseOutput-Test.cpp (99%) diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt b/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt deleted file mode 100644 index c8fe5f4f85..0000000000 --- a/ApplicationCode/FileInterface/FileInterface_UnitTests/CMakeLists.txt +++ /dev/null @@ -1,114 +0,0 @@ -cmake_minimum_required (VERSION 2.8) - -SET (ProjectName FileInterface_UnitTests) -project ( ${ProjectName} ) - - -# Qt -find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) -include (${QT_USE_FILE}) - -include_directories( - ${ResInsight_SOURCE_DIR}/ApplicationCode - ${ResInsight_SOURCE_DIR}/ApplicationCode/ResultStatisticsCache - ${ResInsight_SOURCE_DIR}/ApplicationCode/ReservoirDataModel - ${ResInsight_SOURCE_DIR}/ApplicationCode/FileInterface - ${ResInsight_SOURCE_DIR}/ApplicationCode/ProjectDataModel - ${ResInsight_SOURCE_DIR}/ThirdParty - - ${ResInsight_SOURCE_DIR}/Fwk/AppFwk/cafProjectDataModel - - ${ResInsight_SOURCE_DIR}/Fwk/AppFwk/CommonCode - - #Remove when RigStatistics is out - ${ResInsight_SOURCE_DIR}/ApplicationCode/ModelVisualization -) - - -# Populate variables from read from CMakeLists_files.cmake -set (CODE_SOURCE_FILES ) -include ("${ResInsight_SOURCE_DIR}/ApplicationCode/FileInterface/CMakeLists_files.cmake") -set( CPP_SOURCES - ${CPP_SOURCES} - ${CODE_SOURCE_FILES} -) -source_group( "FileInterface" FILES ${CODE_SOURCE_FILES} ) - - -# Populate variables from read from CMakeLists_files.cmake -set (CODE_SOURCE_FILES ) -include ("${ResInsight_SOURCE_DIR}/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake") -set( CPP_SOURCES - ${CPP_SOURCES} - ${CODE_SOURCE_FILES} -) -source_group( "ReservoirDataModel" FILES ${CODE_SOURCE_FILES} ) - - -set( CPP_SOURCES - ${CPP_SOURCES} - - ${ResInsight_SOURCE_DIR}/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp -) - -source_group( "Headers" FILES ${CODE_HEADER_FILES} ) - -set( UNIT_TEST_CPP_SOURCES - main.cpp - RifReaderEclipseOutput-Test.cpp - RifEclipseInputFileTools-Test.cpp - Ert-Test.cpp -) - -set( LINK_LIBRARIES - cafProjectDataModel - CommonCode - - ResultStatisticsCache - - LibViewing - LibRender - LibGeometry - LibCore - - ecl - ert_util - ert_geometry - ecl_well - - ${QT_LIBRARIES} -) - -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "-DGTEST_USE_OWN_TR1_TUPLE=1") -endif() - -add_executable( ${ProjectName} - ${CODE_HEADER_FILES} - - ${CPP_SOURCES} - ${UNIT_TEST_CPP_SOURCES} - - ${ResInsight_SOURCE_DIR}/ThirdParty/gtest/gtest-all.cc - - ${ResInsight_SOURCE_DIR}/ApplicationCode/FileInterface/CMakeLists_files.cmake - ${ResInsight_SOURCE_DIR}/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake -) - -set( EXTERNAL_LINK_LIBRARIES ${ERT_LIBRARY_LIST} ) -target_link_libraries( ${ProjectName} ${LINK_LIBRARIES} ${EXTERNAL_LINK_LIBRARIES}) - - -# Copy Dlls -if (MSVC) - - # Qt DLLs - set (QTLIBLIST QtCore QtCored QtGui QtGuid QtOpenGl QtOpenGld QtNetwork QtNetworkd QtScript QtScriptd QtScriptTools QtScriptToolsd) - foreach (qtlib ${QTLIBLIST}) - add_custom_command(TARGET ${ProjectName} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${QT_BINARY_DIR}/${qtlib}4.dll" - ${CMAKE_CURRENT_BINARY_DIR}/$) - endforeach( qtlib ) - -endif(MSVC) diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/main.cpp b/ApplicationCode/FileInterface/FileInterface_UnitTests/main.cpp deleted file mode 100644 index 03d89c0085..0000000000 --- a/ApplicationCode/FileInterface/FileInterface_UnitTests/main.cpp +++ /dev/null @@ -1,44 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// -// 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 -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RiaStdInclude.h" - -#include "cvfBase.h" - -#include "gtest/gtest.h" -#include - -#include "cvfTrace.h" - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int main(int argc, char **argv) -{ - cvf::Assert::setReportMode(cvf::Assert::CONSOLE); - - testing::InitGoogleTest(&argc, argv); - - int result = RUN_ALL_TESTS(); - - std::cout << "Please press to close the window."; - std::cin.get(); - - return result; -} diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/Ert-Test.cpp b/ApplicationCode/UnitTests/Ert-Test.cpp similarity index 100% rename from ApplicationCode/FileInterface/FileInterface_UnitTests/Ert-Test.cpp rename to ApplicationCode/UnitTests/Ert-Test.cpp diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/RifEclipseInputFileTools-Test.cpp b/ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp similarity index 100% rename from ApplicationCode/FileInterface/FileInterface_UnitTests/RifEclipseInputFileTools-Test.cpp rename to ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp diff --git a/ApplicationCode/FileInterface/FileInterface_UnitTests/RifReaderEclipseOutput-Test.cpp b/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp similarity index 99% rename from ApplicationCode/FileInterface/FileInterface_UnitTests/RifReaderEclipseOutput-Test.cpp rename to ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp index 5c7b451bbb..fd6efe0081 100644 --- a/ApplicationCode/FileInterface/FileInterface_UnitTests/RifReaderEclipseOutput-Test.cpp +++ b/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp @@ -18,7 +18,6 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include "RiaStdInclude.h" #include "gtest/gtest.h" #include "RigCaseData.h" diff --git a/CMakeLists.txt b/CMakeLists.txt index 266a44bdf4..222293921a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,19 +255,6 @@ endif (RESINSIGHT_PRIVATE_INSTALL) add_subdirectory(ApplicationCode) add_subdirectory(OctavePlugin) -################################################################################ -# Unit tests -################################################################################ -add_subdirectory(ApplicationCode/ReservoirDataModel/ReservoirDataModel_UnitTests) -#add_subdirectory(ApplicationCode/FileInterface/FileInterface_UnitTests) - -set_property(TARGET -# FileInterface_UnitTests - RigReservoirDataModel_UnitTests - PROPERTY FOLDER "UnitTests" -) - - ################################################################################ # Code documentation using Doxygen ################################################################################ From de41755320c88c0c6db47fa58a818c561054fde5 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 11:38:59 +0100 Subject: [PATCH 207/290] (#687) Added option RESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS to enable unit tests --- .../Application/RiaApplication.cpp | 4 +++ ApplicationCode/CMakeLists.txt | 22 +++++++++---- .../UnitTests/CMakeLists_files.cmake | 33 +++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 ApplicationCode/UnitTests/CMakeLists_files.cmake diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 921c968286..faf12ad20f 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1186,6 +1186,7 @@ bool RiaApplication::parseArguments() //-------------------------------------------------------------------------------------------------- int RiaApplication::launchUnitTests() { +#ifdef USE_UNIT_TESTS cvf::Assert::setReportMode(cvf::Assert::CONSOLE); int argc = QCoreApplication::argc(); @@ -1198,6 +1199,9 @@ int RiaApplication::launchUnitTests() // parsed by InitGoogleTest(). return RUN_ALL_TESTS(); +#else + return -1; +#endif } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index aabac1605d..218ce46306 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -61,8 +61,6 @@ set( APPLICATION_FILES Application/RiaImageCompareReporter.cpp Application/RiaProjectModifier.cpp Application/RiaRegressionTest.cpp - - ${ResInsight_SOURCE_DIR}/ThirdParty/gtest/gtest-all.cc ) set( USER_INTERFACE_FILES @@ -112,11 +110,6 @@ set( SOCKET_INTERFACE_FILES SocketInterface/RiaSocketDataTransfer.cpp ) -# Using GLOB here to ease adding of new unit tests -FILE ( GLOB UNIT_TEST_FILES - UnitTests/*.cpp -) - list( APPEND CPP_SOURCES ${APPLICATION_FILES} ${USER_INTERFACE_FILES} @@ -144,6 +137,21 @@ list( APPEND REFERENCED_CMAKE_FILES Commands/CrossSectionCommands/CMakeLists_files.cmake ) +option (RESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS "Include ApplicationCode Unit Tests" OFF) +if (RESINSIGHT_INCLUDE_APPLICATION_UNIT_TESTS) + add_definitions(-DUSE_UNIT_TESTS) + + list( APPEND REFERENCED_CMAKE_FILES + UnitTests/CMakeLists_files.cmake + ) + + list( APPEND CPP_SOURCES + ${ResInsight_SOURCE_DIR}/ThirdParty/gtest/gtest-all.cc + ) + +endif() + + # Include source file lists from *.cmake files foreach (referencedfile ${REFERENCED_CMAKE_FILES}) include (${referencedfile}) diff --git a/ApplicationCode/UnitTests/CMakeLists_files.cmake b/ApplicationCode/UnitTests/CMakeLists_files.cmake new file mode 100644 index 0000000000..26efe91b33 --- /dev/null +++ b/ApplicationCode/UnitTests/CMakeLists_files.cmake @@ -0,0 +1,33 @@ + +# Use this workaround until we're on 2.8.3 on all platforms and can use CMAKE_CURRENT_LIST_DIR directly +if (${CMAKE_VERSION} VERSION_GREATER "2.8.2") + set(CEE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/) +endif() + +set (SOURCE_GROUP_HEADER_FILES +) + +set (SOURCE_GROUP_SOURCE_FILES +${CEE_CURRENT_LIST_DIR}cvfGeometryTools-Test.cpp +${CEE_CURRENT_LIST_DIR}Ert-Test.cpp +${CEE_CURRENT_LIST_DIR}RifEclipseInputFileTools-Test.cpp +${CEE_CURRENT_LIST_DIR}RifReaderEclipseOutput-Test.cpp +${CEE_CURRENT_LIST_DIR}RigActiveCellInfo-Test.cpp +${CEE_CURRENT_LIST_DIR}RigReservoir-Test.cpp +${CEE_CURRENT_LIST_DIR}RigStatisticsMath-Test.cpp +${CEE_CURRENT_LIST_DIR}RimWellLogExtractionCurveImpl-Test.cpp +${CEE_CURRENT_LIST_DIR}RivPipeGeometryGenerator-Test.cpp +${CEE_CURRENT_LIST_DIR}RivTernaryScalarMapper-Test.cpp +${CEE_CURRENT_LIST_DIR}ScalarMapper-Test.cpp +${CEE_CURRENT_LIST_DIR}WellPathAsciiFileReader-Test.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "UnitTests" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CEE_CURRENT_LIST_DIR}CMakeLists_files.cmake ) From 71cb7115eb8e29cdb4ed5d775e50c1d22ba4e0c8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 12:54:13 +0100 Subject: [PATCH 208/290] (#689) Do not try to update colors if no intersection geometry is present --- .../RivCrossSectionGeometryGenerator.cpp | 15 +++++++++++++++ .../RivCrossSectionGeometryGenerator.h | 2 ++ .../ModelVisualization/RivCrossSectionPartMgr.cpp | 4 ++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp index 03797b15bb..e021a433a8 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.cpp @@ -1280,6 +1280,21 @@ const RimCrossSection* RivCrossSectionGeometryGenerator::crossSection() const return m_crossSection; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivCrossSectionGeometryGenerator::isAnyGeometryPresent() const +{ + if (m_triangleVxes->size() == 0) + { + return false; + } + else + { + return true; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h index ae65f3bc35..58898eda4b 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivCrossSectionGeometryGenerator.h @@ -137,6 +137,8 @@ class RivCrossSectionGeometryGenerator : public cvf::Object const RivCrossSectionHexGridIntf* grid ); ~RivCrossSectionGeometryGenerator(); + + bool isAnyGeometryPresent() const; // Generate geometry cvf::ref generateSurface(); diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index d24ec8008c..4c4b3a83b2 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -83,14 +83,14 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) { if (m_crossSectionGenerator.isNull()) return; + if (!m_crossSectionGenerator->isAnyGeometryPresent()) return; + RimEclipseView* eclipseView; m_rimCrossSection->firstAnchestorOrThisOfType(eclipseView); if (eclipseView) { RimEclipseCellColors* cellResultColors = eclipseView->cellResult(); - - CVF_ASSERT(cellResultColors); RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); From a0775fc6ec4dbcecef29efdd89cc18baacb4ec7a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 14:02:36 +0100 Subject: [PATCH 209/290] (#688) Update bounding box for grid box model when camera changes --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 2 ++ ApplicationCode/UserInterface/RiuViewer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 0b9fc15c5a..8b21b5d602 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -160,6 +160,8 @@ void RivGridBoxGenerator::updateFromCamera(const cvf::Camera* camera) m_gridBoxModel->addPart(m_gridBoxLegendParts[2 * i + 1].p()); } } + + m_gridBoxModel->updateBoundingBoxesRecursive(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 4be74f84ea..05c0adee29 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -541,9 +541,9 @@ RimView* RiuViewer::ownerReservoirView() //-------------------------------------------------------------------------------------------------- void RiuViewer::optimizeClippingPlanes() { - caf::Viewer::optimizeClippingPlanes(); - m_gridBoxGenerator->updateFromCamera(mainCamera()); + + caf::Viewer::optimizeClippingPlanes(); } //-------------------------------------------------------------------------------------------------- From 69ced2cdf04b3fe710441898dabbe4c2f32ef415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 3 Dec 2015 10:12:03 +0100 Subject: [PATCH 210/290] (#685) Fixed errors in findMainIJKFaces that might cause crash, and incorrect mapping. Makes the example case work. --- .../GeoMechDataModel/RigFemPartGrid.cpp | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp index c877f4ada5..372b7f2078 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp @@ -245,16 +245,27 @@ cvf::Vec3i RigFemPartGrid::findMainIJKFaces(int elementIndex) const CVF_ASSERT(false); } + mainElmDirections[0].normalize(); + mainElmDirections[1].normalize(); + mainElmDirections[2].normalize(); + // Match the element main directions with best XYZ match (IJK respectively) - // Find the max component of a mainElmDirection. - // Assign the index of that mainElmDirection to the mainElmDirectionIdxForIJK at the index of the max component. + // Find the mainElmDirection with the largest component starting with Z + // and use that for the corresponding IJK direction. + // Find the Z (for K) first. Then select among the other two the Y (for J), + // and select the remaining for I int mainElmDirectionIdxForIJK[3] ={ -1, -1, -1 }; - for (int dIdx = 0; dIdx < 3; ++dIdx) + for (int cIdx = 2; cIdx >= 0 ; --cIdx) // Check Z first as it is more important { - double maxAbsComp = 0; - for (int cIdx = 2; cIdx >= 0 ; --cIdx) + double maxAbsComp = -1.0; + int usedDir1 = -1; + int usedDir2 = -1; + + for (int dIdx = 0; dIdx < 3 ; ++dIdx) { + if (dIdx == usedDir1 || dIdx == usedDir2) continue; + float absComp = fabs(mainElmDirections[dIdx][cIdx]); if (absComp > maxAbsComp) { @@ -262,25 +273,9 @@ cvf::Vec3i RigFemPartGrid::findMainIJKFaces(int elementIndex) const mainElmDirectionIdxForIJK[cIdx] = dIdx; } } - } - // make sure all the main directions are used - - bool mainDirsUsed[3] ={ false, false, false }; - mainDirsUsed[mainElmDirectionIdxForIJK[0]] = true; - mainDirsUsed[mainElmDirectionIdxForIJK[1]] = true; - mainDirsUsed[mainElmDirectionIdxForIJK[2]] = true; - - int unusedDir = -1; - if (!mainDirsUsed[0]) unusedDir = 0; - if (!mainDirsUsed[1]) unusedDir = 1; - if (!mainDirsUsed[2]) unusedDir = 2; - - if (unusedDir >= 0) - { - if (mainElmDirectionIdxForIJK[0] == mainElmDirectionIdxForIJK[1]) mainElmDirectionIdxForIJK[0] = unusedDir; - else if (mainElmDirectionIdxForIJK[1] == mainElmDirectionIdxForIJK[2]) mainElmDirectionIdxForIJK[1] = unusedDir; - else if (mainElmDirectionIdxForIJK[2] == mainElmDirectionIdxForIJK[0]) mainElmDirectionIdxForIJK[2] = unusedDir; + if (usedDir1 == -1) usedDir1 = mainElmDirectionIdxForIJK[cIdx]; + else usedDir2 = mainElmDirectionIdxForIJK[cIdx]; } // Assign the correct face based on the main direction From 1977578d90ae397636ebd0c01fc57ff4a647a44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 3 Dec 2015 16:23:41 +0100 Subject: [PATCH 211/290] Fixed error in Fem to Eclipse rangefilter mapping. The Fem elment was rotated again and again, bsed on previous rotation. Need to use the original rotation each time. --- .../RigCaseToCaseRangeFilterMapper.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp index 8af8e0f1d3..f8b2a55099 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.cpp @@ -444,6 +444,7 @@ RigCaseToCaseRangeFilterMapper::findBestEclCellFromFemCell(const RigFemPart* dep cvf::Vec3d elmCenter = RigCaseToCaseCellMapperTools::calculateCellCenter(elmCorners); bool foundExactMatch = false; + cvf::Vec3d rotatedElm[8]; for (size_t ccIdx = 0; ccIdx < closeCells.size(); ++ccIdx) { @@ -458,10 +459,19 @@ RigCaseToCaseRangeFilterMapper::findBestEclCellFromFemCell(const RigFemPart* dep globCellIdxToBestMatch = cellIdx; sqDistToClosestCellCenter = sqDist; } - - RigCaseToCaseCellMapperTools::rotateCellTopologicallyToMatchBaseCell(geoMechConvertedEclCell, isEclFaceNormalsOutwards, elmCorners); - - foundExactMatch = RigCaseToCaseCellMapperTools::isEclFemCellsMatching(geoMechConvertedEclCell, elmCorners, + + rotatedElm[0] = elmCorners[0]; + rotatedElm[1] = elmCorners[1]; + rotatedElm[2] = elmCorners[2]; + rotatedElm[3] = elmCorners[3]; + rotatedElm[4] = elmCorners[4]; + rotatedElm[5] = elmCorners[5]; + rotatedElm[6] = elmCorners[6]; + rotatedElm[7] = elmCorners[7]; + + RigCaseToCaseCellMapperTools::rotateCellTopologicallyToMatchBaseCell(geoMechConvertedEclCell, isEclFaceNormalsOutwards, rotatedElm); + + foundExactMatch = RigCaseToCaseCellMapperTools::isEclFemCellsMatching(geoMechConvertedEclCell, rotatedElm, xyTolerance, zTolerance); if (foundExactMatch) From c4eee507a877466f0f1f9639edd057705f553ccf Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 19:13:12 +0100 Subject: [PATCH 212/290] (#404) Use only one structure for well path geometry --- .../ModelVisualization/RivWellPathPartMgr.cpp | 39 ++++++++++++------- .../ModelVisualization/RivWellPathPartMgr.h | 2 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp index 0182ab3ccf..e7dfeb845b 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -90,7 +90,7 @@ RivWellPathPartMgr::RivWellPathPartMgr(RimWellPathCollection* wellPathCollection //-------------------------------------------------------------------------------------------------- RivWellPathPartMgr::~RivWellPathPartMgr() { - + clearAllBranchData(); } //-------------------------------------------------------------------------------------------------- @@ -106,15 +106,14 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl if (wellPathGeometry->m_wellPathPoints.size() < 2) return; - m_wellBranches.clear(); + clearAllBranchData(); double wellPathRadius = m_wellPathCollection->wellPathRadiusScaleFactor() * m_rimWellPath->wellPathRadiusScaleFactor() * characteristicCellSize; cvf::Vec3d textPosition = wellPathGeometry->m_wellPathPoints[0]; // Generate the well path geometry as a line and pipe structure { - m_wellBranches.push_back(RivPipeBranchData()); - RivPipeBranchData& pbd = m_wellBranches.back(); + RivPipeBranchData& pbd = m_pipeBranchData; pbd.m_pipeGeomGenerator = new RivPipeGeometryGenerator; @@ -243,17 +242,14 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* m buildWellPathParts(displayModelOffset, characteristicCellSize, wellPathClipBoundingBox); } - std::list::iterator it; - for (it = m_wellBranches.begin(); it != m_wellBranches.end(); ++it) + if (m_pipeBranchData.m_surfacePart.notNull()) { - if (it->m_surfacePart.notNull()) - { - model->addPart(it->m_surfacePart.p()); - } - if (it->m_centerLinePart.notNull()) - { - model->addPart(it->m_centerLinePart.p()); - } + model->addPart(m_pipeBranchData.m_surfacePart.p()); + } + + if (m_pipeBranchData.m_centerLinePart.notNull()) + { + model->addPart(m_pipeBranchData.m_centerLinePart.p()); } if (m_wellLabelPart.notNull()) @@ -262,6 +258,9 @@ void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* m } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- void RivWellPathPartMgr::setScaleTransform( cvf::Transform * scaleTransform ) { if (m_scaleTransform.isNull() || m_scaleTransform.p() != scaleTransform) @@ -270,3 +269,15 @@ void RivWellPathPartMgr::setScaleTransform( cvf::Transform * scaleTransform ) scheduleGeometryRegen(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivWellPathPartMgr::clearAllBranchData() +{ + m_pipeBranchData.m_pipeGeomGenerator = NULL; + m_pipeBranchData.m_surfacePart = NULL; + m_pipeBranchData.m_surfaceDrawable = NULL; + m_pipeBranchData.m_centerLinePart = NULL; + m_pipeBranchData.m_centerLineDrawable = NULL; +} diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h index 911c816d19..b9b50b4c97 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h @@ -60,6 +60,7 @@ class RivWellPathPartMgr : public cvf::Object bool m_needsTransformUpdate; void buildWellPathParts(cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox); + void clearAllBranchData(); struct RivPipeBranchData { @@ -71,7 +72,6 @@ class RivWellPathPartMgr : public cvf::Object }; RivPipeBranchData m_pipeBranchData; - std::list m_wellBranches; cvf::ref m_wellLabelPart; cvf::ref m_scalarMapper; From 27db48a336c6000ab776ec94242ad33f17a415c9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 3 Dec 2015 19:31:34 +0100 Subject: [PATCH 213/290] (#404) Cleaned up includes and removed collection from constructor --- .../ModelVisualization/RivWellPathPartMgr.cpp | 69 +++++++++---------- .../ModelVisualization/RivWellPathPartMgr.h | 5 +- .../ProjectDataModel/RimWellPath.cpp | 10 ++- 3 files changed, 36 insertions(+), 48 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp index e7dfeb845b..e9332d80b6 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -19,47 +19,35 @@ ///////////////////////////////////////////////////////////////////////////////// -#include "cvfLibCore.h" +#include "RivWellPathPartMgr.h" #include "RiaApplication.h" -#include "RimEclipseCase.h" -#include "RimProject.h" -#include "RimWellPathCollection.h" -#include "RimReservoirCellResultsStorage.h" -#include "RimIdenticalGridCaseGroup.h" -#include "RimScriptCollection.h" -#include "RimCaseCollection.h" -#include "RimEclipseCellColors.h" -#include "RimCellEdgeColors.h" -#include "RimCellRangeFilterCollection.h" -#include "RimEclipsePropertyFilterCollection.h" -#include "RimEclipseWellCollection.h" -#include "Rim3dOverlayInfoConfig.h" -#include "RimEclipseView.h" -#include "RigCaseData.h" -#include "RigCell.h" -#include "RivWellPathPartMgr.h" -#include "RivWellPathSourceInfo.h" + +#include "RigWellPath.h" + #include "RimWellPath.h" +#include "RimWellPathCollection.h" + #include "RivPipeGeometryGenerator.h" +#include "RivWellPathSourceInfo.h" + +#include "cafEffectGenerator.h" + +#include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" +#include "cvfFont.h" #include "cvfModelBasicList.h" -#include "cvfTransform.h" #include "cvfPart.h" #include "cvfScalarMapperDiscreteLinear.h" -#include "cvfDrawableGeo.h" -#include "cvfDrawableText.h" -#include "cvfRay.h" -#include "cafEffectGenerator.h" +#include "cvfTransform.h" #include "cvfqtUtils.h" -#include "RimOilField.h" -#include "RimEclipseCaseCollection.h" + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivWellPathPartMgr::RivWellPathPartMgr(RimWellPathCollection* wellPathCollection, RimWellPath* wellPath) +RivWellPathPartMgr::RivWellPathPartMgr(RimWellPath* wellPath) { - m_wellPathCollection = wellPathCollection; m_rimWellPath = wellPath; m_needsTransformUpdate = true; @@ -99,7 +87,9 @@ RivWellPathPartMgr::~RivWellPathPartMgr() void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox) { - if (m_wellPathCollection.isNull()) return; + RimWellPathCollection* wellPathCollection = NULL; + m_rimWellPath->firstAnchestorOrThisOfType(wellPathCollection); + if (!wellPathCollection) return; RigWellPath* wellPathGeometry = m_rimWellPath->wellPathGeometry(); if (!wellPathGeometry) return; @@ -107,7 +97,7 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl if (wellPathGeometry->m_wellPathPoints.size() < 2) return; clearAllBranchData(); - double wellPathRadius = m_wellPathCollection->wellPathRadiusScaleFactor() * m_rimWellPath->wellPathRadiusScaleFactor() * characteristicCellSize; + double wellPathRadius = wellPathCollection->wellPathRadiusScaleFactor() * m_rimWellPath->wellPathRadiusScaleFactor() * characteristicCellSize; cvf::Vec3d textPosition = wellPathGeometry->m_wellPathPoints[0]; @@ -118,17 +108,17 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl pbd.m_pipeGeomGenerator = new RivPipeGeometryGenerator; pbd.m_pipeGeomGenerator->setRadius(wellPathRadius); - pbd.m_pipeGeomGenerator->setCrossSectionVertexCount(m_wellPathCollection->wellPathCrossSectionVertexCount()); + pbd.m_pipeGeomGenerator->setCrossSectionVertexCount(wellPathCollection->wellPathCrossSectionVertexCount()); pbd.m_pipeGeomGenerator->setPipeColor( m_rimWellPath->wellPathColor()); cvf::ref cvfCoords = new cvf::Vec3dArray; - if (m_wellPathCollection->wellPathClip) + if (wellPathCollection->wellPathClip) { std::vector clippedPoints; for (size_t idx = 0; idx < wellPathGeometry->m_wellPathPoints.size(); idx++) { cvf::Vec3d point = wellPathGeometry->m_wellPathPoints[idx]; - if (point.z() < (wellPathClipBoundingBox.max().z() + m_wellPathCollection->wellPathClipZDistance)) + if (point.z() < (wellPathClipBoundingBox.max().z() + wellPathCollection->wellPathClipZDistance)) clippedPoints.push_back(point); } if (clippedPoints.size() < 2) return; @@ -188,7 +178,7 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl textPosition.z() += 1.2 * characteristicCellSize; m_wellLabelPart = NULL; - if (m_wellPathCollection->showWellPathLabel() && m_rimWellPath->showWellPathLabel() && !m_rimWellPath->name().isEmpty()) + if (wellPathCollection->showWellPathLabel() && m_rimWellPath->showWellPathLabel() && !m_rimWellPath->name().isEmpty()) { cvf::Font* standardFont = RiaApplication::instance()->standardFont(); @@ -198,7 +188,7 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl drawableText->setDrawBorder(false); drawableText->setDrawBackground(false); drawableText->setVerticalAlignment(cvf::TextDrawer::CENTER); - drawableText->setTextColor(m_wellPathCollection->wellPathLabelColor()); + drawableText->setTextColor(wellPathCollection->wellPathLabelColor()); cvf::String cvfString = cvfqt::Utils::toString(m_rimWellPath->name()); @@ -227,13 +217,16 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl void RivWellPathPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* model, cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox) { - if (m_wellPathCollection.isNull()) return; + RimWellPathCollection* wellPathCollection = NULL; + m_rimWellPath->firstAnchestorOrThisOfType(wellPathCollection); + if (!wellPathCollection) return; + if (m_rimWellPath.isNull()) return; - if (m_wellPathCollection->wellPathVisibility() == RimWellPathCollection::FORCE_ALL_OFF) + if (wellPathCollection->wellPathVisibility() == RimWellPathCollection::FORCE_ALL_OFF) return; - if (m_wellPathCollection->wellPathVisibility() != RimWellPathCollection::FORCE_ALL_ON && m_rimWellPath->showWellPath() == false ) + if (wellPathCollection->wellPathVisibility() != RimWellPathCollection::FORCE_ALL_ON && m_rimWellPath->showWellPath() == false ) return; if (m_needsTransformUpdate) diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h index b9b50b4c97..16828f9123 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h @@ -22,7 +22,6 @@ #include "cafPdmPointer.h" #include "cvfBoundingBox.h" -#include namespace cvf { @@ -37,12 +36,11 @@ namespace cvf class RivPipeGeometryGenerator; class RimProject; class RimWellPath; -class RimWellPathCollection; class RivWellPathPartMgr : public cvf::Object { public: - RivWellPathPartMgr(RimWellPathCollection* wellPathCollection, RimWellPath* wellPath); + RivWellPathPartMgr(RimWellPath* wellPath); ~RivWellPathPartMgr(); void setScaleTransform(cvf::Transform * scaleTransform); @@ -53,7 +51,6 @@ class RivWellPathPartMgr : public cvf::Object double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox); private: - caf::PdmPointer m_wellPathCollection; caf::PdmPointer m_rimWellPath; cvf::ref m_scaleTransform; diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.cpp b/ApplicationCode/ProjectDataModel/RimWellPath.cpp index e6d0797d55..6689eba785 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPath.cpp @@ -129,7 +129,6 @@ caf::PdmFieldHandle* RimWellPath::userDescriptionField() return &name; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -142,20 +141,21 @@ void RimWellPath::setSurveyType(QString surveyType) wellPathColor = cvf::Color3f(0.0f, 0.333f, 0.999f); } - +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- RivWellPathPartMgr* RimWellPath::partMgr() { if (m_wellPathPartMgr.isNull()) { RimWellPathCollection* wpColl; this->firstAnchestorOrThisOfType(wpColl); - if (wpColl) m_wellPathPartMgr = new RivWellPathPartMgr(wpColl, this); + if (wpColl) m_wellPathPartMgr = new RivWellPathPartMgr(this); } return m_wellPathPartMgr.p(); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -168,7 +168,6 @@ void RimWellPath::fieldChangedByUi(const caf::PdmFieldHandle* changedField, cons if (proj) proj->createDisplayModelAndRedrawAllViews(); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -177,7 +176,6 @@ caf::PdmFieldHandle* RimWellPath::objectToggleField() return &showWellPath; } - //-------------------------------------------------------------------------------------------------- /// Read JSON or ascii file containing well path data //-------------------------------------------------------------------------------------------------- From 6d60088a5b226b29086ed21ba8a8a1b060c5cd71 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 4 Dec 2015 11:54:29 +0100 Subject: [PATCH 214/290] Added projection of point on line --- .../ReservoirDataModel/cvfGeometryTools.cpp | 26 ++++++++++++++++++- .../ReservoirDataModel/cvfGeometryTools.h | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp index 9bcd485893..7c1fc0c5ee 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp @@ -327,7 +327,31 @@ GeometryTools::inPlaneLineIntersect3D( const cvf::Vec3d& planeNormal, //-------------------------------------------------------------------------------------------------- -/// +/// Compute projection of point p3 on the line p1 - p2 +// If projection is out side the line segment, the end of line is returned +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d GeometryTools::projectPointOnLine(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, double* normalizedIntersection) +{ + cvf::Vec3d v31 = p3 - p1; + cvf::Vec3d v21 = p2 - p1; + + double u = (v31*v21) / (v21*v21); + cvf::Vec3d projectedPoint(0, 0, 0); + if (0 < u && u < 1) projectedPoint = p1 + u*v21; + else if (u <= 0) projectedPoint = p1; + else projectedPoint = p2; + + if (normalizedIntersection) + { + *normalizedIntersection = u; + } + + return projectedPoint; +} + + +//-------------------------------------------------------------------------------------------------- +/// TODO: Use GeometryTools::projectPointOnLine //-------------------------------------------------------------------------------------------------- double GeometryTools::linePointSquareDist(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3) { diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h index 2c1478a983..538a856b03 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h @@ -36,6 +36,8 @@ class GeometryTools public: static cvf::Vec3d computeFaceCenter(const cvf::Vec3d& v0, const cvf::Vec3d& v1, const cvf::Vec3d& v2, const cvf::Vec3d& v3); + static cvf::Vec3d projectPointOnLine(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3, double* normalizedIntersection); + static double linePointSquareDist(const cvf::Vec3d& p1, const cvf::Vec3d& p2, const cvf::Vec3d& p3); static int intersectLineSegmentTriangle( const cvf::Vec3d p0, const cvf::Vec3d p1, const cvf::Vec3d t0, const cvf::Vec3d t1, const cvf::Vec3d t2, From 622e49fe69b9341b6cc161da84c1e31387340a60 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 4 Dec 2015 12:05:06 +0100 Subject: [PATCH 215/290] (#404) Compute well segment index from triangle index --- .../RivPipeGeometryGenerator.cpp | 23 ++++++++++++++- .../RivPipeGeometryGenerator.h | 13 +++++---- .../ModelVisualization/RivWellPathPartMgr.cpp | 28 +++++++++++++++++-- .../ModelVisualization/RivWellPathPartMgr.h | 3 +- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp index 19bff35595..71b1404ddc 100644 --- a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp @@ -1,6 +1,8 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -35,6 +37,7 @@ RivPipeGeometryGenerator::RivPipeGeometryGenerator() m_crossSectionNodeCount = 8; m_minimumBendAngle = 80.0; m_bendScalingFactor = 0.00001; + m_firstSegmentIndex = 0; } //-------------------------------------------------------------------------------------------------- @@ -582,3 +585,21 @@ void RivPipeGeometryGenerator::clearComputedData() m_filteredPipeSegmentToResult.clear(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RivPipeGeometryGenerator::segmentIndexFromTriangleIndex(size_t triangleIndex) const +{ + size_t filteredIndex = triangleIndex / (m_crossSectionNodeCount * 2); + + return filteredIndex + m_firstSegmentIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// Well pipes are clipped, set index to first segment in visible well path +//-------------------------------------------------------------------------------------------------- +void RivPipeGeometryGenerator::setFirstSegmentIndex(size_t segmentIndex) +{ + m_firstSegmentIndex = segmentIndex; +} + diff --git a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.h index 40a392ada8..657d5a15b2 100644 --- a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.h @@ -1,6 +1,8 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// Copyright (C) Statoil ASA +// Copyright (C) Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,8 +20,6 @@ #pragma once -//class RivPipeQuadToSegmentMapper; - class RivPipeGeometryGenerator : public cvf::Object { public: @@ -31,6 +31,7 @@ class RivPipeGeometryGenerator : public cvf::Object // Pipe bends with a opening angle below given angle is modified with extra bend coordinates void setMinimumBendAngle(double degrees); + // Scaling factor used to control how far from original pipe position the extra bend coordinates are located // This will affect how sharp or smooth bend will appear void setBendScalingFactor(double scaleFactor); @@ -46,6 +47,9 @@ class RivPipeGeometryGenerator : public cvf::Object void pipeSurfaceTextureCoords(cvf::Vec2fArray* textureCoords, const std::vector& segmentResults, const cvf::ScalarMapper* mapper) const; void centerlineTextureCoords(cvf::Vec2fArray* textureCoords, const std::vector& segmentResults, const cvf::ScalarMapper* mapper) const; + void setFirstSegmentIndex(size_t segmentIndex); + size_t segmentIndexFromTriangleIndex(size_t triangleIndex) const; + private: void clearComputedData(); void updateFilteredPipeCenterCoords(); @@ -72,8 +76,7 @@ class RivPipeGeometryGenerator : public cvf::Object // Map from generated cylinder segments to pipe result indices std::vector m_filteredPipeSegmentToResult; - // TODO: implement - //RivPipeQuadToSegmentMapper* m_quadToSegmentMapper; + size_t m_firstSegmentIndex; double m_radius; double m_minimumBendAngle; diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp index e9332d80b6..f390936e24 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -114,13 +114,29 @@ void RivWellPathPartMgr::buildWellPathParts(cvf::Vec3d displayModelOffset, doubl cvf::ref cvfCoords = new cvf::Vec3dArray; if (wellPathCollection->wellPathClip) { - std::vector clippedPoints; + size_t firstVisibleSegmentIndex = cvf::UNDEFINED_SIZE_T; for (size_t idx = 0; idx < wellPathGeometry->m_wellPathPoints.size(); idx++) { cvf::Vec3d point = wellPathGeometry->m_wellPathPoints[idx]; if (point.z() < (wellPathClipBoundingBox.max().z() + wellPathCollection->wellPathClipZDistance)) - clippedPoints.push_back(point); + { + firstVisibleSegmentIndex = idx; + break; + } + } + + std::vector clippedPoints; + + if (firstVisibleSegmentIndex != cvf::UNDEFINED_SIZE_T) + { + for (size_t idx = firstVisibleSegmentIndex; idx < wellPathGeometry->m_wellPathPoints.size(); idx++) + { + clippedPoints.push_back(wellPathGeometry->m_wellPathPoints[idx]); + } + + pbd.m_pipeGeomGenerator->setFirstSegmentIndex(firstVisibleSegmentIndex); } + if (clippedPoints.size() < 2) return; textPosition = clippedPoints[0]; @@ -274,3 +290,11 @@ void RivWellPathPartMgr::clearAllBranchData() m_pipeBranchData.m_centerLinePart = NULL; m_pipeBranchData.m_centerLineDrawable = NULL; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RivWellPathPartMgr::segmentIndexFromTriangleIndex(size_t triangleIndex) +{ + return m_pipeBranchData.m_pipeGeomGenerator->segmentIndexFromTriangleIndex(triangleIndex); +} diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h index 16828f9123..18e8e1c646 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.h @@ -50,6 +50,8 @@ class RivWellPathPartMgr : public cvf::Object void appendStaticGeometryPartsToModel(cvf::ModelBasicList* model, cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox); + size_t segmentIndexFromTriangleIndex(size_t triangleIndex); + private: caf::PdmPointer m_rimWellPath; @@ -58,7 +60,6 @@ class RivWellPathPartMgr : public cvf::Object void buildWellPathParts(cvf::Vec3d displayModelOffset, double characteristicCellSize, cvf::BoundingBox wellPathClipBoundingBox); void clearAllBranchData(); - struct RivPipeBranchData { cvf::ref m_pipeGeomGenerator; From 27206cab3bca57bcb0c8c6552fe4bcf34edb20ee Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 4 Dec 2015 12:05:43 +0100 Subject: [PATCH 216/290] (#404) Added display of picked well path text in Result Info --- .../RivWellPathSourceInfo.cpp | 72 ++++++++++++++++++- .../RivWellPathSourceInfo.h | 21 ++++-- .../UserInterface/RiuViewerCommands.cpp | 38 +++++++--- 3 files changed, 111 insertions(+), 20 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp index 3445907400..e6b6ebbddc 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp @@ -19,18 +19,20 @@ #include "RivWellPathSourceInfo.h" +#include "RimCase.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" -#include "RivPipeQuadToSegmentMapper.h" +#include "RivWellPathPartMgr.h" + +#include "cvfGeometryTools.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivWellPathSourceInfo::RivWellPathSourceInfo(RimWellPath* wellPath/*, RivPipeQuadToSegmentMapper* quadToSegmentMapper*/) +RivWellPathSourceInfo::RivWellPathSourceInfo(RimWellPath* wellPath) { m_wellPath = wellPath; - //m_quadToSegmentMapper = quadToSegmentMapper; } //-------------------------------------------------------------------------------------------------- @@ -40,3 +42,67 @@ RimWellPath* RivWellPathSourceInfo::wellPath() const { return m_wellPath.p(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RivWellPathSourceInfo::measuredDepth(size_t triangleIndex, const cvf::Vec3d& globalIntersection) const +{ + size_t firstSegmentIndex = cvf::UNDEFINED_SIZE_T; + double norm = 0.0; + + normalizedIntersection(triangleIndex, globalIntersection, &firstSegmentIndex, &norm); + + double firstDepth = m_wellPath->wellPathGeometry()->m_measuredDepths[firstSegmentIndex]; + double secDepth = m_wellPath->wellPathGeometry()->m_measuredDepths[firstSegmentIndex + 1]; + + return firstDepth * (1.0 - norm) + norm * secDepth; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RivWellPathSourceInfo::trueVerticalDepth(size_t triangleIndex, const cvf::Vec3d& globalIntersection) const +{ + size_t firstSegmentIndex = cvf::UNDEFINED_SIZE_T; + double norm = 0.0; + + normalizedIntersection(triangleIndex, globalIntersection, &firstSegmentIndex, &norm); + + cvf::Vec3d firstDepth = m_wellPath->wellPathGeometry()->m_wellPathPoints[firstSegmentIndex]; + cvf::Vec3d secDepth = m_wellPath->wellPathGeometry()->m_wellPathPoints[firstSegmentIndex + 1]; + + return firstDepth * (1.0 - norm) + norm * secDepth; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivWellPathSourceInfo::normalizedIntersection(size_t triangleIndex, const cvf::Vec3d& globalIntersection, + size_t* firstSegmentIndex, double* normalizedSegmentIntersection) const +{ + size_t segIndex = segmentIndex(triangleIndex); + + RigWellPath* rigWellPath = m_wellPath->wellPathGeometry(); + + cvf::Vec3d segmentStart = rigWellPath->m_wellPathPoints[segIndex]; + cvf::Vec3d segmentEnd = rigWellPath->m_wellPathPoints[segIndex + 1]; + + double norm = 0.0; + cvf::Vec3d pointOnLine = cvf::GeometryTools::projectPointOnLine(segmentStart, segmentEnd, globalIntersection, &norm); + CVF_ASSERT(0.0 < norm && norm < 1.0); + + cvf::Math::clamp(norm, 0.0, 1.0); + + *firstSegmentIndex = segIndex; + *normalizedSegmentIntersection = norm; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RivWellPathSourceInfo::segmentIndex(size_t triangleIndex) const +{ + return m_wellPath->partMgr()->segmentIndexFromTriangleIndex(triangleIndex); +} + diff --git a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.h b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.h index 4ae7bcf59b..27d24ad0bd 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.h +++ b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.h @@ -19,25 +19,32 @@ #pragma once +#include "cafPdmPointer.h" + #include "cvfBase.h" #include "cvfObject.h" -#include "cafPdmPointer.h" +#include "cvfVector3.h" class RimWellPath; -//class RivPipeQuadToSegmentMapper; //================================================================================================== /// -/// TODO: Implement and add RivPipeQuadToSegmentMapper //================================================================================================== class RivWellPathSourceInfo : public cvf::Object { public: - RivWellPathSourceInfo(RimWellPath* wellPath/*, RivPipeQuadToSegmentMapper* quadToSegmentMapper*/); + RivWellPathSourceInfo(RimWellPath* wellPath); RimWellPath* wellPath() const; -private: - caf::PdmPointer m_wellPath; - //RivPipeQuadToSegmentMapper* m_quadToSegmentMapper; + size_t segmentIndex(size_t triangleIndex) const; + double measuredDepth(size_t triangleIndex, const cvf::Vec3d& globalIntersection) const; + cvf::Vec3d trueVerticalDepth(size_t triangleIndex, const cvf::Vec3d& globalIntersection) const; + +private: + void normalizedIntersection(size_t triangleIndex, const cvf::Vec3d& globalIntersection, + size_t* firstSegmentIndex, double* normalizedSegmentIntersection) const; + +private: + caf::PdmPointer m_wellPath; }; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index fcc21b805a..0bb23d1ae2 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -417,7 +417,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM size_t gridIndex = cvf::UNDEFINED_SIZE_T; size_t cellIndex = cvf::UNDEFINED_SIZE_T; size_t nncIndex = cvf::UNDEFINED_SIZE_T; - RimWellPath* wellPath = NULL; cvf::StructGridInterface::FaceType face = cvf::StructGridInterface::NO_FACE; cvf::Vec3d localIntersectionPoint(cvf::Vec3d::ZERO); @@ -473,7 +472,34 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } else if (wellPathSourceInfo) { - wellPath = wellPathSourceInfo->wellPath(); + cvf::Vec3d displayModelOffset = cvf::Vec3d::ZERO; + + RimCase* rimCase = NULL; + m_reservoirView->firstAnchestorOrThisOfType(rimCase); + if (rimCase) + { + displayModelOffset = rimCase->displayModelOffset(); + } + + cvf::Vec3d unscaledIntersection = localIntersectionPoint; + unscaledIntersection.z() /= m_reservoirView->scaleZ; + + size_t wellSegmentIndex = wellPathSourceInfo->segmentIndex(firstPartTriangleIndex); + double measuredDepth = wellPathSourceInfo->measuredDepth(firstPartTriangleIndex, unscaledIntersection + displayModelOffset); + cvf::Vec3d trueVerticalDepth = wellPathSourceInfo->trueVerticalDepth(firstPartTriangleIndex, unscaledIntersection + displayModelOffset); + + QString wellPathText; + wellPathText += wellPathSourceInfo->wellPath()->name; + wellPathText += "\n"; + wellPathText += QString("Well path segment index : %1\n").arg(wellSegmentIndex); + wellPathText += QString("Measured depth : %1\n").arg(measuredDepth); + + QString formattedText; + formattedText.sprintf("Intersection point : [E: %.2f, N: %.2f, Depth: %.2f]", trueVerticalDepth.x(), trueVerticalDepth.y(), -trueVerticalDepth.z()); + wellPathText += formattedText; + + RiuMainWindow::instance()->setResultInfo(wellPathText); + } else if (crossSectionSourceInfo) { @@ -536,14 +562,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM RiuSelectionManager::instance()->setSelectedItem(selItem); } } - - if (wellPath) - { - QString pickInfo = QString("Well path hit: %1").arg(wellPath->name()); - - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - mainWnd->statusBar()->showMessage(pickInfo); - } } //-------------------------------------------------------------------------------------------------- From e65facd5902d39b0406ad65ab34b1601392d7494 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 4 Dec 2015 15:15:13 +0100 Subject: [PATCH 217/290] (#404) Added RicViewerEventInterface and moved well path text display into a separate class --- .../RicNewPolylineCrossSectionFeature.cpp | 4 +- .../RicNewPolylineCrossSectionFeature.h | 6 +- .../Commands/RicViewerEventInterface.h | 53 +++++++++++ .../WellPathCommands/CMakeLists_files.cmake | 2 + .../RicWellPathViewerEventHandler.cpp | 92 +++++++++++++++++++ .../RicWellPathViewerEventHandler.h} | 24 ++--- .../ProjectDataModel/RimCrossSection.cpp | 2 - .../UserInterface/RiuViewerCommands.cpp | 58 +++--------- .../UserInterface/RiuViewerCommands.h | 4 +- 9 files changed, 176 insertions(+), 69 deletions(-) create mode 100644 ApplicationCode/Commands/RicViewerEventInterface.h create mode 100644 ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp rename ApplicationCode/Commands/{RicCommandFeature.h => WellPathCommands/RicWellPathViewerEventHandler.h} (65%) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp index a626f71209..502fc11703 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp @@ -78,14 +78,14 @@ void RicNewPolylineCrossSectionFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicNewPolylineCrossSectionFeature::handleUiEvent(cvf::Object* uiEventObject) +bool RicNewPolylineCrossSectionFeature::handleEvent(cvf::Object* eventObject) { std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); if (selection.size() == 1) { - RicLocalIntersectionUiEvent* polylineUiEvent = dynamic_cast(uiEventObject); + RicViewerEventObject* polylineUiEvent = dynamic_cast(eventObject); if (polylineUiEvent) { RimCrossSection* crossSection = selection[0]; diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h index 6900672c4e..c6ae47e624 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.h @@ -19,7 +19,7 @@ #pragma once -#include "RicCommandFeature.h" +#include "RicViewerEventInterface.h" #include "cafCmdExecuteCommand.h" #include "cafPdmPointer.h" @@ -53,7 +53,7 @@ class RicNewPolylineCrossSectionFeatureCmd : public caf::CmdExecuteCommand //================================================================================================== /// //================================================================================================== -class RicNewPolylineCrossSectionFeature : public RicCommandFeature +class RicNewPolylineCrossSectionFeature : public caf::CmdFeature, public RicViewerEventInterface { CAF_CMD_HEADER_INIT; @@ -66,7 +66,7 @@ class RicNewPolylineCrossSectionFeature : public RicCommandFeature virtual void onActionTriggered( bool isChecked ); virtual void setupActionLook( QAction* actionToSetup ); - virtual bool handleUiEvent(cvf::Object* uiEventObject); + virtual bool handleEvent(cvf::Object* eventObject); }; diff --git a/ApplicationCode/Commands/RicViewerEventInterface.h b/ApplicationCode/Commands/RicViewerEventInterface.h new file mode 100644 index 0000000000..837532136c --- /dev/null +++ b/ApplicationCode/Commands/RicViewerEventInterface.h @@ -0,0 +1,53 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +namespace cvf { + class Part; +} + +class RicViewerEventInterface +{ +public: + virtual bool handleEvent(cvf::Object* eventObject) = 0; +}; + + +class RicViewerEventObject : public cvf::Object +{ +public: + RicViewerEventObject(cvf::Vec3d localIntersectionPoint, cvf::Part* firstHitPart, cvf::uint firstPartTriangleIndex) + : localIntersectionPoint(localIntersectionPoint), + firstHitPart(firstHitPart), + firstPartTriangleIndex(firstPartTriangleIndex) + { + } + + cvf::Vec3d localIntersectionPoint; + cvf::Part* firstHitPart; + cvf::uint firstPartTriangleIndex; +}; + diff --git a/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake index 41ab4db8f8..0deea938f8 100644 --- a/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake @@ -9,6 +9,7 @@ ${CEE_CURRENT_LIST_DIR}RicWellPathDeleteFeature.h ${CEE_CURRENT_LIST_DIR}RicWellPathsDeleteAllFeature.h ${CEE_CURRENT_LIST_DIR}RicWellPathsImportFileFeature.h ${CEE_CURRENT_LIST_DIR}RicWellPathsImportSsihubFeature.h +${CEE_CURRENT_LIST_DIR}RicWellPathViewerEventHandler.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -16,6 +17,7 @@ ${CEE_CURRENT_LIST_DIR}RicWellPathDeleteFeature.cpp ${CEE_CURRENT_LIST_DIR}RicWellPathsDeleteAllFeature.cpp ${CEE_CURRENT_LIST_DIR}RicWellPathsImportFileFeature.cpp ${CEE_CURRENT_LIST_DIR}RicWellPathsImportSsihubFeature.cpp +${CEE_CURRENT_LIST_DIR}RicWellPathViewerEventHandler.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp new file mode 100644 index 0000000000..bd43abca7b --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp @@ -0,0 +1,92 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicWellPathViewerEventHandler.h" + +#include "RiaApplication.h" + +#include "RimCase.h" +#include "RimView.h" +#include "RimWellPath.h" +#include "RiuMainWindow.h" + +#include "RivWellPathSourceInfo.h" + +#include "cvfPart.h" +#include "cvfVector3.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathViewerEventHandler* RicWellPathViewerEventHandler::instance() +{ + static RicWellPathViewerEventHandler* singleton = new RicWellPathViewerEventHandler; + return singleton; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicWellPathViewerEventHandler::handleEvent(cvf::Object* eventObject) +{ + RicViewerEventObject* uiEvent = dynamic_cast(eventObject); + if (!uiEvent) return false; + + if (uiEvent->firstHitPart && uiEvent->firstHitPart->sourceInfo()) + { + const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(uiEvent->firstHitPart->sourceInfo()); + if (wellPathSourceInfo) + { + cvf::Vec3d displayModelOffset = cvf::Vec3d::ZERO; + + RimView* activeView = RiaApplication::instance()->activeReservoirView(); + if (!activeView) return false; + + RimCase* rimCase = NULL; + activeView->firstAnchestorOrThisOfType(rimCase); + if (rimCase) + { + displayModelOffset = rimCase->displayModelOffset(); + } + + cvf::Vec3d unscaledIntersection = uiEvent->localIntersectionPoint; + unscaledIntersection.z() /= activeView->scaleZ; + + size_t wellSegmentIndex = wellPathSourceInfo->segmentIndex(uiEvent->firstPartTriangleIndex); + double measuredDepth = wellPathSourceInfo->measuredDepth(uiEvent->firstPartTriangleIndex, unscaledIntersection + displayModelOffset); + cvf::Vec3d trueVerticalDepth = wellPathSourceInfo->trueVerticalDepth(uiEvent->firstPartTriangleIndex, unscaledIntersection + displayModelOffset); + + QString wellPathText; + wellPathText += QString("Well path name : %1\n").arg(wellPathSourceInfo->wellPath()->name); + wellPathText += QString("Measured depth : %1\n").arg(measuredDepth); + + QString formattedText; + formattedText.sprintf("Intersection point : [E: %.2f, N: %.2f, Depth: %.2f]", trueVerticalDepth.x(), trueVerticalDepth.y(), -trueVerticalDepth.z()); + wellPathText += formattedText; + + RiuMainWindow::instance()->setResultInfo(wellPathText); + + return true; + } + } + + return false; +} + diff --git a/ApplicationCode/Commands/RicCommandFeature.h b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.h similarity index 65% rename from ApplicationCode/Commands/RicCommandFeature.h rename to ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.h index aed7624bf5..305e856ab8 100644 --- a/ApplicationCode/Commands/RicCommandFeature.h +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.h @@ -19,27 +19,17 @@ #pragma once -#include "cafCmdFeature.h" +#include "RicViewerEventInterface.h" -#include "cvfBase.h" -#include "cvfObject.h" -#include "cvfVector3.h" - -class RicCommandFeature : public caf::CmdFeature -{ -public: - virtual bool handleUiEvent(cvf::Object* uiEventObject) = 0; -}; - -class RicLocalIntersectionUiEvent : public cvf::Object +//================================================================================================== +/// +//================================================================================================== +class RicWellPathViewerEventHandler : public RicViewerEventInterface { public: - RicLocalIntersectionUiEvent(cvf::Vec3d localIntersectionPoint) - : localIntersectionPoint(localIntersectionPoint) - { - } + static RicWellPathViewerEventHandler* instance(); - cvf::Vec3d localIntersectionPoint; + virtual bool handleEvent(cvf::Object* eventObject); }; diff --git a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp index cea704e7a5..40f3ffcc77 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSection.cpp @@ -21,8 +21,6 @@ #include "RiaApplication.h" -#include "RicCommandFeature.h" - #include "RigSimulationWellCenterLineCalculator.h" #include "RimCase.h" diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 0bb23d1ae2..057fb262c8 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -19,7 +19,7 @@ #include "RiuViewerCommands.h" -#include "RicCommandFeature.h" +#include "RicViewerEventInterface.h" #include "RicEclipsePropertyFilterNewExec.h" #include "RicGeoMechPropertyFilterNewExec.h" #include "RicRangeFilterNewExec.h" @@ -65,10 +65,13 @@ #include "cvfHitItemCollection.h" #include "cvfPart.h" +#include "WellPathCommands/RicWellPathViewerEventHandler.h" + #include #include #include + //================================================================================================== // // RiaViewerCommands @@ -84,13 +87,16 @@ RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) m_currentGridIdx(-1), m_currentCellIndex(-1) { - caf::CmdFeature* cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicNewPolylineCrossSectionFeature"); - CVF_ASSERT(cmdFeature); + { + caf::CmdFeature* cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicNewPolylineCrossSectionFeature"); + CVF_ASSERT(cmdFeature); - RicCommandFeature* riCommandFeature = dynamic_cast(cmdFeature); - CVF_ASSERT(riCommandFeature); + m_viewerEventHandlers.push_back(dynamic_cast(cmdFeature)); + } - m_activeUiCommandFeature = riCommandFeature; + { + m_viewerEventHandlers.push_back(dynamic_cast(RicWellPathViewerEventHandler::instance())); + } } //-------------------------------------------------------------------------------------------------- @@ -109,7 +115,6 @@ void RiuViewerCommands::setOwnerView(RimView * owner) m_reservoirView = owner; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -434,11 +439,10 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &firstPartTriangleIndex, &firstNncHitPart, &nncPartTriangleIndex); - if (!m_activeUiCommandFeature.isNull()) + cvf::ref eventObj = new RicViewerEventObject(localIntersectionPoint, firstHitPart, firstPartTriangleIndex); + for (size_t i = 0; i < m_viewerEventHandlers.size(); i++) { - cvf::ref uiEventObj = new RicLocalIntersectionUiEvent(localIntersectionPoint); - - if (m_activeUiCommandFeature->handleUiEvent(uiEventObj.p())) + if (m_viewerEventHandlers[i]->handleEvent(eventObj.p())) { return; } @@ -451,7 +455,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivCrossSectionSourceInfo* crossSectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (rivSourceInfo) @@ -470,37 +473,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM gridIndex = femSourceInfo->femPartIndex(); cellIndex = femSourceInfo->triangleToElmMapper()->elementIndex(firstPartTriangleIndex); } - else if (wellPathSourceInfo) - { - cvf::Vec3d displayModelOffset = cvf::Vec3d::ZERO; - - RimCase* rimCase = NULL; - m_reservoirView->firstAnchestorOrThisOfType(rimCase); - if (rimCase) - { - displayModelOffset = rimCase->displayModelOffset(); - } - - cvf::Vec3d unscaledIntersection = localIntersectionPoint; - unscaledIntersection.z() /= m_reservoirView->scaleZ; - - size_t wellSegmentIndex = wellPathSourceInfo->segmentIndex(firstPartTriangleIndex); - double measuredDepth = wellPathSourceInfo->measuredDepth(firstPartTriangleIndex, unscaledIntersection + displayModelOffset); - cvf::Vec3d trueVerticalDepth = wellPathSourceInfo->trueVerticalDepth(firstPartTriangleIndex, unscaledIntersection + displayModelOffset); - - QString wellPathText; - wellPathText += wellPathSourceInfo->wellPath()->name; - wellPathText += "\n"; - wellPathText += QString("Well path segment index : %1\n").arg(wellSegmentIndex); - wellPathText += QString("Measured depth : %1\n").arg(measuredDepth); - - QString formattedText; - formattedText.sprintf("Intersection point : [E: %.2f, N: %.2f, Depth: %.2f]", trueVerticalDepth.x(), trueVerticalDepth.y(), -trueVerticalDepth.z()); - wellPathText += formattedText; - - RiuMainWindow::instance()->setResultInfo(wellPathText); - - } else if (crossSectionSourceInfo) { findCellAndGridIndex(crossSectionSourceInfo, firstPartTriangleIndex, &cellIndex, &gridIndex); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index ab2e117266..e83e0236db 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -31,7 +31,7 @@ class RimGeoMechView; class RimView; class RiuViewer; class RivCrossSectionSourceInfo; -class RicCommandFeature; +class RicViewerEventInterface; class QMouseEvent; @@ -79,7 +79,7 @@ private slots: QPointer m_viewer; - QPointer m_activeUiCommandFeature; + std::vector m_viewerEventHandlers; }; From a2bfc12c575ad5335ecfa697d869f025c1f3d4b8 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 7 Dec 2015 09:59:19 +0100 Subject: [PATCH 218/290] (#674) Clicking on items in 3D view selects corresponding item in tree view/property panel Clicking on 3D Info box and legends for cell result, separate fault result and cell edge selects corresponding items in tree view --- ApplicationCode/ProjectDataModel/RimView.cpp | 8 +++ ApplicationCode/ProjectDataModel/RimView.h | 3 +- ApplicationCode/UserInterface/RiuViewer.cpp | 44 +++++++++---- ApplicationCode/UserInterface/RiuViewer.h | 4 +- .../UserInterface/RiuViewerCommands.cpp | 61 ++++++++++++++++++- .../UserInterface/RiuViewerCommands.h | 2 + Fwk/AppFwk/cafViewer/cafViewer.cpp | 13 ++++ Fwk/AppFwk/cafViewer/cafViewer.h | 2 + 8 files changed, 122 insertions(+), 15 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 0f0782279c..b83dca6e41 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -870,3 +870,11 @@ bool RimView::showActiveCellsOnly() return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimView::selectOverlayInfoConfig() +{ + RiuMainWindow::instance()->setCurrentObjectInTreeView(m_overlayInfoConfig); +} + diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index 124f20ce75..e4958d2e0c 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -147,6 +147,8 @@ class RimView : public caf::PdmObject virtual bool showActiveCellsOnly(); virtual void axisLabels(cvf::String* xLabel, cvf::String* yLabel, cvf::String* zLabel) = 0; + void selectOverlayInfoConfig(); + public: virtual void loadDataAndUpdate() = 0; virtual RimCase* ownerCase() = 0; @@ -210,7 +212,6 @@ class RimView : public caf::PdmObject private: RimViewLinker* viewLinkerIfMasterView() const; - private: bool m_previousGridModeMeshLinesWasFaults; caf::PdmField m_disableLighting; diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 05c0adee29..8b4086b7dc 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -115,10 +115,10 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) p.setColor(QPalette::Dark, progressAndHistogramColor); // Info Text - m_InfoLabel = new QLabel(); - m_InfoLabel->setPalette(p); - m_InfoLabel->setFrameShape(QFrame::Box); - m_InfoLabel->setMinimumWidth(275); + m_infoLabel = new QLabel(); + m_infoLabel->setPalette(p); + m_infoLabel->setFrameShape(QFrame::Box); + m_infoLabel->setMinimumWidth(275); m_showInfoText = true; // Version info label @@ -152,10 +152,10 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) if (RiaApplication::instance()->isRunningRegressionTests()) { - QFont regTestFont = m_InfoLabel->font(); + QFont regTestFont = m_infoLabel->font(); regTestFont.setPixelSize(11); - m_InfoLabel->setFont(regTestFont); + m_infoLabel->setFont(regTestFont); m_versionInfoLabel->setFont(regTestFont); m_animationProgress->setFont(regTestFont); m_histogramWidget->setFont(regTestFont); @@ -183,7 +183,7 @@ RiuViewer::~RiuViewer() m_rimView->cameraPosition = m_mainCamera->viewMatrix(); } - delete m_InfoLabel; + delete m_infoLabel; delete m_animationProgress; delete m_histogramWidget; delete m_progressBarStyle; @@ -228,6 +228,16 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { + if (!m_infoLabelOverlayArea.isNull()) + { + if (m_infoLabelOverlayArea.contains(event->x(), event->y())) + { + m_rimView->selectOverlayInfoConfig(); + + return; + } + } + m_viewerCommands->handlePickAction(event->x(), event->y(), event->modifiers()); return; } @@ -336,7 +346,7 @@ void RiuViewer::paintOverlayItems(QPainter* painter) if (isAnimationActive() && frameCount() > 1) showAnimBar = true; //if (showAnimBar) columnWidth = CVF_MAX(columnWidth, m_animationProgress->width()); - if (m_showInfoText) columnWidth = CVF_MAX(columnWidth, m_InfoLabel->sizeHint().width()); + if (m_showInfoText) columnWidth = CVF_MAX(columnWidth, m_infoLabel->sizeHint().width()); int columnPos = this->width() - columnWidth - margin; @@ -356,9 +366,19 @@ void RiuViewer::paintOverlayItems(QPainter* painter) if (m_showInfoText) { - m_InfoLabel->resize(columnWidth, m_InfoLabel->sizeHint().height()); - m_InfoLabel->render(painter, QPoint(columnPos, yPos)); - yPos += m_InfoLabel->height() + margin; + QPoint topLeft = QPoint(columnPos, yPos); + m_infoLabel->resize(columnWidth, m_infoLabel->sizeHint().height()); + m_infoLabel->render(painter, topLeft); + + m_infoLabelOverlayArea.setTopLeft(topLeft); + m_infoLabelOverlayArea.setBottom(yPos + m_infoLabel->height()); + m_infoLabelOverlayArea.setRight(columnPos + columnWidth); + + yPos += m_infoLabel->height() + margin; + } + else + { + m_infoLabelOverlayArea = QRect(); } if (m_showHistogram) @@ -383,7 +403,7 @@ void RiuViewer::paintOverlayItems(QPainter* painter) //-------------------------------------------------------------------------------------------------- void RiuViewer::setInfoText(QString text) { - m_InfoLabel->setText(text); + m_infoLabel->setText(text); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index 97dc692686..504e51f620 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -110,7 +110,9 @@ public slots: void mousePressEvent(QMouseEvent* event); private: - QLabel* m_InfoLabel; + QLabel* m_infoLabel; + QRect m_infoLabelOverlayArea; + QLabel* m_versionInfoLabel; bool m_showInfoText; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 057fb262c8..359aa07e8b 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -30,17 +30,20 @@ #include "RigFemPartGrid.h" #include "RigGeoMechCaseData.h" +#include "RimCellEdgeColors.h" #include "RimContextCommandBuilder.h" #include "RimCrossSection.h" #include "RimDefines.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" +#include "RimEclipseFaultColors.h" #include "RimEclipseView.h" #include "RimEclipseWell.h" #include "RimFaultCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" #include "RimGeoMechView.h" +#include "RimTernaryLegendConfig.h" #include "RimViewController.h" #include "RimWellPath.h" @@ -53,6 +56,7 @@ #include "RivFemPartGeometryGenerator.h" #include "RivFemPickSourceInfo.h" #include "RivSourceInfo.h" +#include "RivTernarySaturationOverlayItem.h" #include "RivWellPathSourceInfo.h" #include "RivWellPipeSourceInfo.h" @@ -63,6 +67,8 @@ #include "cvfDrawableGeo.h" #include "cvfHitItemCollection.h" +#include "cvfOverlayAxisCross.h" +#include "cvfOverlayScalarMapperLegend.h" #include "cvfPart.h" #include "WellPathCommands/RicWellPathViewerEventHandler.h" @@ -419,6 +425,11 @@ void RiuViewerCommands::slotHideIntersection() //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers) { + if (handleOverlayItemPicking(winPosX, winPosY)) + { + return; + } + size_t gridIndex = cvf::UNDEFINED_SIZE_T; size_t cellIndex = cvf::UNDEFINED_SIZE_T; size_t nncIndex = cvf::UNDEFINED_SIZE_T; @@ -434,7 +445,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM uint nncPartTriangleIndex = cvf::UNDEFINED_UINT; cvf::HitItemCollection hitItems; - if (m_viewer->rayPick(winPosX, winPosY, &hitItems)) { extractIntersectionData(hitItems, &localIntersectionPoint, &firstHitPart, &firstPartTriangleIndex, &firstNncHitPart, &nncPartTriangleIndex); @@ -715,3 +725,52 @@ void RiuViewerCommands::updateSelectionFromPickedPart(cvf::Part* part) } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) +{ + cvf::OverlayItem* pickedOverlayItem = m_viewer->overlayItem(winPosX, winPosY); + if (pickedOverlayItem) + { + caf::PdmObject* objToSelect = NULL; + + RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + if (eclipseView) + { + if (eclipseView->cellResult()->legendConfig()->legend() == pickedOverlayItem + || eclipseView->cellResult()->ternaryLegendConfig->legend() == pickedOverlayItem) + { + objToSelect = eclipseView->cellResult(); + } + else if (eclipseView->faultResultSettings()->customFaultResult()->legendConfig()->legend() == pickedOverlayItem + || eclipseView->faultResultSettings()->customFaultResult()->ternaryLegendConfig()->legend() == pickedOverlayItem) + { + objToSelect = eclipseView->faultResultSettings(); + } + else if (eclipseView->cellEdgeResult()->legendConfig()->legend() == pickedOverlayItem) + { + objToSelect = eclipseView->cellEdgeResult(); + } + } + + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + if (geomView) + { + if (geomView->cellResult()->legendConfig()->legend() == pickedOverlayItem) + { + objToSelect = geomView->cellResult(); + } + } + + if (objToSelect) + { + RiuMainWindow::instance()->setCurrentObjectInTreeView(objToSelect); + + return true; + } + } + + return false; +} diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index e83e0236db..32eaa27e4d 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -70,6 +70,8 @@ private slots: void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); void updateSelectionFromPickedPart(cvf::Part* part); + bool handleOverlayItemPicking(int winPosX, int winPosY); + size_t m_currentGridIdx; size_t m_currentCellIndex; cvf::StructGridInterface::FaceType m_currentFaceIndex; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index a0f920b71c..55d006f707 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -908,3 +908,16 @@ void caf::Viewer::appendAllStaticModelsToFrame(cvf::Scene* scene) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::OverlayItem* caf::Viewer::overlayItem(int winPosX, int winPosY) +{ + if (m_mainRendering.isNull()) return NULL; + + int translatedMousePosX = winPosX; + int translatedMousePosY = height() - winPosY; + + return m_mainRendering->overlayItemFromWindowCoordinates(translatedMousePosX, translatedMousePosY); +} + diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 287c8415a8..475d8ca5cd 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -57,6 +57,7 @@ namespace cvf { class Rendering; class Scene; class TextureImage; + class OverlayItem; } namespace caf { @@ -123,6 +124,7 @@ class Viewer : public caf::OpenGLWidget bool canRender() const; bool rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pickedPoints) ; + cvf::OverlayItem* overlayItem(int winPosX, int winPosY); // QPainter based drawing on top of the OpenGL graphics From dc6a50ec3c38ae5e03fadc521a7cfc7ea7eb2658 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 7 Dec 2015 10:07:51 +0100 Subject: [PATCH 219/290] Renamed from setCurrentObjectInTreeView to selectAsCurrentItem --- ApplicationCode/Application/RiaApplication.cpp | 8 ++++---- .../RicNewPolylineCrossSectionFeature.cpp | 2 +- .../Commands/RicEclipseCaseNewGroupExec.cpp | 2 +- .../RicEclipsePropertyFilterFeatureImpl.cpp | 4 ++-- .../RicGeoMechPropertyFilterFeatureImpl.cpp | 4 ++-- .../Commands/RicNewStatisticsCaseFeature.cpp | 3 +-- .../Commands/RicRangeFilterInsertExec.cpp | 2 +- .../Commands/RicRangeFilterNewExec.cpp | 2 +- .../ViewLink/RicShowLinkOptionsFeature.cpp | 3 +-- .../RicAddWellLogToPlotFeature.cpp | 10 +--------- .../RicNewWellLogCurveExtractionFeature.cpp | 2 +- .../RicNewWellLogFileCurveFeature.cpp | 2 +- .../RimCrossSectionCollection.cpp | 2 +- ApplicationCode/ProjectDataModel/RimView.cpp | 2 +- .../UserInterface/RiuMainWindow.cpp | 2 +- ApplicationCode/UserInterface/RiuMainWindow.h | 2 +- .../UserInterface/RiuViewerCommands.cpp | 5 ++--- .../UserInterface/RiuWellLogTrack.cpp | 18 ++++++++---------- 18 files changed, 31 insertions(+), 44 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index faf12ad20f..b000edc340 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -759,7 +759,7 @@ bool RiaApplication::openEclipseCase(const QString& caseName, const QString& cas analysisModels->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(riv->cellResult()); + RiuMainWindow::instance()->selectAsCurrentItem(riv->cellResult()); return true; @@ -795,7 +795,7 @@ bool RiaApplication::openInputEclipseCaseFromFileNames(const QStringList& fileNa analysisModels->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(riv->cellResult()); + RiuMainWindow::instance()->selectAsCurrentItem(riv->cellResult()); return true; } @@ -841,7 +841,7 @@ bool RiaApplication::openOdbCaseFromFile(const QString& fileName) m_project->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(riv->cellResult()); + RiuMainWindow::instance()->selectAsCurrentItem(riv->cellResult()); return true; } @@ -1965,7 +1965,7 @@ bool RiaApplication::addEclipseCases(const QStringList& fileNames) if (gridCaseGroup->statisticsCaseCollection()->reservoirs.size() > 0) { - RiuMainWindow::instance()->setCurrentObjectInTreeView(gridCaseGroup->statisticsCaseCollection()->reservoirs[0]); + RiuMainWindow::instance()->selectAsCurrentItem(gridCaseGroup->statisticsCaseCollection()->reservoirs[0]); } return true; diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp index 502fc11703..f0f4da36ae 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineCrossSectionFeature.cpp @@ -146,7 +146,7 @@ void RicNewPolylineCrossSectionFeatureCmd::redo() RiuSelectionManager::instance()->deleteAllItems(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + RiuMainWindow::instance()->selectAsCurrentItem(crossSection); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicEclipseCaseNewGroupExec.cpp b/ApplicationCode/Commands/RicEclipseCaseNewGroupExec.cpp index 902085ad10..e18f409d79 100644 --- a/ApplicationCode/Commands/RicEclipseCaseNewGroupExec.cpp +++ b/ApplicationCode/Commands/RicEclipseCaseNewGroupExec.cpp @@ -73,7 +73,7 @@ void RicEclipseCaseNewGroupExec::redo() analysisModels->caseGroups().push_back(createdObject); analysisModels->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(createdObject); + RiuMainWindow::instance()->selectAsCurrentItem(createdObject); RiuMainWindow::instance()->setExpanded(createdObject, true); } } diff --git a/ApplicationCode/Commands/RicEclipsePropertyFilterFeatureImpl.cpp b/ApplicationCode/Commands/RicEclipsePropertyFilterFeatureImpl.cpp index 8864b9613a..6124ffde97 100644 --- a/ApplicationCode/Commands/RicEclipsePropertyFilterFeatureImpl.cpp +++ b/ApplicationCode/Commands/RicEclipsePropertyFilterFeatureImpl.cpp @@ -65,7 +65,7 @@ void RicEclipsePropertyFilterFeatureImpl::addPropertyFilter(RimEclipsePropertyFi propertyFilterCollection->reservoirView()->scheduleGeometryRegen(PROPERTY_FILTERED); propertyFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(propertyFilter); + RiuMainWindow::instance()->selectAsCurrentItem(propertyFilter); } @@ -81,7 +81,7 @@ void RicEclipsePropertyFilterFeatureImpl::insertPropertyFilter(RimEclipsePropert propertyFilterCollection->reservoirView()->scheduleGeometryRegen(PROPERTY_FILTERED); propertyFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(propertyFilter); + RiuMainWindow::instance()->selectAsCurrentItem(propertyFilter); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp b/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp index 312b260336..388a637f7f 100644 --- a/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp +++ b/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp @@ -66,7 +66,7 @@ void RicGeoMechPropertyFilterFeatureImpl::addPropertyFilter(RimGeoMechPropertyFi propertyFilterCollection->reservoirView()->scheduleCreateDisplayModelAndRedraw(); propertyFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(propertyFilter); + RiuMainWindow::instance()->selectAsCurrentItem(propertyFilter); } @@ -83,7 +83,7 @@ void RicGeoMechPropertyFilterFeatureImpl::insertPropertyFilter(RimGeoMechPropert propertyFilterCollection->reservoirView()->scheduleCreateDisplayModelAndRedraw(); propertyFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(propertyFilter); + RiuMainWindow::instance()->selectAsCurrentItem(propertyFilter); } diff --git a/ApplicationCode/Commands/RicNewStatisticsCaseFeature.cpp b/ApplicationCode/Commands/RicNewStatisticsCaseFeature.cpp index abd3d73b37..6361893a40 100644 --- a/ApplicationCode/Commands/RicNewStatisticsCaseFeature.cpp +++ b/ApplicationCode/Commands/RicNewStatisticsCaseFeature.cpp @@ -29,7 +29,6 @@ #include "RiuMainWindow.h" #include "cafSelectionManager.h" -#include "cafPdmUiTreeView.h" #include @@ -54,7 +53,7 @@ void RicNewStatisticsCaseFeature::onActionTriggered(bool isChecked) RimEclipseStatisticsCase* newCase = addStatisticalCalculation(uiItem); if (newCase) { - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(newCase); + RiuMainWindow::instance()->selectAsCurrentItem(newCase); } } } diff --git a/ApplicationCode/Commands/RicRangeFilterInsertExec.cpp b/ApplicationCode/Commands/RicRangeFilterInsertExec.cpp index 67b89745e1..1e06760071 100644 --- a/ApplicationCode/Commands/RicRangeFilterInsertExec.cpp +++ b/ApplicationCode/Commands/RicRangeFilterInsertExec.cpp @@ -69,7 +69,7 @@ void RicRangeFilterInsertExec::redo() m_cellRangeFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(rangeFilter); + RiuMainWindow::instance()->selectAsCurrentItem(rangeFilter); } } diff --git a/ApplicationCode/Commands/RicRangeFilterNewExec.cpp b/ApplicationCode/Commands/RicRangeFilterNewExec.cpp index a5cd784b73..9e9b50f6ce 100644 --- a/ApplicationCode/Commands/RicRangeFilterNewExec.cpp +++ b/ApplicationCode/Commands/RicRangeFilterNewExec.cpp @@ -72,7 +72,7 @@ void RicRangeFilterNewExec::redo() m_cellRangeFilterCollection->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(rangeFilter); + RiuMainWindow::instance()->selectAsCurrentItem(rangeFilter); } } diff --git a/ApplicationCode/Commands/ViewLink/RicShowLinkOptionsFeature.cpp b/ApplicationCode/Commands/ViewLink/RicShowLinkOptionsFeature.cpp index 14d8522fb4..0c958d247c 100644 --- a/ApplicationCode/Commands/ViewLink/RicShowLinkOptionsFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicShowLinkOptionsFeature.cpp @@ -27,7 +27,6 @@ #include "RiuMainWindow.h" #include "cafSelectionManager.h" -#include "cafPdmUiTreeView.h" #include @@ -62,7 +61,7 @@ void RicShowLinkOptionsFeature::onActionTriggered(bool isChecked) RimViewController* viewController = activeView->viewController(); - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(viewController); + RiuMainWindow::instance()->selectAsCurrentItem(viewController); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index 7e46439643..84ddd94df9 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -105,11 +105,6 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) curve->setWellLogChannelName(wellLog->name()); curve->updatePlotData(); - - if (wlIdx == selection.size() - 1) - { - uiItem = curve; - } } } @@ -119,10 +114,7 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) RiaApplication::instance()->project()->updateConnectedEditors(); - if (uiItem) - { - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(uiItem); - } + RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(selection.back()); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index 012e825ecb..2b2d1ff1b3 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -136,7 +136,7 @@ RimWellLogExtractionCurve* RicNewWellLogCurveExtractionFeature::addCurve(RimWell plotTrack->addCurve(curve); plotTrack->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(curve); + RiuMainWindow::instance()->selectAsCurrentItem(curve); return curve; } diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp index 95300e49e9..d0d47f1bbd 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogFileCurveFeature.cpp @@ -152,7 +152,7 @@ RimWellLogFileCurve* RicNewWellLogFileCurveFeature::addCurve(RimWellLogTrack* pl plotTrack->updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(curve); + RiuMainWindow::instance()->selectAsCurrentItem(curve); return curve; } diff --git a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp index c3a9cc7823..850e7840af 100644 --- a/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimCrossSectionCollection.cpp @@ -118,7 +118,7 @@ void RimCrossSectionCollection::appendCrossSection(RimCrossSection* crossSection m_crossSections.push_back(crossSection); updateConnectedEditors(); - RiuMainWindow::instance()->setCurrentObjectInTreeView(crossSection); + RiuMainWindow::instance()->selectAsCurrentItem(crossSection); RimView* rimView = NULL; firstAnchestorOrThisOfType(rimView); diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index b83dca6e41..93b98ab50d 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -875,6 +875,6 @@ bool RimView::showActiveCellsOnly() //-------------------------------------------------------------------------------------------------- void RimView::selectOverlayInfoConfig() { - RiuMainWindow::instance()->setCurrentObjectInTreeView(m_overlayInfoConfig); + RiuMainWindow::instance()->selectAsCurrentItem(m_overlayInfoConfig); } diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index a58bdacac3..c89a57062b 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1990,7 +1990,7 @@ void RiuMainWindow::restoreTreeViewState() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuMainWindow::setCurrentObjectInTreeView(caf::PdmObject* object) +void RiuMainWindow::selectAsCurrentItem(caf::PdmObject* object) { m_projectTreeView->selectAsCurrentItem(object); } diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index adccc5412c..c4215b4229 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -93,7 +93,7 @@ class RiuMainWindow : public QMainWindow void loadWinGeoAndDockToolBarLayout(); void showWindow(); - void setCurrentObjectInTreeView(caf::PdmObject* object); + void selectAsCurrentItem(caf::PdmObject* object); void selectedCases(std::vector& cases); diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 359aa07e8b..ece612544b 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -62,7 +62,6 @@ #include "cafCmdExecCommandManager.h" #include "cafCmdFeatureManager.h" -#include "cafPdmUiTreeView.h" #include "cafSelectionManager.h" #include "cvfDrawableGeo.h" @@ -720,7 +719,7 @@ void RiuViewerCommands::updateSelectionFromPickedPart(cvf::Part* part) RimWellPath* wellPath = wellPathSourceInfo->wellPath(); if (wellPath) { - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(wellPath); + RiuMainWindow::instance()->selectAsCurrentItem(wellPath); } } } @@ -766,7 +765,7 @@ bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) if (objToSelect) { - RiuMainWindow::instance()->setCurrentObjectInTreeView(objToSelect); + RiuMainWindow::instance()->selectAsCurrentItem(objToSelect); return true; } diff --git a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp index 4447a3af8b..a9652590d7 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp @@ -25,22 +25,20 @@ #include "RiuMainWindow.h" -#include "cafPdmUiTreeView.h" - -#include "qwt_plot_grid.h" #include "qwt_legend.h" -#include "qwt_scale_engine.h" +#include "qwt_plot_curve.h" +#include "qwt_plot_grid.h" #include "qwt_plot_layout.h" #include "qwt_scale_draw.h" +#include "qwt_scale_engine.h" #include "qwt_text.h" -#include "qwt_plot_curve.h" -#include -#include #include +#include +#include +#include #include -#include #define RIU_SCROLLWHEEL_ZOOMFACTOR 1.1 #define RIU_SCROLLWHEEL_PANFACTOR 0.1 @@ -222,7 +220,7 @@ void RiuWellLogTrack::focusInEvent(QFocusEvent* event) { if (m_plotTrackDefinition) { - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(m_plotTrackDefinition); + RiuMainWindow::instance()->selectAsCurrentItem(m_plotTrackDefinition); clearFocus(); } } @@ -256,7 +254,7 @@ void RiuWellLogTrack::selectClosestCurve(const QPoint& pos) RimWellLogCurve* selectedCurve = m_plotTrackDefinition->curveDefinitionFromCurve(closestCurve); if (selectedCurve) { - RiuMainWindow::instance()->projectTreeView()->selectAsCurrentItem(selectedCurve); + RiuMainWindow::instance()->selectAsCurrentItem(selectedCurve); } } } From 5eb38fe2034ae2e6b10a91ef79fff544378ea645 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 7 Dec 2015 12:03:33 +0100 Subject: [PATCH 220/290] (#691) Added option to keep the depth range fixed --- .../Commands/RicDeleteItemExec.cpp | 2 +- .../RicAddWellLogToPlotFeature.cpp | 2 +- .../RicDeleteWellLogPlotTrackFeature.cpp | 2 +- .../RicWellLogPlotTrackFeatureImpl.cpp | 2 +- .../ProjectDataModel/RimWellLogCurve.cpp | 2 +- .../ProjectDataModel/RimWellLogPlot.cpp | 33 ++++++++++++++++--- .../ProjectDataModel/RimWellLogPlot.h | 7 ++-- .../ProjectDataModel/RimWellLogTrack.cpp | 4 +-- 8 files changed, 39 insertions(+), 15 deletions(-) diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 5df31a61d5..d9aea835da 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -125,7 +125,7 @@ void RicDeleteItemExec::redo() if (wellLogPlot) { wellLogPlot->calculateAvailableDepthRange(); - wellLogPlot->zoomAllDepth(); + wellLogPlot->updateDepthZoom(); } RimWellLogTrack* wellLogPlotTrack; diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index 84ddd94df9..a1c9503d7c 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -109,7 +109,7 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) } plot->calculateAvailableDepthRange(); - plot->zoomAllDepth(); + plot->updateDepthZoom(); plotTrack->viewer()->replot(); RiaApplication::instance()->project()->updateConnectedEditors(); diff --git a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp index b5a89d10ce..b86111d335 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp @@ -71,7 +71,7 @@ void RicDeleteWellLogPlotTrackFeature::onActionTriggered(bool isChecked) delete track; wellLogPlot->calculateAvailableDepthRange(); - wellLogPlot->zoomAllDepth(); + wellLogPlot->updateDepthZoom(); wellLogPlot->uiCapability()->updateConnectedEditors(); } } diff --git a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp index f7341ee6b1..4184bfcc00 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicWellLogPlotTrackFeatureImpl.cpp @@ -108,7 +108,7 @@ void RicWellLogPlotTrackFeatureImpl::moveTracksToWellLogPlot(RimWellLogPlot* dst { (*pIt)->calculateAvailableDepthRange(); (*pIt)->updateTrackNames(); - (*pIt)->zoomAllDepth(); + (*pIt)->updateDepthZoom(); (*pIt)->updateConnectedEditors(); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 8cb9543277..01693710be 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -277,7 +277,7 @@ void RimWellLogCurve::zoomAllOwnerTrackAndPlot() if (wellLogPlot) { wellLogPlot->calculateAvailableDepthRange(); - wellLogPlot->zoomAllDepth(); + wellLogPlot->updateDepthZoom(); } RimWellLogTrack* plotTrack; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index 7eb249bb95..d78dbff5cd 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -71,6 +71,7 @@ RimWellLogPlot::RimWellLogPlot() CAF_PDM_InitField(&m_minVisibleDepth, "MinimumDepth", 0.0, "Min", "", "", ""); CAF_PDM_InitField(&m_maxVisibleDepth, "MaximumDepth", 1000.0, "Max", "", "", ""); + CAF_PDM_InitField(&m_isAutoScaleDepthEnabled, "AutoScaleDepthEnabled", true, "Auto Scale", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_tracks, "Tracks", "", "", "", ""); m_tracks.uiCapability()->setUiHidden(true); @@ -147,7 +148,13 @@ void RimWellLogPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c } else if (changedField == &m_minVisibleDepth || changedField == &m_maxVisibleDepth) { - updateDepthZoomInQwt(); + applyDepthZoomFromVisibleDepth(); + + m_isAutoScaleDepthEnabled = false; + } + else if (changedField == &m_isAutoScaleDepthEnabled) + { + updateDepthZoom(); } else if (changedField == &m_userName) { @@ -279,7 +286,7 @@ void RimWellLogPlot::setDepthZoomMinMax(double minimumDepth, double maximumDepth m_minVisibleDepth.uiCapability()->updateConnectedEditors(); m_maxVisibleDepth.uiCapability()->updateConnectedEditors(); - updateDepthZoomInQwt(); + applyDepthZoomFromVisibleDepth(); } //-------------------------------------------------------------------------------------------------- @@ -373,6 +380,7 @@ void RimWellLogPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering.add(&m_depthUnit); caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Visible Depth Range"); + gridGroup->add(&m_isAutoScaleDepthEnabled); gridGroup->add(&m_minVisibleDepth); gridGroup->add(&m_maxVisibleDepth); } @@ -400,7 +408,7 @@ void RimWellLogPlot::updateTracks() } calculateAvailableDepthRange(); - updateDepthZoomInQwt(); + updateDepthZoom(); } } @@ -418,7 +426,22 @@ void RimWellLogPlot::updateTrackNames() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::updateDepthZoomInQwt() +void RimWellLogPlot::updateDepthZoom() +{ + if (m_isAutoScaleDepthEnabled) + { + applyZoomAllDepths(); + } + else + { + applyDepthZoomFromVisibleDepth(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogPlot::applyDepthZoomFromVisibleDepth() { if (m_viewer) { @@ -433,7 +456,7 @@ void RimWellLogPlot::updateDepthZoomInQwt() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::zoomAllDepth() +void RimWellLogPlot::applyZoomAllDepths() { if (hasAvailableDepthRange()) { diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index f7963d6a29..2912a87e22 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -74,7 +74,7 @@ class RimWellLogPlot : public caf::PdmObject RiuWellLogPlot* viewer(); - void zoomAllDepth(); + void updateDepthZoom(); void setDepthZoomByFactorAndCenter(double zoomFactor, double zoomCenter); void panDepth(double panFactor); void setDepthZoomMinMax(double minimumDepth, double maximumDepth); @@ -96,13 +96,13 @@ class RimWellLogPlot : public caf::PdmObject private: void updateViewerWidget(); void updateViewerWidgetWindowTitle(); - void updateDepthZoomInQwt(); + void applyZoomAllDepths(); + void applyDepthZoomFromVisibleDepth(); void recreateTrackPlots(); void detachAllCurves(); void handleViewerDeletion(); private: - caf::PdmField m_showWindow; caf::PdmField m_userName; @@ -113,6 +113,7 @@ class RimWellLogPlot : public caf::PdmObject caf::PdmField m_minVisibleDepth; caf::PdmField m_maxVisibleDepth; + caf::PdmField m_isAutoScaleDepthEnabled; double m_minAvailableDepth; double m_maxAvailableDepth; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 758e78eb3c..635beae269 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -92,7 +92,7 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, if (wellLogPlot) { wellLogPlot->calculateAvailableDepthRange(); - wellLogPlot->zoomAllDepth(); + wellLogPlot->updateDepthZoom(); if (wellLogPlot->viewer()) wellLogPlot->viewer()->updateChildrenLayout(); } } @@ -268,7 +268,7 @@ void RimWellLogTrack::zoomAllXAndZoomAllDepthOnOwnerPlot() firstAnchestorOrThisOfType(wellLogPlot); if (wellLogPlot) { - wellLogPlot->zoomAllDepth(); + wellLogPlot->updateDepthZoom(); } zoomAllXAxisIfAutoScale(); From b4e7e27f765cf97afd3f5905dd5a34193bed2345 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 7 Dec 2015 12:53:36 +0100 Subject: [PATCH 221/290] Fixed issued reported by CppDepends --- .../WellLogCommands/RicAddWellLogToPlotFeature.cpp | 2 -- .../RicWellPathViewerEventHandler.cpp | 1 - .../RicWellPathsImportSsihubFeature.cpp | 12 +++++------- ApplicationCode/ModelVisualization/RivFaultPartMgr.h | 1 - .../ReservoirDataModel/RigCaseCellResultsData.cpp | 4 +--- .../UserInterface/RiuSimpleHistogramWidget.cpp | 1 + 6 files changed, 7 insertions(+), 14 deletions(-) diff --git a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp index a1c9503d7c..2af17d75c9 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAddWellLogToPlotFeature.cpp @@ -74,8 +74,6 @@ void RicAddWellLogToPlotFeature::onActionTriggered(bool isChecked) plot->loadDataAndUpdate(); - caf::PdmUiItem* uiItem = NULL; - for (size_t wlIdx = 0; wlIdx < selection.size(); wlIdx++) { RimWellLogFileChannel* wellLog = selection[wlIdx]; diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp index bd43abca7b..e7cf8cd56f 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp @@ -69,7 +69,6 @@ bool RicWellPathViewerEventHandler::handleEvent(cvf::Object* eventObject) cvf::Vec3d unscaledIntersection = uiEvent->localIntersectionPoint; unscaledIntersection.z() /= activeView->scaleZ; - size_t wellSegmentIndex = wellPathSourceInfo->segmentIndex(uiEvent->firstPartTriangleIndex); double measuredDepth = wellPathSourceInfo->measuredDepth(uiEvent->firstPartTriangleIndex, unscaledIntersection + displayModelOffset); cvf::Vec3d trueVerticalDepth = wellPathSourceInfo->trueVerticalDepth(uiEvent->firstPartTriangleIndex, unscaledIntersection + displayModelOffset); diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathsImportSsihubFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathsImportSsihubFeature.cpp index b2800d2364..68163fa9a7 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathsImportSsihubFeature.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathsImportSsihubFeature.cpp @@ -86,16 +86,14 @@ void RicWellPathsImportSsihubFeature::onActionTriggered(bool isChecked) // Get password/username from application cache { - QString ssihubUsername = app->cacheDataObject("ssihub_username").toString(); - QString ssihubPassword = app->cacheDataObject("ssihub_password").toString(); - #ifdef _DEBUG - // Valid credentials for ssihubfake received in mail from Håkon - ssihubUsername = "admin"; - ssihubPassword = "resinsight"; + QString ssihubUsername = "admin"; + QString ssihubPassword = "resinsight"; +#else + QString ssihubUsername = app->cacheDataObject("ssihub_username").toString(); + QString ssihubPassword = app->cacheDataObject("ssihub_password").toString(); #endif - wellImportwizard.setCredentials(ssihubUsername, ssihubPassword); } diff --git a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h index 0f2c2dc3e3..fdc1276bba 100644 --- a/ApplicationCode/ModelVisualization/RivFaultPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivFaultPartMgr.h @@ -83,7 +83,6 @@ class RivFaultPartMgr : public cvf::Object float m_opacityLevel; cvf::Color3f m_defaultColor; - bool m_showOppositeFaces; bool m_showLabel; cvf::ref m_cellVisibility; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 7834e8d3ed..df4291934e 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -198,9 +198,7 @@ size_t RigCaseCellResultsData::findScalarResultIndex(RimDefines::ResultCatType t //-------------------------------------------------------------------------------------------------- size_t RigCaseCellResultsData::findScalarResultIndex(const QString& resultName) const { - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; - - scalarResultIndex = this->findScalarResultIndex(RimDefines::STATIC_NATIVE, resultName); + size_t scalarResultIndex = this->findScalarResultIndex(RimDefines::STATIC_NATIVE, resultName); if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) { diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp index e74ebc6658..253b098955 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp @@ -13,6 +13,7 @@ QWidget(parent, f) m_mean = HUGE_VAL; m_min = HUGE_VAL; m_max = -HUGE_VAL; + m_maxHistogramCount = 0; } //-------------------------------------------------------------------------------------------------- From 2478898a8b8886128bac838c537dd3484de4b295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 7 Dec 2015 16:03:12 +0100 Subject: [PATCH 222/290] Upped to 1.5.102-dev for Sprint 10 --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 3fa852e2f3..b967507f1e 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 101) +set(CMAKE_PATCH_VERSION 102) set(DEV_VERSION "-dev") From c8ecf78c8ce4b987fd37f4ea3b18ab3af86efc6d Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 8 Dec 2015 15:33:42 +0100 Subject: [PATCH 223/290] (#694) Removed assert when finding projected point on well path segment --- ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp index e6b6ebbddc..2d2c075539 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp @@ -90,8 +90,6 @@ void RivWellPathSourceInfo::normalizedIntersection(size_t triangleIndex, const c double norm = 0.0; cvf::Vec3d pointOnLine = cvf::GeometryTools::projectPointOnLine(segmentStart, segmentEnd, globalIntersection, &norm); - CVF_ASSERT(0.0 < norm && norm < 1.0); - cvf::Math::clamp(norm, 0.0, 1.0); *firstSegmentIndex = segIndex; From 75b476c063c04d5fbbc7950ed8d14a6b9bf51a3c Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 8 Dec 2015 17:25:48 +0100 Subject: [PATCH 224/290] (#696) Select legend definition when clicking on legend in 3D view --- .../UserInterface/RiuViewerCommands.cpp | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index ece612544b..3371f1848a 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -738,19 +738,25 @@ bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); if (eclipseView) { - if (eclipseView->cellResult()->legendConfig()->legend() == pickedOverlayItem - || eclipseView->cellResult()->ternaryLegendConfig->legend() == pickedOverlayItem) + if (eclipseView->cellResult()->legendConfig()->legend() == pickedOverlayItem) { - objToSelect = eclipseView->cellResult(); + objToSelect = eclipseView->cellResult()->legendConfig(); } - else if (eclipseView->faultResultSettings()->customFaultResult()->legendConfig()->legend() == pickedOverlayItem - || eclipseView->faultResultSettings()->customFaultResult()->ternaryLegendConfig()->legend() == pickedOverlayItem) + else if (eclipseView->cellResult()->ternaryLegendConfig()->legend() == pickedOverlayItem) { - objToSelect = eclipseView->faultResultSettings(); + objToSelect = eclipseView->cellResult()->ternaryLegendConfig(); + } + else if (eclipseView->faultResultSettings()->customFaultResult()->legendConfig()->legend() == pickedOverlayItem) + { + objToSelect = eclipseView->faultResultSettings()->customFaultResult()->legendConfig(); + } + else if (eclipseView->faultResultSettings()->customFaultResult()->ternaryLegendConfig()->legend() == pickedOverlayItem) + { + objToSelect = eclipseView->faultResultSettings()->customFaultResult()->ternaryLegendConfig(); } else if (eclipseView->cellEdgeResult()->legendConfig()->legend() == pickedOverlayItem) { - objToSelect = eclipseView->cellEdgeResult(); + objToSelect = eclipseView->cellEdgeResult()->legendConfig(); } } @@ -759,7 +765,7 @@ bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) { if (geomView->cellResult()->legendConfig()->legend() == pickedOverlayItem) { - objToSelect = geomView->cellResult(); + objToSelect = geomView->cellResult()->legendConfig(); } } From a8d1dfa329e94af612f350cc76319b94d9025741 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 8 Dec 2015 17:43:07 +0100 Subject: [PATCH 225/290] (#696) Fixed missing display of ternary config for separate fault result --- .../ProjectDataModel/RimEclipseFaultColors.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp index 7a28274b07..5122a5ff1b 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp @@ -23,8 +23,10 @@ #include "RigMainGrid.h" #include "RimEclipseCase.h" -#include "RimEclipseView.h" #include "RimEclipseCellColors.h" +#include "RimEclipseView.h" +#include "RimTernaryLegendConfig.h" + #include "RiuMainWindow.h" #include "cafPdmUiTreeOrdering.h" @@ -144,7 +146,12 @@ bool RimEclipseFaultColors::hasValidCustomResult() //-------------------------------------------------------------------------------------------------- void RimEclipseFaultColors::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { - if (m_customFaultResultColors()->legendConfig()) + if (m_customFaultResultColors()->ternaryLegendConfig() + && !m_customFaultResultColors()->ternaryLegendConfig.uiCapability()->isUiChildrenHidden(uiConfigName)) + { + uiTreeOrdering.add(m_customFaultResultColors()->ternaryLegendConfig()); + } + else if (m_customFaultResultColors()->legendConfig()) { uiTreeOrdering.add(m_customFaultResultColors()->legendConfig()); } From 4b39ba4508b75f5e12b1ec38410fb9d005df708a Mon Sep 17 00:00:00 2001 From: Jacob Storen Date: Wed, 9 Dec 2015 02:12:58 -0800 Subject: [PATCH 226/290] Remove compile warnings Linux --- .../ModelVisualization/GridBox/RivGridBoxGenerator.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index 8b21b5d602..c339fc5f71 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -370,15 +370,15 @@ cvf::Vec3d RivGridBoxGenerator::displayModelCoordFromDomainCoord(const cvf::Vec3 //-------------------------------------------------------------------------------------------------- void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection* parts) { - cvf::Vec3d posMin; - cvf::Vec3d posMax; + cvf::Vec3d posMin = cvf::Vec3d::ZERO; + cvf::Vec3d posMax = cvf::Vec3d::ZERO; cvf::Vec3d min = m_displayCoordsBoundingBox.min(); cvf::Vec3d max = m_displayCoordsBoundingBox.max(); - AxisType axis; + AxisType axis = X_AXIS; - cvf::Vec3f tickMarkDir; + cvf::Vec3f tickMarkDir = cvf::Vec3f::X_AXIS; switch (edge) { @@ -455,6 +455,7 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection tickMarkDir = cornerDirection(NEG_X, NEG_Y); break; default: + CVF_TIGHT_ASSERT(false); break; } From cbe728c9afdbf2d6c682f0d39d904a42223e328a Mon Sep 17 00:00:00 2001 From: Jacob Storen Date: Wed, 9 Dec 2015 02:20:33 -0800 Subject: [PATCH 227/290] (#690) Fixed crash on linux when selecting cells with high cell index. Caused by unintentional pointer arithmetics on string literal. --- .../GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp | 2 +- .../ModelVisualization/RivSingleCellPartGenerator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp index 7a8a5fcace..b8da666461 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp @@ -144,7 +144,7 @@ void RivFemPartPartMgr::generatePartGeometry(RivFemPartGeometryGenerator& geoBui } cvf::ref part = new cvf::Part; - part->setName("Grid mesh " + m_gridIdx); + part->setName("Grid mesh " + cvf::String(m_gridIdx)); part->setDrawable(geoMesh.p()); part->setTransform(m_scaleTransform.p()); diff --git a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp index 9168a10968..3e1f52435b 100644 --- a/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivSingleCellPartGenerator.cpp @@ -61,7 +61,7 @@ RivSingleCellPartGenerator::RivSingleCellPartGenerator(RimGeoMechCase* rimGeoMec cvf::ref RivSingleCellPartGenerator::createPart(const cvf::Color3f color) { cvf::ref part = new cvf::Part; - part->setName("Hightlight part for cell index " + m_cellIndex); + part->setName(cvf::String("Hightlight part for cell index ") + cvf::String((cvf::int64)m_cellIndex)); part->setDrawable(createMeshDrawable().p()); cvf::ref eff; From 2a53054f2d1d0a9d6093cbdd7a1e395ff7dfb24f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 8 Dec 2015 20:39:06 +0100 Subject: [PATCH 228/290] (#697) Added line, symbol and line_symbol as curve style --- .../ProjectDataModel/RimWellLogCurve.cpp | 38 ++++++++++++++++++- .../ProjectDataModel/RimWellLogCurve.h | 14 +++++++ .../RimWellLogExtractionCurve.cpp | 1 + .../ProjectDataModel/RimWellLogFileCurve.cpp | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 01693710be..ca556584b1 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -30,9 +30,23 @@ #include "cvfAssert.h" +#include "qwt_symbol.h" + // NB! Special macro for pure virtual class CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimWellLogCurve, "WellLogPlotCurve"); +namespace caf +{ + template<> + void caf::AppEnum< RimWellLogCurve::CurvePlotTypeEnum >::setUp() + { + addItem(RimWellLogCurve::LINE, "LINE", "Line"); + addItem(RimWellLogCurve::SYMBOL, "SYMBOL", "Symbol"); + addItem(RimWellLogCurve::LINE_AND_SYMBOL, "LINE_AND_SYMBOL", "Line and Symbol"); + setDefault(RimWellLogCurve::LINE); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -54,6 +68,9 @@ RimWellLogCurve::RimWellLogCurve() CAF_PDM_InitField(&m_curveThickness, "Thickness", 1.0f, "Thickness", "", "", ""); m_curveThickness.uiCapability()->setUiEditorTypeName(caf::PdmUiComboBoxEditor::uiEditorTypeName()); + caf::AppEnum< RimWellLogCurve::CurvePlotTypeEnum > curvePlotType = LINE; + CAF_PDM_InitField(&m_curvePlotStyle, "CurvePlotStyle", curvePlotType, "Curve style", "", "", ""); + m_qwtPlotCurve = new RiuLineSegmentQwtPlotCurve; m_qwtPlotCurve->setXAxis(QwtPlot::xTop); m_qwtPlotCurve->setYAxis(QwtPlot::yLeft); @@ -90,7 +107,8 @@ void RimWellLogCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updatePlotTitle(); } else if (&m_curveColor == changedField - || &m_curveThickness == changedField) + || &m_curveThickness == changedField + || &m_curvePlotStyle == changedField) { updateCurvePen(); } @@ -326,6 +344,24 @@ void RimWellLogCurve::updateCurvePen() { CVF_ASSERT(m_qwtPlotCurve); m_qwtPlotCurve->setPen(QColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()), m_curveThickness); + + QwtSymbol* symbol = NULL; + + if (m_curvePlotStyle == LINE_AND_SYMBOL || m_curvePlotStyle == SYMBOL) + { + // QwtPlotCurve will take ownership of the symbol + symbol = new QwtSymbol(QwtSymbol::XCross); + symbol->setSize(6, 6); + } + + QwtPlotCurve::CurveStyle curveStyle = QwtPlotCurve::Lines; + if (m_curvePlotStyle == SYMBOL) + { + curveStyle = QwtPlotCurve::NoCurve; + } + + m_qwtPlotCurve->setStyle(curveStyle); + m_qwtPlotCurve->setSymbol(symbol); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index 85ab089fdd..aee4951311 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -24,13 +24,17 @@ #include "cafPdmObject.h" #include "RigWellLogCurveData.h" + #include + #include class RigWellLogCurveData; class RiuWellLogTrack; class RiuLineSegmentQwtPlotCurve; + class QwtPlotCurve; + class QString; //================================================================================================== @@ -40,6 +44,14 @@ class QString; class RimWellLogCurve : public caf::PdmObject { CAF_PDM_HEADER_INIT; +public: + enum CurvePlotTypeEnum + { + LINE, + SYMBOL, + LINE_AND_SYMBOL + }; + public: RimWellLogCurve(); virtual ~RimWellLogCurve(); @@ -94,4 +106,6 @@ class RimWellLogCurve : public caf::PdmObject caf::PdmField m_autoName; caf::PdmField m_curveColor; caf::PdmField m_curveThickness; + + caf::PdmField< caf::AppEnum< CurvePlotTypeEnum > > m_curvePlotStyle; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 76a5dee24f..1d471b8de7 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -383,6 +383,7 @@ void RimWellLogExtractionCurve::defineUiOrdering(QString uiConfigName, caf::PdmU caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); appearanceGroup->add(&m_curveThickness); + appearanceGroup->add(&m_curvePlotStyle); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); if (m_autoName) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index 70a600074d..7b3edf7a72 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -176,6 +176,7 @@ void RimWellLogFileCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); appearanceGroup->add(&m_curveThickness); + appearanceGroup->add(&m_curvePlotStyle); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); } From 8e0e16447e920f9fa2ac0e104642eda504a8a311 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 07:55:35 +0100 Subject: [PATCH 229/290] (#460) Added logarithmic x-axis for tracks --- .../ProjectDataModel/RimWellLogTrack.cpp | 60 ++++++++++++++++++- .../ProjectDataModel/RimWellLogTrack.h | 7 ++- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 635beae269..b787b8db2b 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -27,7 +27,11 @@ #include "RiuMainWindow.h" #include "cafPdmUiTreeView.h" + #include "cvfAssert.h" +#include "cvfMath.h" + +#include "qwt_scale_engine.h" #include @@ -56,7 +60,9 @@ RimWellLogTrack::RimWellLogTrack() CAF_PDM_InitField(&m_visibleXRangeMin, "VisibleXRangeMin", RI_LOGPLOTTRACK_MINX_DEFAULT, "Min", "", "", ""); CAF_PDM_InitField(&m_visibleXRangeMax, "VisibleXRangeMax", RI_LOGPLOTTRACK_MAXX_DEFAULT, "Max", "", "", ""); - CAF_PDM_InitField(&m_isAutoScaleXEnabled, "AutoScaleX", true, "Auto Scale", "", "", ""); + CAF_PDM_InitField(&m_isAutoScaleXEnabled, "AutoScaleX", true, "Auto Scale", "", "", ""); + + CAF_PDM_InitField(&m_isLogarithmicScaleEnabled, "LogarithmicScaleX", false, "Logarithmic Scale", "", "", ""); } //-------------------------------------------------------------------------------------------------- @@ -98,18 +104,33 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, } else if (changedField == &m_visibleXRangeMin || changedField == &m_visibleXRangeMax) { + clampMinimumXRangeForLogarithmicScale(); + m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); m_wellLogTrackPlotWidget->replot(); m_isAutoScaleXEnabled = false; } - else if (changedField == &m_isAutoScaleXEnabled ) + else if (changedField == &m_isAutoScaleXEnabled) { if (m_isAutoScaleXEnabled()) { this->zoomAllXAxisIfAutoScale(); + clampMinimumXRangeForLogarithmicScale(); + if (m_wellLogTrackPlotWidget) m_wellLogTrackPlotWidget->replot(); } } + else if (changedField == &m_isLogarithmicScaleEnabled) + { + updateAxisScaleEngine(); + + this->zoomAllXAxisIfAutoScale(); + clampMinimumXRangeForLogarithmicScale(); + + m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); + + m_wellLogTrackPlotWidget->replot(); + } } //-------------------------------------------------------------------------------------------------- @@ -238,6 +259,7 @@ void RimWellLogTrack::recreateViewer() if (m_wellLogTrackPlotWidget == NULL) { m_wellLogTrackPlotWidget = new RiuWellLogTrack(this); + updateAxisScaleEngine(); for (size_t cIdx = 0; cIdx < curves.size(); ++cIdx) { @@ -315,6 +337,8 @@ void RimWellLogTrack::zoomAllXAxisIfAutoScale() m_visibleXRangeMin = minValue; m_visibleXRangeMax = maxValue; + clampMinimumXRangeForLogarithmicScale(); + if (m_wellLogTrackPlotWidget) m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); updateConnectedEditors(); @@ -347,7 +371,7 @@ void RimWellLogTrack::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& gridGroup->add(&m_isAutoScaleXEnabled); gridGroup->add(&m_visibleXRangeMin); gridGroup->add(&m_visibleXRangeMax); - + gridGroup->add(&m_isLogarithmicScaleEnabled); } //-------------------------------------------------------------------------------------------------- @@ -365,3 +389,33 @@ bool RimWellLogTrack::isVisible() { return m_show; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogTrack::updateAxisScaleEngine() +{ + if (m_isLogarithmicScaleEnabled) + { + m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xTop, new QwtLogScaleEngine); + } + else + { + m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xTop, new QwtLinearScaleEngine); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogTrack::clampMinimumXRangeForLogarithmicScale() +{ + if (m_isLogarithmicScaleEnabled) + { + double minValue = m_visibleXRangeMin; + + minValue = cvf::Math::clamp(minValue, 0.01, m_visibleXRangeMax()); + + m_visibleXRangeMin = minValue; + } +} diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index 1f9b615978..0d54a1eec6 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -65,14 +65,18 @@ class RimWellLogTrack : public caf::PdmObject RimWellLogCurve* curveDefinitionFromCurve(const QwtPlotCurve* curve) const; protected: - // Overridden PDM methods virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + + void clampMinimumXRangeForLogarithmicScale(); + virtual caf::PdmFieldHandle* objectToggleField(); virtual caf::PdmFieldHandle* userDescriptionField(); virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); private: + void updateAxisScaleEngine(); + private: caf::PdmField m_show; caf::PdmField m_userName; @@ -80,6 +84,7 @@ class RimWellLogTrack : public caf::PdmObject caf::PdmField m_visibleXRangeMin; caf::PdmField m_visibleXRangeMax; caf::PdmField m_isAutoScaleXEnabled; + caf::PdmField m_isLogarithmicScaleEnabled; QPointer m_wellLogTrackPlotWidget; }; From e9b18e05fe59e7b01d2b995971e2fa1108cda91d Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 08:02:33 +0100 Subject: [PATCH 230/290] (#697) Set color for point symbols --- ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index ca556584b1..9c12a90d36 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -343,15 +343,17 @@ const RigWellLogCurveData* RimWellLogCurve::curveData() const void RimWellLogCurve::updateCurvePen() { CVF_ASSERT(m_qwtPlotCurve); - m_qwtPlotCurve->setPen(QColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()), m_curveThickness); - QwtSymbol* symbol = NULL; + QColor curveColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); + m_qwtPlotCurve->setPen(curveColor, m_curveThickness); + QwtSymbol* symbol = NULL; if (m_curvePlotStyle == LINE_AND_SYMBOL || m_curvePlotStyle == SYMBOL) { // QwtPlotCurve will take ownership of the symbol symbol = new QwtSymbol(QwtSymbol::XCross); symbol->setSize(6, 6); + symbol->setColor(curveColor); } QwtPlotCurve::CurveStyle curveStyle = QwtPlotCurve::Lines; From 28a0e1107c87e8e91b4fa1c54b25192ff4864e41 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 09:17:13 +0100 Subject: [PATCH 231/290] Improved result accessor factory Moved clamping of time step to zero for static results into factory --- .../RivCrossSectionPartMgr.cpp | 11 ++----- .../RivReservoirViewPartMgr.cpp | 11 +------ .../RivTextureCoordsCreator.cpp | 8 +---- .../RimWellLogExtractionCurve.cpp | 9 ++---- .../RigResultAccessorFactory.cpp | 31 ++++++++++++++++++- .../RigResultAccessorFactory.h | 12 +++++-- 6 files changed, 46 insertions(+), 36 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp index 4c4b3a83b2..3aa569149e 100644 --- a/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivCrossSectionPartMgr.cpp @@ -126,17 +126,10 @@ void RivCrossSectionPartMgr::updateCellResultColor(size_t timeStepIndex) } else { - size_t adjustedTimeStepIndex = timeStepIndex; - if (cellResultColors->hasStaticResult()) - { - adjustedTimeStepIndex = 0; - } - resultAccessor = RigResultAccessorFactory::createResultAccessor(cellResultColors->reservoirView()->eclipseCase()->reservoirData(), 0, - RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()), - adjustedTimeStepIndex, - cellResultColors->resultVariable()); + timeStepIndex, + cellResultColors); } RivCrossSectionPartMgr::calculateEclipseTextureCoordinates(m_crossSectionFacesTextureCoords.p(), diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp index 762ba1d1a8..5714221d55 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp @@ -785,20 +785,11 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis const double lowerBound = propertyFilter->lowerBound(); const double upperBound = propertyFilter->upperBound(); - size_t adjustedTimeStepIndex = timeStepIndex; - - // Set time step to zero for static results - if (propertyFilter->resultDefinition()->hasStaticResult()) - { - adjustedTimeStepIndex = 0; - } - const RimCellFilter::FilterModeType filterType = propertyFilter->filterMode(); - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(propertyFilter->resultDefinition()->porosityModel()); RigCaseData* eclipseCase = propFilterColl->reservoirView()->eclipseCase()->reservoirData(); - cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, grid->gridIndex(), porosityModel, adjustedTimeStepIndex, propertyFilter->resultDefinition->resultVariable(), propertyFilter->resultDefinition->resultType()); + cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, grid->gridIndex(), timeStepIndex, propertyFilter->resultDefinition()); CVF_ASSERT(resultAccessor.notNull()); //#pragma omp parallel for schedule(dynamic) diff --git a/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp index 4683af0e17..91dbabe2db 100644 --- a/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp @@ -39,13 +39,7 @@ RivTextureCoordsCreator::RivTextureCoordsCreator(RimEclipseCellColors* cellResul m_quadMapper = quadMapper; CVF_ASSERT(quadMapper && eclipseCase ); - size_t resTimeStepIdx = timeStepIndex; - - if (cellResultColors->hasStaticResult()) resTimeStepIdx = 0; - - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(cellResultColors->porosityModel()); - - m_resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, cellResultColors->resultVariable()); + m_resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, timeStepIndex, cellResultColors); cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), eclipseCase->gridCellToWellIndex(gridIndex)); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 1d471b8de7..6e9ada5311 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -213,14 +213,11 @@ void RimWellLogExtractionCurve::updatePlotData() tvDepthValues = eclExtractor->trueVerticalDepth(); } - RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(m_eclipseResultDefinition->porosityModel()); - m_eclipseResultDefinition->loadResult(); - cvf::ref resAcc = RigResultAccessorFactory::createResultAccessor( - eclipseCase->reservoirData(), 0, - porosityModel, + eclipseCase->reservoirData(), + 0, m_timeStep, - m_eclipseResultDefinition->resultVariable()); + m_eclipseResultDefinition); if (resAcc.notNull()) { diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp index 5377028d91..958fe7f689 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp @@ -30,6 +30,8 @@ #include "RigMainGrid.h" #include "RigResultAccessor.h" +#include "RimEclipseResultDefinition.h" + #include "cvfAssert.h" #include "cvfBase.h" #include "cvfLibCore.h" @@ -145,7 +147,34 @@ cvf::ref RigResultAccessorFactory::createResultAccessor(RigCa return NULL; } - return createResultAccessor(eclipseCase, gridIndex, porosityModel, timeStepIndex, scalarSetIndex); + size_t adjustedTimeStepIndex = timeStepIndex; + if (resultType == RimDefines::STATIC_NATIVE) + { + adjustedTimeStepIndex = 0; + } + + return createResultAccessor(eclipseCase, gridIndex, porosityModel, adjustedTimeStepIndex, scalarSetIndex); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RigResultAccessorFactory::createResultAccessor(RigCaseData* eclipseCase, size_t gridIndex, size_t timeStepIndex, RimEclipseResultDefinition* resultDefinition) +{ + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(resultDefinition->porosityModel()); + resultDefinition->loadResult(); + + size_t adjustedTimeStepIndex = timeStepIndex; + if (resultDefinition->hasStaticResult()) + { + adjustedTimeStepIndex = 0; + } + + return RigResultAccessorFactory::createResultAccessor( + eclipseCase, 0, + porosityModel, + adjustedTimeStepIndex, + resultDefinition->resultVariable()); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h index aec039f3fe..b85440b573 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h @@ -21,14 +21,23 @@ #include "RifReaderInterface.h" #include "RigResultAccessor.h" + #include "RimDefines.h" class RigActiveCellInfo; class RigGridBase; +class RimEclipseResultDefinition; + class RigResultAccessorFactory { public: + static cvf::ref + createResultAccessor(RigCaseData* eclipseCase, + size_t gridIndex, + size_t timeStepIndex, + RimEclipseResultDefinition* resultDefinition); + static cvf::ref createResultAccessor(RigCaseData* eclipseCase, size_t gridIndex, @@ -51,8 +60,6 @@ class RigResultAccessorFactory size_t timeStepIndex, size_t resultIndex); - - private: static cvf::ref createNativeResultAccessor(RigCaseData* eclipseCase, @@ -61,7 +68,6 @@ class RigResultAccessorFactory size_t timeStepIndex, const QString& resultName); - }; From a31973e655e076ee18328b54e85678cbd2b8a8eb Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 09:36:05 +0100 Subject: [PATCH 232/290] Made posNegClosestToZero a static function --- .../RigEclipseNativeStatCalc.cpp | 22 +--------------- .../RigStatisticsCalculator.cpp | 25 +++++++++++++++++++ .../RigStatisticsCalculator.h | 2 ++ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp index a152114abf..1a0c0a1665 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp @@ -70,27 +70,9 @@ void RigEclipseNativeStatCalc::posNegClosestToZero(size_t timeStepIndex, double& { std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); - size_t i; - for (i = 0; i < values.size(); i++) - { - if (values[i] == HUGE_VAL) - { - continue; - } - - if (values[i] < pos && values[i] > 0) - { - pos = values[i]; - } - - if (values[i] > neg && values[i] < 0) - { - neg = values[i]; - } - } + RigStatisticsCalculator::posNegClosestToZero(values, pos, neg); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -101,8 +83,6 @@ void RigEclipseNativeStatCalc::addDataToHistogramCalculator(size_t timeStepIndex histogramCalculator.addData(values); } - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp index 80270f146d..b02b942cb5 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.cpp @@ -87,3 +87,28 @@ void RigStatisticsCalculator::addDataToHistogramCalculator(RigHistogramCalculato } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigStatisticsCalculator::posNegClosestToZero(const std::vector& values, double& pos, double& neg) +{ + size_t i; + for (i = 0; i < values.size(); i++) + { + if (values[i] == HUGE_VAL) + { + continue; + } + + if (values[i] < pos && values[i] > 0) + { + pos = values[i]; + } + + if (values[i] > neg && values[i] < 0) + { + neg = values[i]; + } + } +} + diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h index d3ab541e54..2ddfd404eb 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsCalculator.h @@ -46,4 +46,6 @@ class RigStatisticsCalculator : public cvf::Object virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) = 0; virtual size_t timeStepCount() = 0; + + static void posNegClosestToZero(const std::vector& values, double& pos, double& neg); }; From dd78842ad402ee8d7248eea6feef438bec809e21 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 10:14:58 +0100 Subject: [PATCH 233/290] (#460) Use smallest positive value as axis limit when autoscaling log --- .../ProjectDataModel/RimWellLogTrack.cpp | 32 ++++++++++++------- .../ProjectDataModel/RimWellLogTrack.h | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index b787b8db2b..d21cfc93b6 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -19,6 +19,8 @@ #include "RimWellLogTrack.h" +#include "RigStatisticsCalculator.h" + #include "RimWellLogPlot.h" #include "RimWellLogCurve.h" @@ -104,8 +106,6 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, } else if (changedField == &m_visibleXRangeMin || changedField == &m_visibleXRangeMax) { - clampMinimumXRangeForLogarithmicScale(); - m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); m_wellLogTrackPlotWidget->replot(); m_isAutoScaleXEnabled = false; @@ -115,7 +115,7 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, if (m_isAutoScaleXEnabled()) { this->zoomAllXAxisIfAutoScale(); - clampMinimumXRangeForLogarithmicScale(); + computeAndSetXRangeMinForLogarithmicScale(); if (m_wellLogTrackPlotWidget) m_wellLogTrackPlotWidget->replot(); } @@ -125,7 +125,7 @@ void RimWellLogTrack::fieldChangedByUi(const caf::PdmFieldHandle* changedField, updateAxisScaleEngine(); this->zoomAllXAxisIfAutoScale(); - clampMinimumXRangeForLogarithmicScale(); + computeAndSetXRangeMinForLogarithmicScale(); m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); @@ -337,7 +337,7 @@ void RimWellLogTrack::zoomAllXAxisIfAutoScale() m_visibleXRangeMin = minValue; m_visibleXRangeMax = maxValue; - clampMinimumXRangeForLogarithmicScale(); + computeAndSetXRangeMinForLogarithmicScale(); if (m_wellLogTrackPlotWidget) m_wellLogTrackPlotWidget->setXRange(m_visibleXRangeMin, m_visibleXRangeMax); @@ -408,14 +408,24 @@ void RimWellLogTrack::updateAxisScaleEngine() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogTrack::clampMinimumXRangeForLogarithmicScale() +void RimWellLogTrack::computeAndSetXRangeMinForLogarithmicScale() { - if (m_isLogarithmicScaleEnabled) + if (m_isAutoScaleXEnabled && m_isLogarithmicScaleEnabled) { - double minValue = m_visibleXRangeMin; - - minValue = cvf::Math::clamp(minValue, 0.01, m_visibleXRangeMax()); + double pos = HUGE_VAL; + double neg = -HUGE_VAL; + + for (size_t cIdx = 0; cIdx < curves.size(); cIdx++) + { + if (curves[cIdx]->isCurveVisible() && curves[cIdx]->curveData()) + { + RigStatisticsCalculator::posNegClosestToZero(curves[cIdx]->curveData()->xPlotValues(), pos, neg); + } + } - m_visibleXRangeMin = minValue; + if (pos != HUGE_VAL) + { + m_visibleXRangeMin = pos; + } } } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index 0d54a1eec6..037c5cc966 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -68,7 +68,7 @@ class RimWellLogTrack : public caf::PdmObject // Overridden PDM methods virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - void clampMinimumXRangeForLogarithmicScale(); + void computeAndSetXRangeMinForLogarithmicScale(); virtual caf::PdmFieldHandle* objectToggleField(); virtual caf::PdmFieldHandle* userDescriptionField(); From b80639436cf253a3b79d281fe234eb0890d828b5 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 11:14:21 +0100 Subject: [PATCH 234/290] (#460) Show grid using logarithmic scale div --- ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index d21cfc93b6..1c56658c45 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -398,13 +398,20 @@ void RimWellLogTrack::updateAxisScaleEngine() if (m_isLogarithmicScaleEnabled) { m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xTop, new QwtLogScaleEngine); + + // NB! Must assign scale engine to bottom in order to make QwtPlotGrid work + m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xBottom, new QwtLogScaleEngine); } else { m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xTop, new QwtLinearScaleEngine); + + // NB! Must assign scale engine to bottom in order to make QwtPlotGrid work + m_wellLogTrackPlotWidget->setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine); } } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- From c67a413926c20bc343d27b8e1693b175dc2bad91 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 11:32:46 +0100 Subject: [PATCH 235/290] (#464) Set logarithmic scale if PERM is selected as single curve --- .../RimWellLogExtractionCurve.cpp | 22 +++++++++++++++++++ .../RimWellLogExtractionCurve.h | 7 ++++-- .../ProjectDataModel/RimWellLogTrack.cpp | 11 ++++++++++ .../ProjectDataModel/RimWellLogTrack.h | 2 ++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 6e9ada5311..ed35a1fdff 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -276,6 +276,8 @@ void RimWellLogExtractionCurve::updatePlotData() zoomAllOwnerTrackAndPlot(); + setLogScaleFromSelectedResult(); + if (m_ownerQwtTrack) m_ownerQwtTrack->replot(); } } @@ -418,6 +420,26 @@ void RimWellLogExtractionCurve::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiT uiTreeOrdering.setForgetRemainingFields(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogExtractionCurve::setLogScaleFromSelectedResult() +{ + QString resVar = m_eclipseResultDefinition->resultVariable(); + + if (resVar.toUpper().contains("PERM")) + { + RimWellLogTrack* track = NULL; + this->firstAnchestorOrThisOfType(track); + if (track) + { + if (track->curveCount() == 1) + { + track->setLogarithmicScale(true); + } + } + } +} //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index 9f0428f412..87f8f47f9e 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -27,8 +27,8 @@ class RimCase; class RimEclipseResultDefinition; class RimGeoMechResultDefinition; -class RimWellPath; class RimView; +class RimWellPath; //================================================================================================== /// @@ -62,6 +62,10 @@ class RimWellLogExtractionCurve : public RimWellLogCurve virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); +private: + void setLogScaleFromSelectedResult(); + +private: caf::PdmPtrField m_wellPath; caf::PdmPtrField m_case; caf::PdmChildField m_eclipseResultDefinition; @@ -75,4 +79,3 @@ class RimWellLogExtractionCurve : public RimWellLogCurve caf::PdmField m_addDateToCurveName; }; - diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 1c56658c45..a4ba26e4e4 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -436,3 +436,14 @@ void RimWellLogTrack::computeAndSetXRangeMinForLogarithmicScale() } } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogTrack::setLogarithmicScale(bool enable) +{ + m_isLogarithmicScaleEnabled = enable; + + updateAxisScaleEngine(); + computeAndSetXRangeMinForLogarithmicScale(); +} diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h index 037c5cc966..0080fe58d0 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.h @@ -64,6 +64,8 @@ class RimWellLogTrack : public caf::PdmObject RimWellLogCurve* curveDefinitionFromCurve(const QwtPlotCurve* curve) const; + void setLogarithmicScale(bool enable); + protected: // Overridden PDM methods virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); From a608904beadd3817459b6b9ac88685522d629e16 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 12:21:57 +0100 Subject: [PATCH 236/290] (#697) Added combo box for selection of point and line style --- .../ProjectDataModel/RimWellLogCurve.cpp | 106 +++++++++++++++--- .../ProjectDataModel/RimWellLogCurve.h | 26 ++++- .../RimWellLogExtractionCurve.cpp | 3 +- .../ProjectDataModel/RimWellLogFileCurve.cpp | 3 +- 4 files changed, 113 insertions(+), 25 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp index 9c12a90d36..af592db80a 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.cpp @@ -38,12 +38,30 @@ CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimWellLogCurve, "WellLogPlotCurve"); namespace caf { template<> - void caf::AppEnum< RimWellLogCurve::CurvePlotTypeEnum >::setUp() + void caf::AppEnum< RimWellLogCurve::LineStyleEnum >::setUp() { - addItem(RimWellLogCurve::LINE, "LINE", "Line"); - addItem(RimWellLogCurve::SYMBOL, "SYMBOL", "Symbol"); - addItem(RimWellLogCurve::LINE_AND_SYMBOL, "LINE_AND_SYMBOL", "Line and Symbol"); - setDefault(RimWellLogCurve::LINE); + addItem(RimWellLogCurve::STYLE_NONE, "STYLE_NONE", "None"); + addItem(RimWellLogCurve::STYLE_SOLID, "STYLE_SOLID", "Solid"); + addItem(RimWellLogCurve::STYLE_DASH, "STYLE_DASH", "Dashes"); + addItem(RimWellLogCurve::STYLE_DOT, "STYLE_DOT", "Dots"); + addItem(RimWellLogCurve::STYLE_DASH_DOT,"STYLE_DASH_DOT", "Dashes and Dots"); + + setDefault(RimWellLogCurve::STYLE_SOLID); + } + + + template<> + void caf::AppEnum< RimWellLogCurve::PointSymbolEnum >::setUp() + { + addItem(RimWellLogCurve::SYMBOL_NONE, "SYMBOL_NONE", "None"); + addItem(RimWellLogCurve::SYMBOL_ELLIPSE, "SYMBOL_ELLIPSE", "Ellipse"); + addItem(RimWellLogCurve::SYMBOL_RECT, "SYMBOL_RECT", "Rect"); + addItem(RimWellLogCurve::SYMBOL_DIAMOND, "SYMBOL_DIAMOND", "Diamond"); + addItem(RimWellLogCurve::SYMBOL_TRIANGLE, "SYMBOL_TRIANGLE", "Triangle"); + addItem(RimWellLogCurve::SYMBOL_CROSS, "SYMBOL_CROSS", "Cross"); + addItem(RimWellLogCurve::SYMBOL_XCROSS, "SYMBOL_XCROSS", "X Cross"); + + setDefault(RimWellLogCurve::SYMBOL_NONE); } } @@ -68,8 +86,11 @@ RimWellLogCurve::RimWellLogCurve() CAF_PDM_InitField(&m_curveThickness, "Thickness", 1.0f, "Thickness", "", "", ""); m_curveThickness.uiCapability()->setUiEditorTypeName(caf::PdmUiComboBoxEditor::uiEditorTypeName()); - caf::AppEnum< RimWellLogCurve::CurvePlotTypeEnum > curvePlotType = LINE; - CAF_PDM_InitField(&m_curvePlotStyle, "CurvePlotStyle", curvePlotType, "Curve style", "", "", ""); + caf::AppEnum< RimWellLogCurve::LineStyleEnum > lineStyle = STYLE_SOLID; + CAF_PDM_InitField(&m_lineStyle, "LineStyle", lineStyle, "Line style", "", "", ""); + + caf::AppEnum< RimWellLogCurve::PointSymbolEnum > pointSymbol = SYMBOL_NONE; + CAF_PDM_InitField(&m_pointSymbol, "PointSymbol", pointSymbol, "Point style", "", "", ""); m_qwtPlotCurve = new RiuLineSegmentQwtPlotCurve; m_qwtPlotCurve->setXAxis(QwtPlot::xTop); @@ -108,9 +129,10 @@ void RimWellLogCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, } else if (&m_curveColor == changedField || &m_curveThickness == changedField - || &m_curvePlotStyle == changedField) + || &m_pointSymbol == changedField + || &m_lineStyle == changedField) { - updateCurvePen(); + updateCurveAppearance(); } else if (changedField == &m_autoName) { @@ -174,7 +196,7 @@ void RimWellLogCurve::updatePlotConfiguration() this->updateCurveName(); this->updatePlotTitle(); - updateCurvePen(); + updateCurveAppearance(); // Todo: Rest of the curve setup controlled from this class } @@ -340,28 +362,78 @@ const RigWellLogCurveData* RimWellLogCurve::curveData() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogCurve::updateCurvePen() +void RimWellLogCurve::updateCurveAppearance() { CVF_ASSERT(m_qwtPlotCurve); QColor curveColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); - m_qwtPlotCurve->setPen(curveColor, m_curveThickness); QwtSymbol* symbol = NULL; - if (m_curvePlotStyle == LINE_AND_SYMBOL || m_curvePlotStyle == SYMBOL) + + if (m_pointSymbol() != SYMBOL_NONE) { + QwtSymbol::Style style = QwtSymbol::NoSymbol; + + switch (m_pointSymbol()) + { + case SYMBOL_ELLIPSE : + style = QwtSymbol::Ellipse; + break; + case SYMBOL_RECT: + style = QwtSymbol::Rect; + break; + case SYMBOL_DIAMOND: + style = QwtSymbol::Diamond; + break; + case SYMBOL_TRIANGLE: + style = QwtSymbol::Triangle; + break; + case SYMBOL_CROSS: + style = QwtSymbol::Cross; + break; + case SYMBOL_XCROSS: + style = QwtSymbol::XCross; + break; + + default: + break; + } + // QwtPlotCurve will take ownership of the symbol - symbol = new QwtSymbol(QwtSymbol::XCross); + symbol = new QwtSymbol(style); + symbol->setSize(6, 6); symbol->setColor(curveColor); } - QwtPlotCurve::CurveStyle curveStyle = QwtPlotCurve::Lines; - if (m_curvePlotStyle == SYMBOL) + QwtPlotCurve::CurveStyle curveStyle = QwtPlotCurve::NoCurve; + Qt::PenStyle penStyle = Qt::SolidLine; + + if (m_lineStyle() != STYLE_NONE) { - curveStyle = QwtPlotCurve::NoCurve; + curveStyle = QwtPlotCurve::Lines; + + switch (m_lineStyle()) + { + case STYLE_SOLID: + penStyle = Qt::SolidLine; + break; + case STYLE_DASH: + penStyle = Qt::DashLine; + break; + case STYLE_DOT: + penStyle = Qt::DotLine; + break; + case STYLE_DASH_DOT: + penStyle = Qt::DashDotLine; + break; + + default: + break; + } } + m_qwtPlotCurve->setPen(curveColor, m_curveThickness, penStyle); m_qwtPlotCurve->setStyle(curveStyle); m_qwtPlotCurve->setSymbol(symbol); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h index aee4951311..31b427596b 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogCurve.h @@ -45,11 +45,24 @@ class RimWellLogCurve : public caf::PdmObject { CAF_PDM_HEADER_INIT; public: - enum CurvePlotTypeEnum + enum LineStyleEnum { - LINE, - SYMBOL, - LINE_AND_SYMBOL + STYLE_NONE, + STYLE_SOLID, + STYLE_DASH, + STYLE_DOT, + STYLE_DASH_DOT + }; + + enum PointSymbolEnum + { + SYMBOL_NONE, + SYMBOL_ELLIPSE, + SYMBOL_RECT, + SYMBOL_DIAMOND, + SYMBOL_TRIANGLE, + SYMBOL_CROSS, + SYMBOL_XCROSS }; public: @@ -85,7 +98,7 @@ class RimWellLogCurve : public caf::PdmObject void updateCurveVisibility(); void zoomAllOwnerTrackAndPlot(); void updateOptionSensitivity(); - void updateCurvePen(); + void updateCurveAppearance(); // Overridden PDM methods virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); @@ -107,5 +120,6 @@ class RimWellLogCurve : public caf::PdmObject caf::PdmField m_curveColor; caf::PdmField m_curveThickness; - caf::PdmField< caf::AppEnum< CurvePlotTypeEnum > > m_curvePlotStyle; + caf::PdmField< caf::AppEnum< PointSymbolEnum > > m_pointSymbol; + caf::PdmField< caf::AppEnum< LineStyleEnum > > m_lineStyle; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index ed35a1fdff..99e2be0caf 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -382,7 +382,8 @@ void RimWellLogExtractionCurve::defineUiOrdering(QString uiConfigName, caf::PdmU caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); appearanceGroup->add(&m_curveThickness); - appearanceGroup->add(&m_curvePlotStyle); + appearanceGroup->add(&m_pointSymbol); + appearanceGroup->add(&m_lineStyle); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); if (m_autoName) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp index 7b3edf7a72..cc5233b32d 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFileCurve.cpp @@ -176,7 +176,8 @@ void RimWellLogFileCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); appearanceGroup->add(&m_curveColor); appearanceGroup->add(&m_curveThickness); - appearanceGroup->add(&m_curvePlotStyle); + appearanceGroup->add(&m_pointSymbol); + appearanceGroup->add(&m_lineStyle); appearanceGroup->add(&m_curveName); appearanceGroup->add(&m_autoName); } From 5e6fc505d066fc42475738361b60668412bcbcec Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 12:26:32 +0100 Subject: [PATCH 237/290] (#694) Fixed missing assigment --- ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp index 2d2c075539..97fe54a4e6 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathSourceInfo.cpp @@ -90,7 +90,7 @@ void RivWellPathSourceInfo::normalizedIntersection(size_t triangleIndex, const c double norm = 0.0; cvf::Vec3d pointOnLine = cvf::GeometryTools::projectPointOnLine(segmentStart, segmentEnd, globalIntersection, &norm); - cvf::Math::clamp(norm, 0.0, 1.0); + norm = cvf::Math::clamp(norm, 0.0, 1.0); *firstSegmentIndex = segIndex; *normalizedSegmentIntersection = norm; From a86d24df974e5a4a92ce4b1d953aef6d7d808270 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 13:34:13 +0100 Subject: [PATCH 238/290] Fwk : Added DEBUG assert to detect when data is present in child fields Added assert for ChildArrayField and ChildField --- .../cafPdmCore/cafPdmChildArrayField.inl | 7 +++++++ .../cafProjectDataModel/cafPdmCore/cafPdmChildField.inl | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl index a5b06a0ec7..d928a36bec 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildArrayField.inl @@ -15,6 +15,13 @@ namespace caf template PdmChildArrayField::~PdmChildArrayField() { +#ifdef _DEBUG + for (size_t index = 0; index < m_pointers.size(); ++index) + { + assert(m_pointers.at(index).isNull()); + } +#endif + this->removeThisAsParentField(); } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildField.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildField.inl index d23c6c6a83..8819ce3b1c 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildField.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmChildField.inl @@ -52,6 +52,10 @@ caf::PdmChildField::PdmChildField(const DataTypePtr& fieldValue) template caf::PdmChildField::~PdmChildField() { +#ifdef _DEBUG + assert(m_fieldValue.isNull()); +#endif + if (!m_fieldValue.isNull()) m_fieldValue.rawPtr()->removeAsParentField(this); m_fieldValue.setRawPtr(NULL); } From 47bb20368ab6c79b50c88c04900a615bae94e9a4 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 13:52:25 +0100 Subject: [PATCH 239/290] System : Fixed memory leaks --- ApplicationCode/Application/RiaPreferences.cpp | 2 +- ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp | 2 ++ ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp | 1 + .../ProjectDataModel/RimEclipsePropertyFilterCollection.cpp | 3 +-- ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp | 1 + ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp | 1 + .../ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp | 2 +- ApplicationCode/ProjectDataModel/RimGeoMechView.cpp | 3 +++ ApplicationCode/ProjectDataModel/RimView.cpp | 1 + ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp | 3 ++- ApplicationCode/ProjectDataModel/RimWellLogFile.cpp | 1 + ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp | 3 +++ ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp | 2 ++ 13 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/Application/RiaPreferences.cpp b/ApplicationCode/Application/RiaPreferences.cpp index 0f5ac014b5..aabcf2ae8a 100644 --- a/ApplicationCode/Application/RiaPreferences.cpp +++ b/ApplicationCode/Application/RiaPreferences.cpp @@ -90,7 +90,7 @@ RiaPreferences::RiaPreferences(void) //-------------------------------------------------------------------------------------------------- RiaPreferences::~RiaPreferences(void) { - + delete readerSettings; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp index 5122a5ff1b..9444b09cf7 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp @@ -58,6 +58,8 @@ RimEclipseFaultColors::RimEclipseFaultColors() //-------------------------------------------------------------------------------------------------- RimEclipseFaultColors::~RimEclipseFaultColors() { + delete m_customFaultResultColors; + m_customFaultResultColors = NULL; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp index d931a141e4..7c2c1503dc 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp @@ -86,6 +86,7 @@ RimEclipsePropertyFilter::RimEclipsePropertyFilter() //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilter::~RimEclipsePropertyFilter() { + delete resultDefinition; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp index 4e157d0471..5475d726f3 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp @@ -40,7 +40,6 @@ RimEclipsePropertyFilterCollection::RimEclipsePropertyFilterCollection() CAF_PDM_InitFieldNoDefault(&propertyFilters, "PropertyFilters", "Property Filters", "", "", ""); propertyFilters.uiCapability()->setUiHidden(true); - } //-------------------------------------------------------------------------------------------------- @@ -48,7 +47,7 @@ RimEclipsePropertyFilterCollection::RimEclipsePropertyFilterCollection() //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilterCollection::~RimEclipsePropertyFilterCollection() { - + propertyFilters.deleteAllChildObjects(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp index fa1e58a3ab..c6892aadb4 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp @@ -43,6 +43,7 @@ RimGeoMechCellColors::RimGeoMechCellColors(void) //-------------------------------------------------------------------------------------------------- RimGeoMechCellColors::~RimGeoMechCellColors(void) { + delete legendConfig; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp index 74e58f210e..dc136b27a9 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp @@ -69,6 +69,7 @@ RimGeoMechPropertyFilter::RimGeoMechPropertyFilter() //-------------------------------------------------------------------------------------------------- RimGeoMechPropertyFilter::~RimGeoMechPropertyFilter() { + delete resultDefinition; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp index 18c5c34c68..d17479ff5b 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilterCollection.cpp @@ -47,7 +47,7 @@ RimGeoMechPropertyFilterCollection::RimGeoMechPropertyFilterCollection() //-------------------------------------------------------------------------------------------------- RimGeoMechPropertyFilterCollection::~RimGeoMechPropertyFilterCollection() { - + propertyFilters.deleteAllChildObjects(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 2b7e2ec571..d3aaf1366a 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -96,6 +96,9 @@ RimGeoMechView::RimGeoMechView(void) RimGeoMechView::~RimGeoMechView(void) { m_geomechCase = NULL; + + delete cellResult; + delete m_propertyFilterCollection; } diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 93b98ab50d..676794d4fa 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -175,6 +175,7 @@ RimView::~RimView(void) delete m_rangeFilterCollection; delete m_overrideRangeFilterCollection; delete crossSectionCollection; + delete m_gridCollection; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 99e2be0caf..7f6a4bbfc7 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -99,7 +99,8 @@ RimWellLogExtractionCurve::RimWellLogExtractionCurve() //-------------------------------------------------------------------------------------------------- RimWellLogExtractionCurve::~RimWellLogExtractionCurve() { - + delete m_geomResultDefinition; + delete m_eclipseResultDefinition; } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp index 4fc50b885a..576030190f 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp @@ -65,6 +65,7 @@ RimWellLogFile::RimWellLogFile() //-------------------------------------------------------------------------------------------------- RimWellLogFile::~RimWellLogFile() { + m_wellLogChannelNames.deleteAllChildObjects(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index d78dbff5cd..d0b49819fb 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -89,7 +89,10 @@ RimWellLogPlot::RimWellLogPlot() RimWellLogPlot::~RimWellLogPlot() { RiuMainWindow::instance()->removeViewer(m_viewer); + detachAllCurves(); + m_tracks.deleteAllChildObjects(); + delete m_viewer; } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index a4ba26e4e4..8fb6447c01 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -72,6 +72,8 @@ RimWellLogTrack::RimWellLogTrack() //-------------------------------------------------------------------------------------------------- RimWellLogTrack::~RimWellLogTrack() { + curves.deleteAllChildObjects(); + delete m_wellLogTrackPlotWidget; } From 4713014d26eb0ae5ab912ce9f6011e827d89d98e Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 15:36:37 +0100 Subject: [PATCH 240/290] (#700) Build bounding box search tree when grid is loaded --- ApplicationCode/ReservoirDataModel/RigMainGrid.cpp | 14 ++++++++++++-- ApplicationCode/ReservoirDataModel/RigMainGrid.h | 6 ++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp index 463ba5e632..705da96221 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp @@ -116,6 +116,8 @@ void RigMainGrid::computeCachedData() { initAllSubGridsParentGridPointer(); initAllSubCellsMainGridCellIndex(); + + buildCellSearchTree(); } //-------------------------------------------------------------------------------------------------- @@ -449,6 +451,16 @@ const RigFault* RigMainGrid::findFaultFromCellIndexAndCellFace(size_t reservoirC /// //-------------------------------------------------------------------------------------------------- void RigMainGrid::findIntersectingCells(const cvf::BoundingBox& inputBB, std::vector* cellIndices) const +{ + CVF_ASSERT(m_cellSearchTree.notNull()); + + m_cellSearchTree->findIntersections(inputBB, cellIndices); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigMainGrid::buildCellSearchTree() { if (m_cellSearchTree.isNull()) { @@ -476,8 +488,6 @@ void RigMainGrid::findIntersectingCells(const cvf::BoundingBox& inputBB, std::ve m_cellSearchTree = new cvf::BoundingBoxTree; m_cellSearchTree->buildTreeFromBoundingBoxes(cellBoundingBoxes, NULL); } - - m_cellSearchTree->findIntersections(inputBB, cellIndices); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.h b/ApplicationCode/ReservoirDataModel/RigMainGrid.h index 9a9100722a..085da40b03 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.h +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.h @@ -69,11 +69,13 @@ class RigMainGrid : public RigGridBase void setFlipAxis(bool flipXAxis, bool flipYAxis); void findIntersectingCells(const cvf::BoundingBox& inputBB, std::vector* cellIndices) const; - cvf::BoundingBox boundingBox() const; + + cvf::BoundingBox boundingBox() const; private: void initAllSubGridsParentGridPointer(); void initAllSubCellsMainGridCellIndex(); void computeActiveAndValidCellRanges(); + void buildCellSearchTree(); private: std::vector m_nodes; ///< Global vertex table @@ -87,7 +89,7 @@ class RigMainGrid : public RigGridBase cvf::ref m_faultsPrCellAcc; cvf::Vec3d m_displayModelOffset; - mutable cvf::ref m_cellSearchTree; + cvf::ref m_cellSearchTree; mutable cvf::BoundingBox m_boundingBox; bool m_flipXAxis; From 64b3281382344e87ae9ef310f297366f03f98511 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 9 Dec 2015 18:34:48 +0100 Subject: [PATCH 241/290] (#703) Fixed resolve of PtrField after the object copy was inserted into PdmStructures --- .../RicPasteEclipseViewsFeature.cpp | 37 ++++++++++--------- .../RicPasteGeoMechViewsFeature.cpp | 31 ++++++++-------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp index 2d3426ce09..ce4626fc89 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp @@ -81,30 +81,33 @@ void RicPasteEclipseViewsFeature::onActionTriggered(bool isChecked) if (objectGroup.objects.size() == 0) return; std::vector > eclipseViews; - objectGroup.createCopyByType(&eclipseViews, PdmDefaultObjectFactory::instance()); + objectGroup.objectsByType(&eclipseViews); - if (eclipseViews.size() != 0) + // Add cases to case group + for (size_t i = 0; i < eclipseViews.size(); i++) { - // Add cases to case group - for (size_t i = 0; i < eclipseViews.size(); i++) - { - RimEclipseView* rimReservoirView = eclipseViews[i]; - QString nameOfCopy = QString("Copy of ") + rimReservoirView->name; - rimReservoirView->name = nameOfCopy; - eclipseCase->reservoirViews().push_back(rimReservoirView); + RimEclipseView* rimReservoirView = dynamic_cast(eclipseViews[i]->xmlCapability()->copyByXmlSerialization(PdmDefaultObjectFactory::instance())); + CVF_ASSERT(rimReservoirView); - // Delete all wells to be able to copy/paste between cases, as the wells differ between cases - rimReservoirView->wellCollection()->wells().deleteAllChildObjects(); + QString nameOfCopy = QString("Copy of ") + rimReservoirView->name; + rimReservoirView->name = nameOfCopy; + eclipseCase->reservoirViews().push_back(rimReservoirView); - rimReservoirView->initAfterReadRecursively(); - rimReservoirView->setEclipseCase(eclipseCase); + // Delete all wells to be able to copy/paste between cases, as the wells differ between cases + rimReservoirView->wellCollection()->wells().deleteAllChildObjects(); - caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); + rimReservoirView->setEclipseCase(eclipseCase); - rimReservoirView->loadDataAndUpdate(); + // Resolve references after reservoir view has been inserted into Rim structures + // Intersections referencing a well path requires this + rimReservoirView->initAfterReadRecursively(); + rimReservoirView->resolveReferencesRecursively(); - eclipseCase->updateConnectedEditors(); - } + caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); + + rimReservoirView->loadDataAndUpdate(); + + eclipseCase->updateConnectedEditors(); } } diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteGeoMechViewsFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteGeoMechViewsFeature.cpp index 879ab427b1..63cedf9d73 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteGeoMechViewsFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteGeoMechViewsFeature.cpp @@ -75,27 +75,28 @@ void RicPasteGeoMechViewsFeature::onActionTriggered(bool isChecked) if (objectGroup.objects.size() == 0) return; std::vector > geomViews; - objectGroup.createCopyByType(&geomViews, PdmDefaultObjectFactory::instance()); + objectGroup.objectsByType(&geomViews); - if (geomViews.size() != 0) + // Add cases to case group + for (size_t i = 0; i < geomViews.size(); i++) { - // Add cases to case group - for (size_t i = 0; i < geomViews.size(); i++) - { - RimGeoMechView* rimReservoirView = geomViews[i]; - QString nameOfCopy = QString("Copy of ") + rimReservoirView->name; - rimReservoirView->name = nameOfCopy; - geomCase->geoMechViews().push_back(rimReservoirView); + RimGeoMechView* rimReservoirView = dynamic_cast(geomViews[i]->xmlCapability()->copyByXmlSerialization(PdmDefaultObjectFactory::instance())); + QString nameOfCopy = QString("Copy of ") + rimReservoirView->name; + rimReservoirView->name = nameOfCopy; + geomCase->geoMechViews().push_back(rimReservoirView); - rimReservoirView->initAfterReadRecursively(); - rimReservoirView->setGeoMechCase(geomCase); + rimReservoirView->setGeoMechCase(geomCase); - caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); + // Resolve references after reservoir view has been inserted into Rim structures + // Intersections referencing a well path requires this + rimReservoirView->initAfterReadRecursively(); + rimReservoirView->resolveReferencesRecursively(); - rimReservoirView->loadDataAndUpdate(); + caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); - geomCase->updateConnectedEditors(); - } + rimReservoirView->loadDataAndUpdate(); + + geomCase->updateConnectedEditors(); } } From bbb0a5e9939622bf97f7198d5d5e361736cbfdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sat, 5 Dec 2015 00:56:14 +0100 Subject: [PATCH 242/290] (#168) Wip: Parallel projection. Basics in place --- ApplicationCode/ProjectDataModel/RimView.cpp | 6 + ApplicationCode/ProjectDataModel/RimView.h | 1 + .../UserInterface/RiuCadNavigation.cpp | 2 + .../UserInterface/RiuGeoQuestNavigation.cpp | 2 + .../UserInterface/RiuRmsNavigation.cpp | 2 + Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 1 + Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp | 20 +-- .../cafViewer/cafCeetronPlusNavigation.cpp | 1 + Fwk/AppFwk/cafViewer/cafViewer.cpp | 130 ++++++++++++++---- Fwk/AppFwk/cafViewer/cafViewer.h | 5 +- 10 files changed, 127 insertions(+), 43 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index 676794d4fa..c089742ebd 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -77,6 +77,8 @@ RimView::RimView(void) showWindow.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&cameraPosition, "CameraPosition", cvf::Mat4d::IDENTITY, "", "", "", ""); cameraPosition.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&isPerspectiveView, "PerspectiveProjection", true, "Perspective Projection", "", "", ""); double defaultScaleFactor = preferences->defaultScaleFactorZ; CAF_PDM_InitField(&scaleZ, "GridZScale", defaultScaleFactor, "Z Scale", "", "Scales the scene in the Z direction", ""); @@ -491,6 +493,10 @@ void RimView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QV RiuMainWindow::instance()->refreshDrawStyleActions(); RiuMainWindow::instance()->refreshAnimationActions(); } + else if (changedField == &isPerspectiveView) + { + if (m_viewer) m_viewer->enableParallelProjection(!isPerspectiveView()); + } else if (changedField == &scaleZ) { if (scaleZ < 1) scaleZ = 1; diff --git a/ApplicationCode/ProjectDataModel/RimView.h b/ApplicationCode/ProjectDataModel/RimView.h index e4958d2e0c..29e2ab952f 100644 --- a/ApplicationCode/ProjectDataModel/RimView.h +++ b/ApplicationCode/ProjectDataModel/RimView.h @@ -76,6 +76,7 @@ class RimView : public caf::PdmObject caf::PdmField showWindow; caf::PdmField cameraPosition; + caf::PdmField isPerspectiveView; caf::PdmField< cvf::Color3f > backgroundColor; caf::PdmField maximumFrameRate; diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index 09c5e60418..3a2b3fba7f 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -169,6 +169,8 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); + + m_viewer->updateParallelProjectionHeight(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp index 84faebc730..0f4020bda0 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp @@ -245,6 +245,8 @@ void RiuGeoQuestNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); + m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->navigationPolicyUpdate(); } } diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp index 70afb005b4..07f57f91bf 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp @@ -269,6 +269,8 @@ void RiuRmsNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); + m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->navigationPolicyUpdate(); } } diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index 92d557eb55..7dcb1b477e 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -172,6 +172,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); + m_viewer->updateParallelProjectionHeight(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } diff --git a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp index a45b58d460..23c856a26f 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp @@ -196,18 +196,13 @@ void caf::CeetronNavigation::wheelEvent(QWheelEvent* event) int posY = m_viewer->height() - event->y(); - if (m_viewer->mainCamera()->projection() == cvf::Camera::PERSPECTIVE) - { - m_trackball->startNavigation(ManipulatorTrackball::WALK, event->x(), posY); - } - else - { - m_trackball->startNavigation(ManipulatorTrackball::ZOOM, event->x(), posY); - } + m_trackball->startNavigation(ManipulatorTrackball::WALK, event->x(), posY); m_trackball->updateNavigation(event->x(), posY + navDelta); m_trackball->endNavigation(); + m_viewer->updateParallelProjectionHeight( m_pointOfInterest); + m_viewer->navigationPolicyUpdate(); event->accept(); @@ -229,14 +224,7 @@ ManipulatorTrackball::NavigationType caf::CeetronNavigation::getNavigationTypeFr } else if (mouseButtons == Qt::MidButton || mouseButtons == (Qt::LeftButton | Qt::RightButton)) { - if (m_viewer->mainCamera()->projection() == cvf::Camera::PERSPECTIVE) - { - return ManipulatorTrackball::WALK; - } - else - { - return ManipulatorTrackball::ZOOM; - } + return ManipulatorTrackball::WALK; } else { diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index e0aa92e12d..c51d45a73a 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -257,6 +257,7 @@ void caf::CeetronPlusNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); + m_viewer->updateParallelProjectionHeight(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 55d006f707..978ac7d6fb 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -80,6 +80,7 @@ caf::Viewer::Viewer(const QGLFormat& format, QWidget* parent) m_navigationPolicy(NULL), m_minNearPlaneDistance(0.05), m_maxFarPlaneDistance(cvf::UNDEFINED_DOUBLE), + m_cameraFieldOfViewYDeg(40.0), m_releaseOGLResourcesEachFrame(false), m_paintCounter(0), m_navigationPolicyEnabled(true), @@ -233,15 +234,11 @@ void caf::Viewer::updateCamera(int width, int height) if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) { - m_mainCamera->setProjectionAsPerspective(40, m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + m_mainCamera->setProjectionAsPerspective(m_cameraFieldOfViewYDeg, m_mainCamera->nearPlane(), m_mainCamera->farPlane()); } else { - cvf::BoundingBox bb = m_renderingSequence->boundingBox(); - if (bb.isValid()) - { - m_mainCamera->setProjectionAsOrtho(bb.extent().length(), m_mainCamera->nearPlane(), m_mainCamera->farPlane()); - } + m_mainCamera->setProjectionAsOrtho(m_mainCamera->frontPlaneFrustumHeight(), m_mainCamera->nearPlane(), m_mainCamera->farPlane()); } } @@ -266,32 +263,36 @@ bool caf::Viewer::canRender() const //-------------------------------------------------------------------------------------------------- void caf::Viewer::optimizeClippingPlanes() { - if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) - { - cvf::BoundingBox bb = m_renderingSequence->boundingBox(); - if (!bb.isValid()) return; + cvf::BoundingBox bb = m_renderingSequence->boundingBox(); + if (!bb.isValid()) return; - cvf::Vec3d eye, vrp, up; - m_mainCamera->toLookAt(&eye, &vrp, &up); + cvf::Vec3d eye, vrp, up; + m_mainCamera->toLookAt(&eye, &vrp, &up); - cvf::Vec3d viewdir = (vrp - eye).getNormalized(); + cvf::Vec3d viewdir = (vrp - eye).getNormalized(); - double distEyeBoxCenterAlongViewDir = (bb.center() - eye)*viewdir; + double distEyeBoxCenterAlongViewDir = (bb.center() - eye)*viewdir; - double farPlaneDist = distEyeBoxCenterAlongViewDir + bb.radius() * 1.2; - farPlaneDist = CVF_MIN(farPlaneDist, m_maxFarPlaneDistance); + double farPlaneDist = distEyeBoxCenterAlongViewDir + bb.radius() * 1.2; + farPlaneDist = CVF_MIN(farPlaneDist, m_maxFarPlaneDistance); - double nearPlaneDist = distEyeBoxCenterAlongViewDir - bb.radius(); - if (nearPlaneDist < m_minNearPlaneDistance) nearPlaneDist = m_minNearPlaneDistance; - if ( m_navigationPolicy.notNull()) - { - double pointOfInterestDist = (eye - m_navigationPolicy->pointOfInterest()).length(); - nearPlaneDist = CVF_MIN( nearPlaneDist, pointOfInterestDist*0.2); - } + double nearPlaneDist = distEyeBoxCenterAlongViewDir - bb.radius(); + if (nearPlaneDist < m_minNearPlaneDistance) nearPlaneDist = m_minNearPlaneDistance; + if (m_navigationPolicy.notNull() && m_navigationPolicyEnabled) + { + double pointOfInterestDist = (eye - m_navigationPolicy->pointOfInterest()).length(); + nearPlaneDist = CVF_MIN(nearPlaneDist, pointOfInterestDist*0.2); + } - if (farPlaneDist <= nearPlaneDist) farPlaneDist = nearPlaneDist + 1.0; + if (farPlaneDist <= nearPlaneDist) farPlaneDist = nearPlaneDist + 1.0; - m_mainCamera->setProjectionAsPerspective(m_mainCamera->fieldOfViewYDeg(), nearPlaneDist, farPlaneDist); + if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) + { + m_mainCamera->setProjectionAsPerspective(m_cameraFieldOfViewYDeg, nearPlaneDist, farPlaneDist); + } + else + { + m_mainCamera->setProjectionAsOrtho(m_mainCamera->frontPlaneFrustumHeight(), nearPlaneDist, farPlaneDist); } } @@ -514,7 +515,7 @@ void caf::Viewer::setMaxFarPlaneDistance(double dist) //-------------------------------------------------------------------------------------------------- void caf::Viewer::setView(const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection) { - if (m_navigationPolicy.notNull()) + if (m_navigationPolicy.notNull() && m_navigationPolicyEnabled) { m_navigationPolicy->setView(alongDirection, upDirection); @@ -921,3 +922,80 @@ cvf::OverlayItem* caf::Viewer::overlayItem(int winPosX, int winPosY) return m_mainRendering->overlayItemFromWindowCoordinates(translatedMousePosX, translatedMousePosY); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::enableParallelProjection(bool enableOrtho) +{ + if (enableOrtho && m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) + { + cvf::Vec3d pointOfInterest; + + if (m_navigationPolicy.isNull() || !m_navigationPolicyEnabled) + { + using namespace cvf; + + Vec3d eye, vrp, up; + m_mainCamera->toLookAt(&eye, &vrp, &up); + + Vec3d eyeToFocus = pointOfInterest - eye; + Vec3d camDir = vrp - eye; + camDir.normalize(); + + double distToFocusPlane = 0.5*(m_mainCamera->farPlane() - m_mainCamera->nearPlane()); + pointOfInterest = camDir *distToFocusPlane; + } + else + { + pointOfInterest = m_navigationPolicy->pointOfInterest(); + } + m_mainCamera->setProjectionAsOrtho(1.0, m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + this->updateParallelProjectionHeight(pointOfInterest); + + this->update(); + } + else if (!enableOrtho && m_mainCamera->projection() == cvf::Camera::ORTHO) + { + // We currently expect all the navigation policies to do walk-based navigation and not fiddle with the field of view + // so we do not need to update the camera position based on orthoHeight and fieldOfView. + // We assume the camera is in a sensible position. + + m_mainCamera->setProjectionAsPerspective(m_cameraFieldOfViewYDeg, m_mainCamera->nearPlane(), m_mainCamera->farPlane()); + this->update(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +double calculateOrthoHeight(double perspectiveViewAngleYDeg, double focusPlaneDist) +{ + return 2 * (cvf::Math::tan( cvf::Math::toRadians(0.5 * perspectiveViewAngleYDeg) ) * focusPlaneDist); +} + +//-------------------------------------------------------------------------------------------------- +/// Update the ortho projection view height from a walk based camera manipulation. +/// Using pointOfInterest, the perspective Y-field Of View along with the camera position +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::updateParallelProjectionHeight(const cvf::Vec3d& pointOfInterest) +{ + using namespace cvf; + cvf::Camera* camera = m_mainCamera.p(); + + if (!camera || camera->projection() != Camera::ORTHO) return; + + Vec3d eye, vrp, up; + camera->toLookAt(&eye, &vrp, &up); + + Vec3d eyeToFocus = pointOfInterest - eye; + Vec3d camDir = vrp - eye; + camDir.normalize(); + + double distToFocusPlane = eyeToFocus*camDir; + + double orthoHeight = calculateOrthoHeight(m_cameraFieldOfViewYDeg, distToFocusPlane); + + camera->setProjectionAsOrtho(orthoHeight, camera->nearPlane(), camera->farPlane()); +} diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 475d8ca5cd..ad53143a53 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -116,6 +116,9 @@ class Viewer : public caf::OpenGLWidget void enableNavigationPolicy(bool enable); void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); void zoomAll(); + void enableParallelProjection(bool enable); + void updateParallelProjectionHeight(const cvf::Vec3d& pointOfInterest); + virtual void navigationPolicyUpdate(); void setMinNearPlaneDistance(double dist); void setMaxFarPlaneDistance(double dist); @@ -140,7 +143,6 @@ class Viewer : public caf::OpenGLWidget // Find out whether the system supports shaders static bool isShadersSupported(); - virtual void navigationPolicyUpdate(); public slots: virtual void slotSetCurrentFrame(int frameIndex); @@ -174,6 +176,7 @@ public slots: double m_minNearPlaneDistance; double m_maxFarPlaneDistance; + double m_cameraFieldOfViewYDeg; private: void setupMainRendering(); From afe84ce75e1424606df2aae696d49787fbfc2431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 7 Dec 2015 15:54:44 +0100 Subject: [PATCH 243/290] (#168) Parallel walk navigation working. Still things to fix --- .../UserInterface/RiuCadNavigation.cpp | 20 ++++-- .../UserInterface/RiuGeoQuestNavigation.cpp | 20 ++++-- .../UserInterface/RiuRmsNavigation.cpp | 20 ++++-- Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 19 +++-- Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp | 19 ++--- .../cafViewer/cafCeetronPlusNavigation.cpp | 20 ++++-- Fwk/AppFwk/cafViewer/cafViewer.cpp | 71 +++++++++++++++++-- Fwk/AppFwk/cafViewer/cafViewer.h | 7 +- 8 files changed, 145 insertions(+), 51 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index 3a2b3fba7f..d86f641970 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -81,8 +81,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) if (hitSomething) { cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - m_trackball->setRotationPoint(pointOfInterest); - m_pointOfInterest = pointOfInterest; + this->setPointOfInterest(pointOfInterest); } else { @@ -170,7 +169,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); - m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } @@ -188,11 +187,16 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) //-------------------------------------------------------------------------------------------------- void RiuCadNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene() || !m_viewer->currentScene()->boundingBox().isValid()) return; - m_pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -237,4 +241,6 @@ void RiuCadNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + } diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp index 0f4020bda0..3d5977a987 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp @@ -69,8 +69,7 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) if (hitSomething) { cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - m_trackball->setRotationPoint(pointOfInterest); - m_pointOfInterest = pointOfInterest; + this->setPointOfInterest(pointOfInterest); } else { @@ -178,11 +177,16 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) //-------------------------------------------------------------------------------------------------- void RiuGeoQuestNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene() || !m_viewer->currentScene()->boundingBox().isValid()) return; - m_pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -227,6 +231,8 @@ void RiuGeoQuestNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + } //-------------------------------------------------------------------------------------------------- @@ -245,7 +251,7 @@ void RiuGeoQuestNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp index 07f57f91bf..e8b5be8694 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp @@ -69,8 +69,7 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) if (hitSomething) { cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - m_trackball->setRotationPoint(pointOfInterest); - m_pointOfInterest = pointOfInterest; + this->setPointOfInterest(pointOfInterest); } else { @@ -202,11 +201,16 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) //-------------------------------------------------------------------------------------------------- void RiuRmsNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene() || !m_viewer->currentScene()->boundingBox().isValid()) return; - m_pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -251,6 +255,8 @@ void RiuRmsNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + } //-------------------------------------------------------------------------------------------------- @@ -269,7 +275,7 @@ void RiuRmsNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index 7dcb1b477e..d9ad91dee4 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -92,8 +92,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) if (hitSomething) { cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - m_trackball->setRotationPoint(pointOfInterest); - m_pointOfInterest = pointOfInterest; + this->setPointOfInterest(pointOfInterest); } else { @@ -172,7 +171,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); - m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } @@ -190,11 +189,16 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) //-------------------------------------------------------------------------------------------------- void caf::CadNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene() || !m_viewer->currentScene()->boundingBox().isValid()) return; - m_pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -239,4 +243,5 @@ void caf::CadNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); } diff --git a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp index 23c856a26f..6796cdd391 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp @@ -201,7 +201,7 @@ void caf::CeetronNavigation::wheelEvent(QWheelEvent* event) m_trackball->updateNavigation(event->x(), posY + navDelta); m_trackball->endNavigation(); - m_viewer->updateParallelProjectionHeight( m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom( m_pointOfInterest); m_viewer->navigationPolicyUpdate(); @@ -263,15 +263,16 @@ void caf::CeetronNavigation::setCursorFromCurrentState() //-------------------------------------------------------------------------------------------------- void caf::CeetronNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene()) return; - - cvf::BoundingBox bb = m_viewer->mainScene()->boundingBox(); - if(bb.isValid()) + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) { - m_pointOfInterest = bb.center(); - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + return; } + + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -291,6 +292,8 @@ void caf::CeetronNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + } diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index c51d45a73a..24f978050c 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -57,8 +57,7 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) if (hitSomething) { cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - m_trackball->setRotationPoint(pointOfInterest); - m_pointOfInterest = pointOfInterest; + this->setPointOfInterest(pointOfInterest); } else { @@ -190,11 +189,16 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) //-------------------------------------------------------------------------------------------------- void caf::CeetronPlusNavigation::initializeRotationCenter() { - if(m_isRotCenterInitialized || m_trackball.isNull() || !m_viewer->mainScene() || !m_viewer->currentScene()->boundingBox().isValid()) return; - m_pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } - m_trackball->setRotationPoint(m_pointOfInterest); - m_isRotCenterInitialized = true; + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); } //-------------------------------------------------------------------------------------------------- @@ -239,6 +243,8 @@ void caf::CeetronPlusNavigation::setPointOfInterest(cvf::Vec3d poi) m_pointOfInterest = poi; m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + } //-------------------------------------------------------------------------------------------------- @@ -257,7 +263,7 @@ void caf::CeetronPlusNavigation::zoomAlongRay(cvf::Ray* ray, int delta) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeight(m_pointOfInterest); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } } diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 978ac7d6fb..788fac3e38 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -68,6 +68,7 @@ #include #include #include +#include "cvfTrace.h" std::list caf::Viewer::sm_viewers; cvf::ref caf::Viewer::sm_openGLContextGroup; @@ -951,7 +952,7 @@ void caf::Viewer::enableParallelProjection(bool enableOrtho) pointOfInterest = m_navigationPolicy->pointOfInterest(); } m_mainCamera->setProjectionAsOrtho(1.0, m_mainCamera->nearPlane(), m_mainCamera->farPlane()); - this->updateParallelProjectionHeight(pointOfInterest); + this->updateParallelProjectionHeightFromMoveZoom(pointOfInterest); this->update(); } @@ -974,28 +975,84 @@ double calculateOrthoHeight(double perspectiveViewAngleYDeg, double focusPlaneDi { return 2 * (cvf::Math::tan( cvf::Math::toRadians(0.5 * perspectiveViewAngleYDeg) ) * focusPlaneDist); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +double calculateDistToPlaneOfInterest(double perspectiveViewAngleYDeg, double orthoHeight) +{ + return orthoHeight / (2 * (cvf::Math::tan( cvf::Math::toRadians(0.5 * perspectiveViewAngleYDeg) ))); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +double distToPlaneOfInterest(const cvf::Camera* camera, const cvf::Vec3d& pointOfInterest) +{ + using namespace cvf; + CVF_ASSERT(camera); + + Vec3d eye, vrp, up; + camera->toLookAt(&eye, &vrp, &up); + + Vec3d camDir = vrp - eye; + camDir.normalize(); + + Vec3d eyeToFocus = pointOfInterest - eye; + double distToFocusPlane = eyeToFocus*camDir; + + return distToFocusPlane; +} //-------------------------------------------------------------------------------------------------- /// Update the ortho projection view height from a walk based camera manipulation. /// Using pointOfInterest, the perspective Y-field Of View along with the camera position //-------------------------------------------------------------------------------------------------- -void caf::Viewer::updateParallelProjectionHeight(const cvf::Vec3d& pointOfInterest) +void caf::Viewer::updateParallelProjectionHeightFromMoveZoom(const cvf::Vec3d& pointOfInterest) { using namespace cvf; cvf::Camera* camera = m_mainCamera.p(); if (!camera || camera->projection() != Camera::ORTHO) return; + + double distToFocusPlane = distToPlaneOfInterest(camera, pointOfInterest); + + double orthoHeight = calculateOrthoHeight(m_cameraFieldOfViewYDeg, distToFocusPlane); + + camera->setProjectionAsOrtho(orthoHeight, camera->nearPlane(), camera->farPlane()); +} + +//-------------------------------------------------------------------------------------------------- +/// Update the camera eye position from point of interest, keeping the ortho height fixed and in sync +/// with distToPlaneOfInterest from a walk based camera manipulation in ortho projection. +//-------------------------------------------------------------------------------------------------- +void caf::Viewer::updateParallelProjectionCameraPosFromPointOfInterestMove(const cvf::Vec3d& pointOfInterest) +{ + using namespace cvf; + cvf::Camera* camera = m_mainCamera.p(); + + if (!camera || camera->projection() != Camera::ORTHO) return; + + + double orthoHeight = camera->frontPlaneFrustumHeight(); + Trace::show(String::number(orthoHeight)); + + double neededDistToFocusPlane = calculateDistToPlaneOfInterest(m_cameraFieldOfViewYDeg, orthoHeight); + Vec3d eye, vrp, up; camera->toLookAt(&eye, &vrp, &up); - - Vec3d eyeToFocus = pointOfInterest - eye; Vec3d camDir = vrp - eye; camDir.normalize(); - double distToFocusPlane = eyeToFocus*camDir; + double existingDistToFocusPlane = distToPlaneOfInterest(camera, pointOfInterest); - double orthoHeight = calculateOrthoHeight(m_cameraFieldOfViewYDeg, distToFocusPlane); + Vec3d newEye = eye + (existingDistToFocusPlane - neededDistToFocusPlane) * camDir; + + Trace::show(String::number(newEye.x()) + ", " + String::number(newEye.y()) + ", " +String::number(newEye.z())); + camera->setFromLookAt(newEye, newEye + 10.0*camDir, up); - camera->setProjectionAsOrtho(orthoHeight, camera->nearPlane(), camera->farPlane()); } + diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index ad53143a53..8681294b52 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -117,9 +117,14 @@ class Viewer : public caf::OpenGLWidget void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); void zoomAll(); void enableParallelProjection(bool enable); - void updateParallelProjectionHeight(const cvf::Vec3d& pointOfInterest); + + // Interface for navigation policies + void updateParallelProjectionHeightFromMoveZoom(const cvf::Vec3d& pointOfInterest); + void updateParallelProjectionCameraPosFromPointOfInterestMove(const cvf::Vec3d& pointOfInterest); + virtual void navigationPolicyUpdate(); + // Min max near far plane. void setMinNearPlaneDistance(double dist); void setMaxFarPlaneDistance(double dist); From 8f92dfd0c0e9fdb69478f430a117c6ec71540ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 9 Dec 2015 15:17:04 +0100 Subject: [PATCH 244/290] Caf: WIP: Created a base class with trackball related navigation stuff. Refactored cad and ceetron plus nav to use the common base --- Fwk/AppFwk/cafViewer/CMakeLists.txt | 2 + Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 95 ++---- Fwk/AppFwk/cafViewer/cafCadNavigation.h | 23 +- .../cafViewer/cafCeetronPlusNavigation.cpp | 142 ++------ .../cafViewer/cafCeetronPlusNavigation.h | 71 ++-- .../cafViewer/cafTrackBallBasedNavigation.cpp | 302 ++++++++++++++++++ .../cafViewer/cafTrackBallBasedNavigation.h | 78 +++++ Fwk/AppFwk/cafViewer/cafViewer.cpp | 1 + 8 files changed, 475 insertions(+), 239 deletions(-) create mode 100644 Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp create mode 100644 Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h diff --git a/Fwk/AppFwk/cafViewer/CMakeLists.txt b/Fwk/AppFwk/cafViewer/CMakeLists.txt index 09960ee2ee..b0402fd991 100644 --- a/Fwk/AppFwk/cafViewer/CMakeLists.txt +++ b/Fwk/AppFwk/cafViewer/CMakeLists.txt @@ -33,6 +33,8 @@ add_library( ${PROJECT_NAME} cafCeetronNavigation.h cafCeetronPlusNavigation.cpp cafCeetronPlusNavigation.h + cafTrackBallBasedNavigation.cpp + cafTrackBallBasedNavigation.h cafNavigationPolicy.cpp cafNavigationPolicy.h cafOpenGLWidget.cpp diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index d9ad91dee4..7acd9d01da 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -38,26 +38,20 @@ #include "cafCadNavigation.h" #include "cafViewer.h" #include "cvfCamera.h" -#include "cvfScene.h" -#include "cvfModel.h" #include "cvfViewport.h" #include "cvfHitItemCollection.h" #include "cvfRay.h" +#include "cvfManipulatorTrackball.h" #include -#include - -using cvf::ManipulatorTrackball; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void caf::CadNavigation::init() { - m_trackball = new cvf::ManipulatorTrackball; - m_trackball->setCamera(m_viewer->mainCamera()); - m_isRotCenterInitialized = false; - m_isRotating = false; + caf::TrackBallBasedNavigation::init(); + m_navigationUpdated = false; } //-------------------------------------------------------------------------------------------------- @@ -81,7 +75,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) if (me->modifiers() & Qt::ShiftModifier) { m_trackball->startNavigation(cvf::ManipulatorTrackball::PAN, translatedMousePosX, translatedMousePosY); - m_isRotating = true; + m_isNavigating = true; isEventHandled = true; } else if (me->modifiers() == Qt::NoModifier) @@ -101,23 +95,30 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) m_trackball->startNavigation(cvf::ManipulatorTrackball::ROTATE, translatedMousePosX, translatedMousePosY); //m_viewer->setCursor(RiuCursors::get(RiuCursors::ROTATE)); - m_isRotating = true; + m_isNavigating = true; isEventHandled = true; } } + + if (isEventHandled) + { + m_navigationUpdated = false; + } } break; case QEvent::MouseButtonRelease: { - if (m_isRotating) + if (m_isNavigating) { QMouseEvent * me = static_cast( inputEvent); if (me->button() == Qt::MidButton) { m_trackball->endNavigation(); //m_viewer->setCursor(RiuCursors::get(RiuCursors::PICK)); - m_isRotating = false; - isEventHandled = true; + m_isNavigating = false; + + isEventHandled = m_navigationUpdated; + m_navigationUpdated = false; } } } @@ -131,12 +132,13 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) int translatedMousePosX = me->x(); int translatedMousePosY = m_viewer->height() - me->y(); - if (m_isRotating) + if (m_isNavigating) { bool needRedraw = m_trackball->updateNavigation(translatedMousePosX, translatedMousePosY); if (needRedraw) { m_viewer->navigationPolicyUpdate(); + m_navigationUpdated = true; } isEventHandled = true; } @@ -171,6 +173,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) cvf::Vec3d newVrp = vrp + trans; m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); m_viewer->navigationPolicyUpdate(); } @@ -183,65 +186,3 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) return isEventHandled; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CadNavigation::initializeRotationCenter() -{ - if (m_isRotCenterInitialized - || m_trackball.isNull() - || !m_viewer->currentScene()->boundingBox().isValid()) - { - return; - } - - cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); - - this->setPointOfInterest(pointOfInterest); -} - -//-------------------------------------------------------------------------------------------------- -/// Repositions and orients the camera to view the rotation point along the -/// direction "alongDirection". The distance to the rotation point is maintained. -/// -//-------------------------------------------------------------------------------------------------- -void caf::CadNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) -{ - m_trackball->setView(alongDirection, upDirection); - /* - if (m_camera.isNull()) return; - - Vec3d dir = alongDirection; - if (!dir.normalize()) return; - Vec3d up = upDirection; - if(!up.normalize()) up = Vec3d::Z_AXIS; - - if((up * dir) < 1e-2) up = dir.perpendicularVector(); - - Vec3d cToE = m_camera->position() - m_rotationPoint; - Vec3d newEye = m_rotationPoint - cToE.length() * dir; - - m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); - */ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3d caf::CadNavigation::pointOfInterest() -{ - initializeRotationCenter(); - return m_pointOfInterest; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CadNavigation::setPointOfInterest(cvf::Vec3d poi) -{ - m_pointOfInterest = poi; - m_trackball->setRotationPoint(poi); - m_isRotCenterInitialized = true; - m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); -} diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.h b/Fwk/AppFwk/cafViewer/cafCadNavigation.h index 9cbae679be..8285dfec87 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.h @@ -37,31 +37,18 @@ #pragma once -#include "cafNavigationPolicy.h" -#include "cvfManipulatorTrackball.h" +#include "cafTrackBallBasedNavigation.h" namespace caf { -class CadNavigation : public NavigationPolicy +class CadNavigation : public TrackBallBasedNavigation { protected: - // General navigation policy reimplememtation - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); + virtual void init(); + virtual bool handleInputEvent(QInputEvent* inputEvent); - - // Cad navigation specific - void initializeRotationCenter(); - - cvf::ref - m_trackball; - bool m_isRotCenterInitialized; - bool m_isRotating; - cvf::Vec3d m_pointOfInterest; + bool m_navigationUpdated; }; } // End namespace caf diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index 24f978050c..700b473c8b 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -1,38 +1,48 @@ //################################################################################################## // -// Copyright (C) 2011, Ceetron AS -// This is UNPUBLISHED PROPRIETARY SOURCE CODE of Ceetron AS. The contents of this file may -// not be disclosed to third parties, copied or duplicated in any form, in whole or in part, -// without the prior written permission of Ceetron AS. +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// //################################################################################################## + #include "cafCeetronPlusNavigation.h" #include "cafViewer.h" #include "cvfCamera.h" -#include "cvfScene.h" -#include "cvfModel.h" #include "cvfViewport.h" #include "cvfHitItemCollection.h" #include "cvfRay.h" +#include "cvfManipulatorTrackball.h" #include -#include - -using cvf::ManipulatorTrackball; - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CeetronPlusNavigation::init() -{ - m_trackball = new cvf::ManipulatorTrackball; - m_trackball->setCamera(m_viewer->mainCamera()); - m_isRotCenterInitialized = false; - m_hasMovedMouseDuringNavigation = false; - m_isNavigating = false; - m_isZooming = false; - m_lastPosX = 0; - m_lastPosY = 0; -} //-------------------------------------------------------------------------------------------------- /// @@ -183,87 +193,3 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) return false;//isEventHandled; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CeetronPlusNavigation::initializeRotationCenter() -{ - if (m_isRotCenterInitialized - || m_trackball.isNull() - || !m_viewer->currentScene()->boundingBox().isValid()) - { - return; - } - - cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); - - this->setPointOfInterest(pointOfInterest); -} - -//-------------------------------------------------------------------------------------------------- -/// Repositions and orients the camera to view the rotation point along the -/// direction "alongDirection". The distance to the rotation point is maintained. -/// -//-------------------------------------------------------------------------------------------------- -void caf::CeetronPlusNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) -{ - m_trackball->setView(alongDirection, upDirection); - /* - if (m_camera.isNull()) return; - - Vec3d dir = alongDirection; - if (!dir.normalize()) return; - Vec3d up = upDirection; - if(!up.normalize()) up = Vec3d::Z_AXIS; - - if((up * dir) < 1e-2) up = dir.perpendicularVector(); - - Vec3d cToE = m_camera->position() - m_rotationPoint; - Vec3d newEye = m_rotationPoint - cToE.length() * dir; - - m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); - */ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3d caf::CeetronPlusNavigation::pointOfInterest() -{ - initializeRotationCenter(); - return m_pointOfInterest; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CeetronPlusNavigation::setPointOfInterest(cvf::Vec3d poi) -{ - m_pointOfInterest = poi; - m_trackball->setRotationPoint(poi); - m_isRotCenterInitialized = true; - m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void caf::CeetronPlusNavigation::zoomAlongRay(cvf::Ray* ray, int delta) -{ - if (ray && abs(delta) > 0) - { - cvf::Vec3d pos, vrp, up; - m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); - - double scale = delta/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); - cvf::Vec3d trans = scale * ray->direction(); - cvf::Vec3d newPos = pos + trans; - cvf::Vec3d newVrp = vrp + trans; - - m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); - m_viewer->navigationPolicyUpdate(); - } -} diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h index caed0c66c6..62d077a134 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h @@ -1,50 +1,49 @@ //################################################################################################## // -// Copyright (C) 2011, Ceetron AS -// This is UNPUBLISHED PROPRIETARY SOURCE CODE of Ceetron AS. The contents of this file may -// not be disclosed to third parties, copied or duplicated in any form, in whole or in part, -// without the prior written permission of Ceetron AS. +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// //################################################################################################## - #pragma once -#include "cvfBase.h" -#include "cafNavigationPolicy.h" -#include "cvfManipulatorTrackball.h" -#include "cvfRay.h" - - +#include "cafTrackBallBasedNavigation.h" namespace caf { -class CeetronPlusNavigation : public NavigationPolicy +class CeetronPlusNavigation : public TrackBallBasedNavigation { protected: - // General navigation policy overrides - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); - - // PdvNavigation specific - void initializeRotationCenter(); - cvf::ref m_trackball; - bool m_isRotCenterInitialized; - cvf::Vec3d m_pointOfInterest; - - bool m_isNavigating; - bool m_hasMovedMouseDuringNavigation; - - // Handle mid mouse button zoom - void zoomAlongRay( cvf::Ray* ray, int delta ); - bool m_isZooming; - cvf::ref m_zoomRay; - int m_lastPosX; /// Previous mouse position - int m_lastPosY; - + virtual bool handleInputEvent(QInputEvent* inputEvent); }; } // End namespace caf diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp new file mode 100644 index 0000000000..d23f92ee95 --- /dev/null +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp @@ -0,0 +1,302 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2015 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## + +#include "cafTrackBallBasedNavigation.h" + +#include "cafViewer.h" +#include "cvfCamera.h" +#include "cvfScene.h" +#include "cvfModel.h" +#include "cvfViewport.h" +#include "cvfHitItemCollection.h" +#include "cvfRay.h" +#include "cvfManipulatorTrackball.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::init() +{ + m_trackball = new cvf::ManipulatorTrackball; + m_trackball->setCamera(m_viewer->mainCamera()); + m_isRotCenterInitialized = false; + m_hasMovedMouseDuringNavigation = false; + m_isNavigating = false; + m_isZooming = false; + m_lastPosX = 0; + m_lastPosY = 0; +} + +#if 0 +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool caf::TrackBallBasedNavigation::handleInputEvent(QInputEvent* inputEvent) +{ + if (! inputEvent) return false; + bool isEventHandled = false; + switch (inputEvent->type()) + { + case QEvent::MouseButtonPress: + { + QMouseEvent * me = static_cast( inputEvent); + int translatedMousePosX = me->x(); + int translatedMousePosY = m_viewer->height() - me->y(); + + if (me->button() == Qt::RightButton) + { + cvf::HitItemCollection hic; + bool hitSomething = m_viewer->rayPick(me->x(), me->y(), &hic); + + if (hitSomething) + { + cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); + this->setPointOfInterest(pointOfInterest); + } + else + { + initializeRotationCenter(); + } + + m_trackball->startNavigation(cvf::ManipulatorTrackball::ROTATE, translatedMousePosX, translatedMousePosY); + //m_viewer->setCursor(RICursors::get(RICursors::ROTATE)); + m_isNavigating = true; + m_hasMovedMouseDuringNavigation = false; + isEventHandled = true; + } + else if (me->button() == Qt::LeftButton) + { + if (me->modifiers() == Qt::NoModifier) + { + m_trackball->startNavigation(cvf::ManipulatorTrackball::PAN, translatedMousePosX, translatedMousePosY); + m_isNavigating = true; + m_hasMovedMouseDuringNavigation = false; + isEventHandled = true; + } + } + else if (me->button() == Qt::MidButton) + { + if (me->modifiers() == Qt::NoModifier) + { + QMouseEvent* we = static_cast ( inputEvent); + m_lastPosX = we->x(); + m_lastPosY = we->y(); + + m_zoomRay = m_viewer->mainCamera()->rayFromWindowCoordinates(translatedMousePosX, translatedMousePosY); + + m_isNavigating = true; + m_hasMovedMouseDuringNavigation = false; + isEventHandled = true; + m_isZooming = true; + } + } + } + break; + case QEvent::MouseButtonRelease: + { + if (m_isNavigating) + { + QMouseEvent * me = static_cast( inputEvent); + if (me->button() == Qt::RightButton || me->button() == Qt::LeftButton ) + { + m_trackball->endNavigation(); + + m_isNavigating = false; + if (m_hasMovedMouseDuringNavigation) isEventHandled = true; + m_hasMovedMouseDuringNavigation = false; + } + else if ( me->button() == Qt::MidButton ) + { + m_isZooming = false; + + m_isNavigating = false; + if (m_hasMovedMouseDuringNavigation) isEventHandled = true; + m_hasMovedMouseDuringNavigation = false; + } + } + } + break; + case QEvent::MouseMove: + { + initializeRotationCenter(); + if (m_isRotCenterInitialized) + { + QMouseEvent * me = static_cast( inputEvent); + int translatedMousePosX = me->x(); + int translatedMousePosY = m_viewer->height() - me->y(); + + if (m_isNavigating) + { + if (m_isZooming) + { + int delta = 3*(m_lastPosY - me->y()); + this->zoomAlongRay(m_zoomRay.p(), delta); + m_lastPosX = me->x(); + m_lastPosY = me->y(); + } + else + { + bool needRedraw = m_trackball->updateNavigation(translatedMousePosX, translatedMousePosY); + if (needRedraw) + { + m_viewer->navigationPolicyUpdate(); + } + } + isEventHandled = true; + m_hasMovedMouseDuringNavigation = true; + } + } + } + break; + case QEvent::Wheel: + { + if (inputEvent->modifiers() == Qt::NoModifier) + { + initializeRotationCenter(); + if (m_isRotCenterInitialized) + { + QWheelEvent* we = static_cast ( inputEvent); + int translatedMousePosX = we->x(); + int translatedMousePosY = m_viewer->height() - we->y(); + int delta = we->delta(); + + cvf::ref ray; + if (delta < 0) + ray = m_viewer->mainCamera()->rayFromWindowCoordinates(translatedMousePosX, translatedMousePosY); + else + ray = m_viewer->mainCamera()->rayFromWindowCoordinates((int)(1.0*translatedMousePosX), (int)(1.0*translatedMousePosY)); + + zoomAlongRay(ray.p(), delta); + + } + isEventHandled = true; + } + } + break; + } + + return false;//isEventHandled; +} + +#endif + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::initializeRotationCenter() +{ + if (m_isRotCenterInitialized + || m_trackball.isNull() + || !m_viewer->currentScene()->boundingBox().isValid()) + { + return; + } + + cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); + + this->setPointOfInterest(pointOfInterest); +} + +//-------------------------------------------------------------------------------------------------- +/// Repositions and orients the camera to view the rotation point along the +/// direction "alongDirection". The distance to the rotation point is maintained. +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) +{ + m_trackball->setView(alongDirection, upDirection); + /* + if (m_camera.isNull()) return; + + Vec3d dir = alongDirection; + if (!dir.normalize()) return; + Vec3d up = upDirection; + if(!up.normalize()) up = Vec3d::Z_AXIS; + + if((up * dir) < 1e-2) up = dir.perpendicularVector(); + + Vec3d cToE = m_camera->position() - m_rotationPoint; + Vec3d newEye = m_rotationPoint - cToE.length() * dir; + + m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); + */ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d caf::TrackBallBasedNavigation::pointOfInterest() +{ + initializeRotationCenter(); + return m_pointOfInterest; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::setPointOfInterest(cvf::Vec3d poi) +{ + m_pointOfInterest = poi; + m_trackball->setRotationPoint(poi); + m_isRotCenterInitialized = true; + m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::zoomAlongRay(cvf::Ray* ray, int delta) +{ + if (ray && abs(delta) > 0) + { + cvf::Vec3d pos, vrp, up; + m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); + + double scale = delta/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); + cvf::Vec3d trans = scale * ray->direction(); + cvf::Vec3d newPos = pos + trans; + cvf::Vec3d newVrp = vrp + trans; + + m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); + m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); + m_viewer->navigationPolicyUpdate(); + } +} + + diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h new file mode 100644 index 0000000000..c0cc22a570 --- /dev/null +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h @@ -0,0 +1,78 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2015 Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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. +// +// This library 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 <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library 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 Lesser General Public License at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include "cafNavigationPolicy.h" + +namespace cvf { + class ManipulatorTrackball; + class Ray; +} + +namespace caf +{ + +class TrackBallBasedNavigation: public NavigationPolicy +{ +protected: + // General navigation policy overrides + virtual void init(); + + virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); + virtual cvf::Vec3d pointOfInterest(); + virtual void setPointOfInterest(cvf::Vec3d poi); + + // Track ball navigation specific + void initializeRotationCenter(); + cvf::ref m_trackball; + bool m_isRotCenterInitialized; + cvf::Vec3d m_pointOfInterest; + + bool m_isNavigating; + bool m_hasMovedMouseDuringNavigation; + + // Zooming towards cursor + void zoomAlongRay( cvf::Ray* ray, int delta ); + bool m_isZooming; + cvf::ref m_zoomRay; + int m_lastPosX; /// Previous mouse position + int m_lastPosY; + +}; + +} // End namespace caf + + diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index 788fac3e38..c957fc0f02 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -56,6 +56,7 @@ #include "cvfTransform.h" #include "cvfRayIntersectSpec.h" #include "cvfHitItemCollection.h" +#include "cvfManipulatorTrackball.h" #include "cvfDebugTimer.h" #include "cvfqtPerformanceInfoHud.h" From f3eb304d66ad752bf85bd042fa75b3e58fc19acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 9 Dec 2015 15:49:55 +0100 Subject: [PATCH 245/290] Caf: Added constructors/destructors to navigation policies --- Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 15 ++++++++++++++ Fwk/AppFwk/cafViewer/cafCadNavigation.h | 3 +++ Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp | 16 +++++++++++++++ Fwk/AppFwk/cafViewer/cafCeetronNavigation.h | 3 +++ .../cafViewer/cafCeetronPlusNavigation.cpp | 17 ++++++++++++++++ .../cafViewer/cafCeetronPlusNavigation.h | 3 +++ Fwk/AppFwk/cafViewer/cafNavigationPolicy.cpp | 17 ++++++++++++++++ Fwk/AppFwk/cafViewer/cafNavigationPolicy.h | 4 ++++ .../cafViewer/cafTrackBallBasedNavigation.cpp | 20 +++++++++++++++++-- .../cafViewer/cafTrackBallBasedNavigation.h | 3 +++ 10 files changed, 99 insertions(+), 2 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index 7acd9d01da..3b10e34ab1 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -44,6 +44,21 @@ #include "cvfManipulatorTrackball.h" #include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CadNavigation::CadNavigation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CadNavigation::~CadNavigation() +{ + +} //-------------------------------------------------------------------------------------------------- /// diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.h b/Fwk/AppFwk/cafViewer/cafCadNavigation.h index 8285dfec87..fec86bc37c 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.h @@ -44,6 +44,9 @@ namespace caf class CadNavigation : public TrackBallBasedNavigation { +public: + CadNavigation(); + virtual ~CadNavigation(); protected: virtual void init(); virtual bool handleInputEvent(QInputEvent* inputEvent); diff --git a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp index 6796cdd391..8c0e152041 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.cpp @@ -57,6 +57,22 @@ using cvf::ManipulatorTrackball; /// //================================================================================================== +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CeetronNavigation::CeetronNavigation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CeetronNavigation::~CeetronNavigation() +{ + +} + //-------------------------------------------------------------------------------------------------- /// Repositions and orients the camera to view the rotation point along the /// direction "alongDirection". The distance to the rotation point is maintained. diff --git a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h index 5fbf9018bd..2eca8e0e20 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h @@ -48,6 +48,9 @@ namespace caf class CeetronNavigation : public NavigationPolicy { +public: + CeetronNavigation(); + virtual ~CeetronNavigation(); protected: // General navigation policy reimplememtation virtual void init(); diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index 700b473c8b..0ef728eef1 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -44,6 +44,23 @@ #include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CeetronPlusNavigation::CeetronPlusNavigation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::CeetronPlusNavigation::~CeetronPlusNavigation() +{ + +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h index 62d077a134..9e44dd6fd7 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h @@ -42,6 +42,9 @@ namespace caf class CeetronPlusNavigation : public TrackBallBasedNavigation { +public: + CeetronPlusNavigation(); + virtual ~CeetronPlusNavigation(); protected: virtual bool handleInputEvent(QInputEvent* inputEvent); }; diff --git a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.cpp b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.cpp index 996a13feac..b953a3d01a 100644 --- a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.cpp +++ b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.cpp @@ -39,6 +39,23 @@ #include "cafViewer.h" #include "cvfScene.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::NavigationPolicy::NavigationPolicy() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::NavigationPolicy::~NavigationPolicy() +{ + +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h index 79d699aa66..1b58c32119 100644 --- a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h +++ b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h @@ -55,6 +55,10 @@ namespace caf class NavigationPolicy : public cvf::Object { +public: + NavigationPolicy(); + virtual ~NavigationPolicy(); + friend class Viewer; public: // protected: // Should be protected but this friending does not work on gcc 4.1.2 diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp index d23f92ee95..61cef22bda 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp @@ -47,6 +47,24 @@ #include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::TrackBallBasedNavigation::TrackBallBasedNavigation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::TrackBallBasedNavigation::~TrackBallBasedNavigation() +{ + +} + + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -298,5 +316,3 @@ void caf::TrackBallBasedNavigation::zoomAlongRay(cvf::Ray* ray, int delta) m_viewer->navigationPolicyUpdate(); } } - - diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h index c0cc22a570..d4766276c7 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h @@ -47,6 +47,9 @@ namespace caf class TrackBallBasedNavigation: public NavigationPolicy { +public: + TrackBallBasedNavigation(); + virtual ~TrackBallBasedNavigation(); protected: // General navigation policy overrides virtual void init(); From 5874df7cc98383edd5fa0dba09f7b1bd65c83758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Wed, 9 Dec 2015 15:51:38 +0100 Subject: [PATCH 246/290] (#168) (#695) Wip: Refactoring the ResInsight nav policies to make bugfixing simpler --- .../UserInterface/RiuCadNavigation.cpp | 99 ++++------------ .../UserInterface/RiuCadNavigation.h | 29 ++--- .../UserInterface/RiuGeoQuestNavigation.cpp | 108 ++---------------- .../UserInterface/RiuGeoQuestNavigation.h | 35 +----- .../UserInterface/RiuRmsNavigation.cpp | 107 ++--------------- .../UserInterface/RiuRmsNavigation.h | 35 +----- 6 files changed, 63 insertions(+), 350 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index d86f641970..a02fe70131 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -20,26 +20,35 @@ #include "RiuCadNavigation.h" #include "cafViewer.h" #include "cvfCamera.h" -#include "cvfScene.h" -#include "cvfModel.h" #include "cvfViewport.h" #include "cvfHitItemCollection.h" #include "cvfRay.h" +#include "cvfManipulatorTrackball.h" #include -#include -using cvf::ManipulatorTrackball; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCadNavigation::RiuCadNavigation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCadNavigation::~RiuCadNavigation() +{ + +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuCadNavigation::init() { - m_trackball = new cvf::ManipulatorTrackball; - m_trackball->setCamera(m_viewer->mainCamera()); - m_isRotCenterInitialized = false; - m_isRotating = false; + caf::TrackBallBasedNavigation::init(); m_navigationUpdated = false; } @@ -62,7 +71,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) if (me->button() == Qt::LeftButton) { m_trackball->startNavigation(cvf::ManipulatorTrackball::PAN, translatedMousePosX, translatedMousePosY); - m_isRotating = true; + m_isNavigating = true; isEventHandled = true; } else if (me->button() == Qt::MidButton) @@ -70,7 +79,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) if (me->modifiers() & Qt::ShiftModifier) { m_trackball->startNavigation(cvf::ManipulatorTrackball::PAN, translatedMousePosX, translatedMousePosY); - m_isRotating = true; + m_isNavigating = true; isEventHandled = true; } else if (me->modifiers() == Qt::NoModifier) @@ -90,7 +99,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) m_trackball->startNavigation(cvf::ManipulatorTrackball::ROTATE, translatedMousePosX, translatedMousePosY); //m_viewer->setCursor(RiuCursors::get(RiuCursors::ROTATE)); - m_isRotating = true; + m_isNavigating = true; isEventHandled = true; } } @@ -103,14 +112,14 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) break; case QEvent::MouseButtonRelease: { - if (m_isRotating) + if (m_isNavigating) { QMouseEvent * me = static_cast( inputEvent); if (me->button() == Qt::MidButton || me->button() == Qt::LeftButton) { m_trackball->endNavigation(); //m_viewer->setCursor(RiuCursors::get(RiuCursors::PICK)); - m_isRotating = false; + m_isNavigating = false; isEventHandled = m_navigationUpdated; m_navigationUpdated = false; @@ -127,7 +136,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) int translatedMousePosX = me->x(); int translatedMousePosY = m_viewer->height() - me->y(); - if (m_isRotating) + if (m_isNavigating) { bool needRedraw = m_trackball->updateNavigation(translatedMousePosX, translatedMousePosY); if (needRedraw) @@ -182,65 +191,3 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) return isEventHandled; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuCadNavigation::initializeRotationCenter() -{ - if (m_isRotCenterInitialized - || m_trackball.isNull() - || !m_viewer->currentScene()->boundingBox().isValid()) - { - return; - } - - cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); - - this->setPointOfInterest(pointOfInterest); -} - -//-------------------------------------------------------------------------------------------------- -/// Repositions and orients the camera to view the rotation point along the -/// direction "alongDirection". The distance to the rotation point is maintained. -/// -//-------------------------------------------------------------------------------------------------- -void RiuCadNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) -{ - m_trackball->setView(alongDirection, upDirection); - /* - if (m_camera.isNull()) return; - - Vec3d dir = alongDirection; - if (!dir.normalize()) return; - Vec3d up = upDirection; - if(!up.normalize()) up = Vec3d::Z_AXIS; - - if((up * dir) < 1e-2) up = dir.perpendicularVector(); - - Vec3d cToE = m_camera->position() - m_rotationPoint; - Vec3d newEye = m_rotationPoint - cToE.length() * dir; - - m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); - */ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3d RiuCadNavigation::pointOfInterest() -{ - initializeRotationCenter(); - return m_pointOfInterest; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuCadNavigation::setPointOfInterest(cvf::Vec3d poi) -{ - m_pointOfInterest = poi; - m_trackball->setRotationPoint(poi); - m_isRotCenterInitialized = true; - m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); - -} diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.h b/ApplicationCode/UserInterface/RiuCadNavigation.h index 08f14c818f..955eb3c3b7 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.h +++ b/ApplicationCode/UserInterface/RiuCadNavigation.h @@ -19,29 +19,16 @@ #pragma once -#include "cvfBase.h" -#include "cafNavigationPolicy.h" -#include "cvfManipulatorTrackball.h" -#include "cvfRay.h" +#include "cafTrackBallBasedNavigation.h" - -class RiuCadNavigation : public caf::NavigationPolicy +class RiuCadNavigation : public caf::TrackBallBasedNavigation { +public: + RiuCadNavigation(); + virtual ~RiuCadNavigation(); protected: - // General navigation policy reimplememtation - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); - - - // Cad navigation specific - void initializeRotationCenter(); + virtual void init(); + virtual bool handleInputEvent(QInputEvent* inputEvent); - cvf::ref m_trackball; - bool m_isRotCenterInitialized; - bool m_isRotating; - cvf::Vec3d m_pointOfInterest; - bool m_navigationUpdated; + bool m_navigationUpdated; }; diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp index 3d5977a987..3bb0ed1797 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp @@ -20,30 +20,27 @@ #include "RiuGeoQuestNavigation.h" #include "cafViewer.h" #include "cvfCamera.h" -#include "cvfScene.h" -#include "cvfModel.h" #include "cvfViewport.h" #include "cvfHitItemCollection.h" #include "cvfRay.h" +#include "cvfManipulatorTrackball.h" #include -#include -using cvf::ManipulatorTrackball; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGeoQuestNavigation::RiuGeoQuestNavigation() +{ + +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuGeoQuestNavigation::init() +RiuGeoQuestNavigation::~RiuGeoQuestNavigation() { - m_trackball = new cvf::ManipulatorTrackball; - m_trackball->setCamera(m_viewer->mainCamera()); - m_isRotCenterInitialized = false; - m_hasMovedMouseDuringNavigation = false; - m_isNavigating = false; - m_isZooming = false; - m_lastPosX = 0; - m_lastPosY = 0; + } //-------------------------------------------------------------------------------------------------- @@ -171,88 +168,3 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) return false;//isEventHandled; } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGeoQuestNavigation::initializeRotationCenter() -{ - if (m_isRotCenterInitialized - || m_trackball.isNull() - || !m_viewer->currentScene()->boundingBox().isValid()) - { - return; - } - - cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); - - this->setPointOfInterest(pointOfInterest); -} - -//-------------------------------------------------------------------------------------------------- -/// Repositions and orients the camera to view the rotation point along the -/// direction "alongDirection". The distance to the rotation point is maintained. -/// -//-------------------------------------------------------------------------------------------------- -void RiuGeoQuestNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) -{ - m_trackball->setView(alongDirection, upDirection); - /* - if (m_camera.isNull()) return; - - Vec3d dir = alongDirection; - if (!dir.normalize()) return; - Vec3d up = upDirection; - if(!up.normalize()) up = Vec3d::Z_AXIS; - - if((up * dir) < 1e-2) up = dir.perpendicularVector(); - - Vec3d cToE = m_camera->position() - m_rotationPoint; - Vec3d newEye = m_rotationPoint - cToE.length() * dir; - - m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); - */ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3d RiuGeoQuestNavigation::pointOfInterest() -{ - initializeRotationCenter(); - return m_pointOfInterest; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGeoQuestNavigation::setPointOfInterest(cvf::Vec3d poi) -{ - m_pointOfInterest = poi; - m_trackball->setRotationPoint(poi); - m_isRotCenterInitialized = true; - m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGeoQuestNavigation::zoomAlongRay(cvf::Ray* ray, int delta) -{ - if (ray && abs(delta) > 0) - { - cvf::Vec3d pos, vrp, up; - m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); - - double scale = delta/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); - cvf::Vec3d trans = scale * ray->direction(); - cvf::Vec3d newPos = pos + trans; - cvf::Vec3d newVrp = vrp + trans; - - m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); - - m_viewer->navigationPolicyUpdate(); - } -} diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.h b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.h index 6dce37449b..2a2814bea3 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.h +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.h @@ -19,37 +19,14 @@ #pragma once -#include "cvfBase.h" -#include "cafNavigationPolicy.h" -#include "cvfManipulatorTrackball.h" -#include "cvfRay.h" +#include "cafTrackBallBasedNavigation.h" -class RiuGeoQuestNavigation : public caf::NavigationPolicy +class RiuGeoQuestNavigation : public caf::TrackBallBasedNavigation { +public: + RiuGeoQuestNavigation(); + virtual ~RiuGeoQuestNavigation(); protected: - // General navigation policy overrides - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); - - // PdvNavigation specific - void initializeRotationCenter(); - cvf::ref m_trackball; - bool m_isRotCenterInitialized; - cvf::Vec3d m_pointOfInterest; - - bool m_isNavigating; - bool m_hasMovedMouseDuringNavigation; - - // Handle mid mouse button zoom - void zoomAlongRay( cvf::Ray* ray, int delta ); - bool m_isZooming; - cvf::ref m_zoomRay; - int m_lastPosX; /// Previous mouse position - int m_lastPosY; - + virtual bool handleInputEvent(QInputEvent* inputEvent); }; diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp index e8b5be8694..e689ed92a2 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp @@ -20,30 +20,27 @@ #include "RiuRmsNavigation.h" #include "cafViewer.h" #include "cvfCamera.h" -#include "cvfScene.h" -#include "cvfModel.h" #include "cvfViewport.h" #include "cvfHitItemCollection.h" #include "cvfRay.h" +#include "cvfManipulatorTrackball.h" #include -#include -using cvf::ManipulatorTrackball; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuRmsNavigation::RiuRmsNavigation() +{ + +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuRmsNavigation::init() +RiuRmsNavigation::~RiuRmsNavigation() { - m_trackball = new cvf::ManipulatorTrackball; - m_trackball->setCamera(m_viewer->mainCamera()); - m_isRotCenterInitialized = false; - m_hasMovedMouseDuringNavigation = false; - m_isNavigating = false; - m_isZooming = false; - m_lastPosX = 0; - m_lastPosY = 0; + } //-------------------------------------------------------------------------------------------------- @@ -196,87 +193,3 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) return false;//isEventHandled; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuRmsNavigation::initializeRotationCenter() -{ - if (m_isRotCenterInitialized - || m_trackball.isNull() - || !m_viewer->currentScene()->boundingBox().isValid()) - { - return; - } - - cvf::Vec3d pointOfInterest = m_viewer->currentScene()->boundingBox().center(); - - this->setPointOfInterest(pointOfInterest); -} - -//-------------------------------------------------------------------------------------------------- -/// Repositions and orients the camera to view the rotation point along the -/// direction "alongDirection". The distance to the rotation point is maintained. -/// -//-------------------------------------------------------------------------------------------------- -void RiuRmsNavigation::setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) -{ - m_trackball->setView(alongDirection, upDirection); - /* - if (m_camera.isNull()) return; - - Vec3d dir = alongDirection; - if (!dir.normalize()) return; - Vec3d up = upDirection; - if(!up.normalize()) up = Vec3d::Z_AXIS; - - if((up * dir) < 1e-2) up = dir.perpendicularVector(); - - Vec3d cToE = m_camera->position() - m_rotationPoint; - Vec3d newEye = m_rotationPoint - cToE.length() * dir; - - m_camera->setFromLookAt(newEye, m_rotationPoint, upDirection); - */ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3d RiuRmsNavigation::pointOfInterest() -{ - initializeRotationCenter(); - return m_pointOfInterest; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuRmsNavigation::setPointOfInterest(cvf::Vec3d poi) -{ - m_pointOfInterest = poi; - m_trackball->setRotationPoint(poi); - m_isRotCenterInitialized = true; - m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuRmsNavigation::zoomAlongRay(cvf::Ray* ray, int delta) -{ - if (ray && abs(delta) > 0) - { - cvf::Vec3d pos, vrp, up; - m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); - - double scale = delta/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); - cvf::Vec3d trans = scale * ray->direction(); - cvf::Vec3d newPos = pos + trans; - cvf::Vec3d newVrp = vrp + trans; - - m_viewer->mainCamera()->setFromLookAt(newPos, newVrp, up ); - m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); - - m_viewer->navigationPolicyUpdate(); - } -} diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.h b/ApplicationCode/UserInterface/RiuRmsNavigation.h index 93fb068ec2..7274105dc7 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.h +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.h @@ -19,37 +19,14 @@ #pragma once -#include "cvfBase.h" -#include "cafNavigationPolicy.h" -#include "cvfManipulatorTrackball.h" -#include "cvfRay.h" +#include "cafTrackBallBasedNavigation.h" -class RiuRmsNavigation : public caf::NavigationPolicy +class RiuRmsNavigation : public caf::TrackBallBasedNavigation { +public: + RiuRmsNavigation(); + virtual ~RiuRmsNavigation(); protected: - // General navigation policy overrides - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); - - // PdvNavigation specific - void initializeRotationCenter(); - cvf::ref m_trackball; - bool m_isRotCenterInitialized; - cvf::Vec3d m_pointOfInterest; - - bool m_isNavigating; - bool m_hasMovedMouseDuringNavigation; - - // Handle mid mouse button zoom - void zoomAlongRay( cvf::Ray* ray, int delta ); - bool m_isZooming; - cvf::ref m_zoomRay; - int m_lastPosX; /// Previous mouse position - int m_lastPosY; - + virtual bool handleInputEvent(QInputEvent* inputEvent); }; From f1574bc774e13642015d9f5311ce699337cf4639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 08:14:50 +0100 Subject: [PATCH 247/290] (#168) Consolidated zoom along ray to prepare for handling ortho view --- .../UserInterface/RiuCadNavigation.cpp | 16 +--------------- Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 16 +--------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index a02fe70131..ba38ba5c97 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -166,21 +166,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) else ray = m_viewer->mainCamera()->rayFromWindowCoordinates((int)(1.0*translatedMousePosX), (int)(1.0*translatedMousePosY)); - if (ray.notNull() && abs(we->delta()) > 0) - { - cvf::Vec3d pos, vrp, up; - m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); - - double scale = -we->delta()/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); - cvf::Vec3d trans = scale * ray->direction(); - cvf::Vec3d newPos = pos + trans; - cvf::Vec3d newVrp = vrp + trans; - - m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); - - m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); - m_viewer->navigationPolicyUpdate(); - } + zoomAlongRay(ray.p(), -we->delta()); } isEventHandled = true; } diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index 3b10e34ab1..72a705b7d6 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -177,21 +177,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) else ray = m_viewer->mainCamera()->rayFromWindowCoordinates((int)(1.0*translatedMousePosX), (int)(1.0*translatedMousePosY)); - if (ray.notNull() && abs(we->delta()) > 0) - { - cvf::Vec3d pos, vrp, up; - m_viewer->mainCamera()->toLookAt(&pos, &vrp, &up); - - double scale = -we->delta()/8.0 * 1.0/150 * (pos - m_pointOfInterest).length(); - cvf::Vec3d trans = scale * ray->direction(); - cvf::Vec3d newPos = pos + trans; - cvf::Vec3d newVrp = vrp + trans; - - m_viewer->mainCamera()->setFromLookAt(newPos,newVrp, up ); - - m_viewer->updateParallelProjectionHeightFromMoveZoom(m_pointOfInterest); - m_viewer->navigationPolicyUpdate(); - } + zoomAlongRay(ray.p(), -we->delta()); } isEventHandled = true; } From 1d9481f09b022c118dd0128434106023f167b936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 09:27:43 +0100 Subject: [PATCH 248/290] (#695) Unintentional picking fixed. Fixed in viewer, keeping the concept of the navigation policies to not flag the the events as handled. Made this clearer by adding an interface to turn event consumption on or off on the navigation policies. --- .../UserInterface/RiuCadNavigation.cpp | 5 +- .../UserInterface/RiuGeoQuestNavigation.cpp | 5 +- .../UserInterface/RiuRmsNavigation.cpp | 5 +- ApplicationCode/UserInterface/RiuViewer.cpp | 9 + Fwk/AppFwk/cafViewer/cafCadNavigation.cpp | 5 +- .../cafViewer/cafCeetronPlusNavigation.cpp | 6 +- .../cafViewer/cafTrackBallBasedNavigation.cpp | 157 +----------------- .../cafViewer/cafTrackBallBasedNavigation.h | 14 ++ 8 files changed, 45 insertions(+), 161 deletions(-) diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index ba38ba5c97..5f145436a6 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -174,6 +174,9 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) break; } - return isEventHandled; + if (isSupposedToConsumeEvents()) + return isEventHandled; + else + return false; } diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp index 3bb0ed1797..95ba63030e 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp @@ -166,5 +166,8 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) break; } - return false;//isEventHandled; + if (isSupposedToConsumeEvents()) + return isEventHandled; + else + return false; } diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp index e689ed92a2..75ddf0a614 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp @@ -190,6 +190,9 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) break; } - return false;//isEventHandled; + if (isSupposedToConsumeEvents()) + return isEventHandled; + else + return false; } diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 8b4086b7dc..f4f7e6a7eb 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -228,6 +228,13 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { + QPoint diffPoint = event->pos() - m_lastMousePressPosition; + if (diffPoint.manhattanLength() > 3) + { + // We are possibly in navigation mode, only clean press event will launch + return; + } + if (!m_infoLabelOverlayArea.isNull()) { if (m_infoLabelOverlayArea.contains(event->x(), event->y())) @@ -239,7 +246,9 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) } m_viewerCommands->handlePickAction(event->x(), event->y(), event->modifiers()); + return; + } else if (event->button() == Qt::RightButton) { diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index 72a705b7d6..aa94ef46ec 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -185,5 +185,8 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) break; } - return isEventHandled; + if (isSupposedToConsumeEvents()) + return isEventHandled; + else + return false; } diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index 0ef728eef1..9e324806ef 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -43,6 +43,7 @@ #include "cvfManipulatorTrackball.h" #include +#include "cvfTrace.h" //-------------------------------------------------------------------------------------------------- /// @@ -208,5 +209,8 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) break; } - return false;//isEventHandled; + if (isSupposedToConsumeEvents()) + return isEventHandled; + else + return false; } diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp index 61cef22bda..9c4591c717 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp @@ -50,7 +50,7 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::TrackBallBasedNavigation::TrackBallBasedNavigation() +caf::TrackBallBasedNavigation::TrackBallBasedNavigation() : m_consumeEvents(false) { } @@ -63,8 +63,6 @@ caf::TrackBallBasedNavigation::~TrackBallBasedNavigation() } - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -80,159 +78,6 @@ void caf::TrackBallBasedNavigation::init() m_lastPosY = 0; } -#if 0 -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool caf::TrackBallBasedNavigation::handleInputEvent(QInputEvent* inputEvent) -{ - if (! inputEvent) return false; - bool isEventHandled = false; - switch (inputEvent->type()) - { - case QEvent::MouseButtonPress: - { - QMouseEvent * me = static_cast( inputEvent); - int translatedMousePosX = me->x(); - int translatedMousePosY = m_viewer->height() - me->y(); - - if (me->button() == Qt::RightButton) - { - cvf::HitItemCollection hic; - bool hitSomething = m_viewer->rayPick(me->x(), me->y(), &hic); - - if (hitSomething) - { - cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); - this->setPointOfInterest(pointOfInterest); - } - else - { - initializeRotationCenter(); - } - - m_trackball->startNavigation(cvf::ManipulatorTrackball::ROTATE, translatedMousePosX, translatedMousePosY); - //m_viewer->setCursor(RICursors::get(RICursors::ROTATE)); - m_isNavigating = true; - m_hasMovedMouseDuringNavigation = false; - isEventHandled = true; - } - else if (me->button() == Qt::LeftButton) - { - if (me->modifiers() == Qt::NoModifier) - { - m_trackball->startNavigation(cvf::ManipulatorTrackball::PAN, translatedMousePosX, translatedMousePosY); - m_isNavigating = true; - m_hasMovedMouseDuringNavigation = false; - isEventHandled = true; - } - } - else if (me->button() == Qt::MidButton) - { - if (me->modifiers() == Qt::NoModifier) - { - QMouseEvent* we = static_cast ( inputEvent); - m_lastPosX = we->x(); - m_lastPosY = we->y(); - - m_zoomRay = m_viewer->mainCamera()->rayFromWindowCoordinates(translatedMousePosX, translatedMousePosY); - - m_isNavigating = true; - m_hasMovedMouseDuringNavigation = false; - isEventHandled = true; - m_isZooming = true; - } - } - } - break; - case QEvent::MouseButtonRelease: - { - if (m_isNavigating) - { - QMouseEvent * me = static_cast( inputEvent); - if (me->button() == Qt::RightButton || me->button() == Qt::LeftButton ) - { - m_trackball->endNavigation(); - - m_isNavigating = false; - if (m_hasMovedMouseDuringNavigation) isEventHandled = true; - m_hasMovedMouseDuringNavigation = false; - } - else if ( me->button() == Qt::MidButton ) - { - m_isZooming = false; - - m_isNavigating = false; - if (m_hasMovedMouseDuringNavigation) isEventHandled = true; - m_hasMovedMouseDuringNavigation = false; - } - } - } - break; - case QEvent::MouseMove: - { - initializeRotationCenter(); - if (m_isRotCenterInitialized) - { - QMouseEvent * me = static_cast( inputEvent); - int translatedMousePosX = me->x(); - int translatedMousePosY = m_viewer->height() - me->y(); - - if (m_isNavigating) - { - if (m_isZooming) - { - int delta = 3*(m_lastPosY - me->y()); - this->zoomAlongRay(m_zoomRay.p(), delta); - m_lastPosX = me->x(); - m_lastPosY = me->y(); - } - else - { - bool needRedraw = m_trackball->updateNavigation(translatedMousePosX, translatedMousePosY); - if (needRedraw) - { - m_viewer->navigationPolicyUpdate(); - } - } - isEventHandled = true; - m_hasMovedMouseDuringNavigation = true; - } - } - } - break; - case QEvent::Wheel: - { - if (inputEvent->modifiers() == Qt::NoModifier) - { - initializeRotationCenter(); - if (m_isRotCenterInitialized) - { - QWheelEvent* we = static_cast ( inputEvent); - int translatedMousePosX = we->x(); - int translatedMousePosY = m_viewer->height() - we->y(); - int delta = we->delta(); - - cvf::ref ray; - if (delta < 0) - ray = m_viewer->mainCamera()->rayFromWindowCoordinates(translatedMousePosX, translatedMousePosY); - else - ray = m_viewer->mainCamera()->rayFromWindowCoordinates((int)(1.0*translatedMousePosX), (int)(1.0*translatedMousePosY)); - - zoomAlongRay(ray.p(), delta); - - } - isEventHandled = true; - } - } - break; - } - - return false;//isEventHandled; -} - -#endif - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h index d4766276c7..0083512d89 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h @@ -44,12 +44,22 @@ namespace cvf { namespace caf { +//-------------------------------------------------------------------------------------------------- +/// This class is a work in progress to consolidate the different navigation policies that are similar. +/// It is not yet finished. We need to extract the Pan, Rotation, ... etc. codes from the +/// special input event handlers and invoke those general methods from the event handlers instead. +/// Some of the protected variables in this class is used by the +/// derived classes, and should rather be used from the general methods in this class and thus be private +/// +//-------------------------------------------------------------------------------------------------- class TrackBallBasedNavigation: public NavigationPolicy { public: TrackBallBasedNavigation(); virtual ~TrackBallBasedNavigation(); + void enableEventEating(bool enable) { m_consumeEvents = enable; } + protected: // General navigation policy overrides virtual void init(); @@ -74,6 +84,10 @@ class TrackBallBasedNavigation: public NavigationPolicy int m_lastPosX; /// Previous mouse position int m_lastPosY; + bool isSupposedToConsumeEvents() { return m_consumeEvents; } + +private: + bool m_consumeEvents; }; } // End namespace caf From 009f1d157a8e36258d6b139391f677829460d6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 09:33:09 +0100 Subject: [PATCH 249/290] (#168) Giving up to get parallel projection production ready for 1.6.0 Hide the parallel projection field. --- ApplicationCode/ProjectDataModel/RimView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ApplicationCode/ProjectDataModel/RimView.cpp b/ApplicationCode/ProjectDataModel/RimView.cpp index c089742ebd..4249bf4b1f 100644 --- a/ApplicationCode/ProjectDataModel/RimView.cpp +++ b/ApplicationCode/ProjectDataModel/RimView.cpp @@ -79,6 +79,7 @@ RimView::RimView(void) cameraPosition.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&isPerspectiveView, "PerspectiveProjection", true, "Perspective Projection", "", "", ""); + isPerspectiveView.uiCapability()->setUiHidden(true); // For now as this is experimental double defaultScaleFactor = preferences->defaultScaleFactorZ; CAF_PDM_InitField(&scaleZ, "GridZScale", defaultScaleFactor, "Z Scale", "", "Scales the scene in the Z direction", ""); From 856054666dede3783112c55c83aef318c0ea5635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 10:40:15 +0100 Subject: [PATCH 250/290] Fixed error introduced in 28a0e1107c87e --- .../ModelVisualization/RivReservoirViewPartMgr.cpp | 12 +++++++++++- .../ReservoirDataModel/RigResultAccessorFactory.cpp | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp index 5714221d55..56209c427e 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp @@ -789,7 +789,17 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis RigCaseData* eclipseCase = propFilterColl->reservoirView()->eclipseCase()->reservoirData(); - cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, grid->gridIndex(), timeStepIndex, propertyFilter->resultDefinition()); + size_t adjustedTimeStepIndex = timeStepIndex; + + // Set time step to zero for static results + if (propertyFilter->resultDefinition()->hasStaticResult()) + { + adjustedTimeStepIndex = 0; + } + + RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(propertyFilter->resultDefinition()->porosityModel()); + cvf::ref resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, grid->gridIndex(), porosityModel, adjustedTimeStepIndex, propertyFilter->resultDefinition->resultVariable(), propertyFilter->resultDefinition->resultType()); + CVF_ASSERT(resultAccessor.notNull()); //#pragma omp parallel for schedule(dynamic) diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp index 958fe7f689..cc7fabfd95 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp @@ -171,7 +171,8 @@ cvf::ref RigResultAccessorFactory::createResultAccessor(RigCa } return RigResultAccessorFactory::createResultAccessor( - eclipseCase, 0, + eclipseCase, + gridIndex, porosityModel, adjustedTimeStepIndex, resultDefinition->resultVariable()); From 2f05ecb9ad9535763b3517432821c7fda4f1d02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 11:39:10 +0100 Subject: [PATCH 251/290] Fixed memory leak and removed unused code --- .../RimEclipseInputPropertyCollection.cpp | 22 +------------------ .../RimEclipseInputPropertyCollection.h | 3 --- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.cpp index 7bd75d92ef..8a44efb595 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.cpp @@ -42,7 +42,7 @@ RimEclipseInputPropertyCollection::RimEclipseInputPropertyCollection() //-------------------------------------------------------------------------------------------------- RimEclipseInputPropertyCollection::~RimEclipseInputPropertyCollection() { - + inputProperties.deleteAllChildObjects(); } //-------------------------------------------------------------------------------------------------- @@ -63,26 +63,6 @@ std::vector RimEclipseInputPropertyCollection::findInp return result; } -//-------------------------------------------------------------------------------------------------- -/// Remove given input property from collection and checks if the associated file is referenced by other input -/// properties -//-------------------------------------------------------------------------------------------------- -void RimEclipseInputPropertyCollection::removeInputProperty(RimEclipseInputProperty* inputProperty, bool& isPropertyFileReferencedByOthers) -{ - CVF_ASSERT(inputProperty); - - this->inputProperties.removeChildObject(inputProperty); - - isPropertyFileReferencedByOthers = false; - for (size_t i = 0; i < this->inputProperties.size(); i++) - { - if (inputProperties[i]->fileName() == inputProperty->fileName) - { - isPropertyFileReferencedByOthers = true; - } - } -} - //-------------------------------------------------------------------------------------------------- /// Returns the InputProperty with resultName \a resultName //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.h b/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.h index a9e46a1948..b7049d926e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseInputPropertyCollection.h @@ -45,9 +45,6 @@ class RimEclipseInputPropertyCollection : public caf::PdmObject std::vector findInputProperties(QString fileName); RimEclipseInputProperty* findInputProperty(QString resultName); - void removeInputProperty(RimEclipseInputProperty* inputProperty, bool& isPropertyFileReferencedByOthers); - - // Fields: caf::PdmChildArrayField inputProperties; From d84db62ebbd2a52cf8cd6264a9db2bb470ea483b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 12:21:01 +0100 Subject: [PATCH 252/290] System: Do not change the preferences when running regression tests. We need the flexibility in the tests. --- .../Application/RiaApplication.cpp | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index b000edc340..487588ff98 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1771,21 +1771,6 @@ void RiaApplication::runRegressionTest(const QString& testRootPath) // Open HTML report QDesktopServices::openUrl(htmlReportFileName); - // Keep current preferences values to be able to restore when regression tests are completed - std::vector preferencesValues; - { - std::vector fields; - this->preferences()->fields(fields); - for (size_t i = 0; i < fields.size(); i++) - { - QVariant v = fields[i]->uiCapability()->uiValue(); - preferencesValues.push_back(v); - } - } - - // Set preferences to make sure regression tests behave identical - this->preferences()->configureForRegressionTests(); - for (int dirIdx = 0; dirIdx < folderList.size(); ++dirIdx) { QDir testCaseFolder(folderList[dirIdx].filePath()); @@ -1825,18 +1810,6 @@ void RiaApplication::runRegressionTest(const QString& testRootPath) closeProject(false); } - - // Restore preferences - { - std::vector fields; - this->preferences()->fields(fields); - CVF_ASSERT(fields.size() == preferencesValues.size()); - - for (size_t i = 0; i < preferencesValues.size(); i++) - { - fields[i]->uiCapability()->setValueFromUi(preferencesValues[i]); - } - } } m_runningRegressionTests = false; From b9318376ccc563681c217477d97d2577691bf140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 12:22:52 +0100 Subject: [PATCH 253/290] Upped to 1.5.103-dev Release candidate for testing --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index b967507f1e..836a16d2ac 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 102) +set(CMAKE_PATCH_VERSION 103) set(DEV_VERSION "-dev") From 179f0c906b3d6be152cea82b16dca94852e8a018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 10 Dec 2015 14:11:07 +0100 Subject: [PATCH 254/290] Fixed simulation well pipe visibility error introduced in 707e8c68ab5e --- ApplicationCode/ProjectDataModel/RimEclipseView.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index 87b6c3eaff..e3939dcb16 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1108,10 +1108,9 @@ void RimEclipseView::syncronizeWellsWithResults() { well = new RimEclipseWell; well->name = wellResults[wIdx]->m_wellName; - } newWells.push_back(well); - well->setWellIndex(wIdx); + well->setWellResults(wellResults[wIdx].p()); } @@ -1140,6 +1139,13 @@ void RimEclipseView::syncronizeWellsWithResults() } this->wellCollection()->sortWellsByName(); + + for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) + { + this->wellCollection()->wells()[wIdx]->setWellIndex(wIdx); + } + + } //-------------------------------------------------------------------------------------------------- From 061de66597aab2085e6be8f16865e3aaa1f8a9f0 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 10 Dec 2015 22:31:41 +0100 Subject: [PATCH 255/290] Clamp time step when changing case for well log extraction curve --- .../RimWellLogExtractionCurve.cpp | 15 +++++++++++++++ .../ProjectDataModel/RimWellLogExtractionCurve.h | 1 + 2 files changed, 16 insertions(+) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 7f6a4bbfc7..6cfbdb4c37 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -140,6 +140,19 @@ void RimWellLogExtractionCurve::setPropertiesFromView(RimView* view) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellLogExtractionCurve::clampTimestep() +{ + if (m_case) + { + if (m_timeStep > m_case->timeStepStrings().size() - 1) + { + m_timeStep = m_case->timeStepStrings().size() - 1; + } + } +} //-------------------------------------------------------------------------------------------------- /// @@ -150,6 +163,8 @@ void RimWellLogExtractionCurve::fieldChangedByUi(const caf::PdmFieldHandle* chan if (changedField == &m_case) { + clampTimestep(); + this->updatePlotData(); } else if (changedField == &m_wellPath) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index 87f8f47f9e..df2b4bcc49 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -64,6 +64,7 @@ class RimWellLogExtractionCurve : public RimWellLogCurve private: void setLogScaleFromSelectedResult(); + void clampTimestep(); private: caf::PdmPtrField m_wellPath; From 34862d39b0851dc2fae905135a44e51d90f654f3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 10 Dec 2015 23:09:33 +0100 Subject: [PATCH 256/290] (#703) Make sure simulation wells are read before resolving references --- .../RicPasteEclipseViewsFeature.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp index ce4626fc89..1825d94b93 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp @@ -93,20 +93,21 @@ void RicPasteEclipseViewsFeature::onActionTriggered(bool isChecked) rimReservoirView->name = nameOfCopy; eclipseCase->reservoirViews().push_back(rimReservoirView); - // Delete all wells to be able to copy/paste between cases, as the wells differ between cases + // Delete all wells to be able to copy/paste between cases, as the wells can be different between cases + // Wells are read from file in loadDataAndUpdate -> syncronizeWellsWithResults rimReservoirView->wellCollection()->wells().deleteAllChildObjects(); rimReservoirView->setEclipseCase(eclipseCase); + rimReservoirView->loadDataAndUpdate(); // Resolve references after reservoir view has been inserted into Rim structures - // Intersections referencing a well path requires this + // Intersections referencing a well path/ simulation well requires this + // TODO: initAfterReadRecursively can probably be removed rimReservoirView->initAfterReadRecursively(); rimReservoirView->resolveReferencesRecursively(); caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); - rimReservoirView->loadDataAndUpdate(); - eclipseCase->updateConnectedEditors(); } } From c0d08dd37fc6d4474b6a2dc4b22ee6a1d917baf2 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 11 Dec 2015 10:10:36 +0100 Subject: [PATCH 257/290] Fixed up regression introduced in 28a0e1107c87e8e91b4fa1c54b25192ff4864e41 Loading of result is supposed to happen only for RimWellLogExtractionCurve --- ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp | 2 ++ ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 6cfbdb4c37..87a7ea1718 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -229,6 +229,8 @@ void RimWellLogExtractionCurve::updatePlotData() tvDepthValues = eclExtractor->trueVerticalDepth(); } + m_eclipseResultDefinition->loadResult(); + cvf::ref resAcc = RigResultAccessorFactory::createResultAccessor( eclipseCase->reservoirData(), 0, diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp index cc7fabfd95..e6895fcb81 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp @@ -162,7 +162,6 @@ cvf::ref RigResultAccessorFactory::createResultAccessor(RigCa cvf::ref RigResultAccessorFactory::createResultAccessor(RigCaseData* eclipseCase, size_t gridIndex, size_t timeStepIndex, RimEclipseResultDefinition* resultDefinition) { RifReaderInterface::PorosityModelResultType porosityModel = RigCaseCellResultsData::convertFromProjectModelPorosityModel(resultDefinition->porosityModel()); - resultDefinition->loadResult(); size_t adjustedTimeStepIndex = timeStepIndex; if (resultDefinition->hasStaticResult()) From 6b070c6b12882fc81ebcf42755fe095d29ac71e9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 11 Dec 2015 10:20:15 +0100 Subject: [PATCH 258/290] (#704) Do not delete simulation wells as part of paste operation Sync of wells happens in loadDataAndUpdate -> syncronizeWellsWithResults, and potentially missing wells will be deleted. LoadDataAndUpdate must also happen after references are resolved --- .../RicPasteEclipseViewsFeature.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp index 1825d94b93..4b522d8d29 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteEclipseViewsFeature.cpp @@ -93,12 +93,7 @@ void RicPasteEclipseViewsFeature::onActionTriggered(bool isChecked) rimReservoirView->name = nameOfCopy; eclipseCase->reservoirViews().push_back(rimReservoirView); - // Delete all wells to be able to copy/paste between cases, as the wells can be different between cases - // Wells are read from file in loadDataAndUpdate -> syncronizeWellsWithResults - rimReservoirView->wellCollection()->wells().deleteAllChildObjects(); - rimReservoirView->setEclipseCase(eclipseCase); - rimReservoirView->loadDataAndUpdate(); // Resolve references after reservoir view has been inserted into Rim structures // Intersections referencing a well path/ simulation well requires this @@ -106,6 +101,8 @@ void RicPasteEclipseViewsFeature::onActionTriggered(bool isChecked) rimReservoirView->initAfterReadRecursively(); rimReservoirView->resolveReferencesRecursively(); + rimReservoirView->loadDataAndUpdate(); + caf::PdmDocument::updateUiIconStateRecursively(rimReservoirView); eclipseCase->updateConnectedEditors(); From 9c8a75a2373a921d4154f74ff35a422926364e82 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 11 Dec 2015 10:45:48 +0100 Subject: [PATCH 259/290] Do not modify fault settings when preparing for regression test --- ApplicationCode/Application/RiaApplication.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 487588ff98..a6577f6890 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1659,6 +1659,10 @@ void RiaApplication::saveSnapshotForAllViews(const QString& snapshotFolderName) clearViewsScheduledForUpdate(); + //riv->updateCurrentTimeStepAndRedraw(); + riv->createDisplayModelAndRedraw(); + viewer->repaint(); + QString fileName = cas->caseUserDescription() + "-" + riv->name(); fileName.replace(" ", "_"); @@ -2258,19 +2262,6 @@ void RiaApplication::regressionTestConfigureProject() // This size is set to match the regression test reference images riv->viewer()->setFixedSize(1000, 745); } - - RimEclipseView* resvView = dynamic_cast(riv); - - if (resvView) - { - resvView->faultCollection->setShowFaultsOutsideFilters(false); - - caf::PdmUiFieldHandle* uiFieldHandle = resvView->faultResultSettings->showCustomFaultResult.uiCapability(); - if (uiFieldHandle) - { - uiFieldHandle->setValueFromUi(false); - } - } } } } From 7bcf6bfd8965b544679a2418b11e59a1405c8a04 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 11 Dec 2015 10:55:37 +0100 Subject: [PATCH 260/290] Upped to 1.5.104-RC Release candidate --- ResInsightVersion.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 836a16d2ac..1e9af80bb9 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,8 +1,8 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 103) -set(DEV_VERSION "-dev") +set(CMAKE_PATCH_VERSION 104) +set(DEV_VERSION "-RC") # https://github.com/CRAVA/crava/tree/master/libs/nrlib From d01367a932a38ee11689cd54997aa8457c6b78f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 11 Dec 2015 17:34:52 +0100 Subject: [PATCH 261/290] (#707) Fixed regression regarding well pipe and well cells Introduced in 707e8c6 and not quite fixed in 179f0c9 --- .../ProjectDataModel/RimEclipseView.cpp | 11 ++--------- .../ProjectDataModel/RimEclipseWell.cpp | 14 +++++++++++--- ApplicationCode/ProjectDataModel/RimEclipseWell.h | 8 ++++---- .../ProjectDataModel/RimEclipseWellCollection.cpp | 2 +- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index e3939dcb16..c3cd15b896 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -1095,7 +1095,7 @@ void RimEclipseView::syncronizeWellsWithResults() for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) { RimEclipseWell* well = this->wellCollection()->wells()[wIdx]; - well->setWellResults(NULL); + well->setWellResults(NULL, -1); } // Find corresponding well from well result, or create a new @@ -1111,7 +1111,7 @@ void RimEclipseView::syncronizeWellsWithResults() } newWells.push_back(well); - well->setWellResults(wellResults[wIdx].p()); + well->setWellResults(wellResults[wIdx].p(), wIdx); } // Delete all wells that does not have a result @@ -1139,13 +1139,6 @@ void RimEclipseView::syncronizeWellsWithResults() } this->wellCollection()->sortWellsByName(); - - for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) - { - this->wellCollection()->wells()[wIdx]->setWellIndex(wIdx); - } - - } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp index 7fbad606e0..2e9c9b3a89 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp @@ -50,7 +50,7 @@ RimEclipseWell::RimEclipseWell() name.uiCapability()->setUiHidden(true); name.uiCapability()->setUiReadOnly(true); - m_wellIndex = cvf::UNDEFINED_SIZE_T; + m_resultWellIndex = cvf::UNDEFINED_SIZE_T; m_reservoirView = NULL; } @@ -254,9 +254,17 @@ void RimEclipseWell::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& //-------------------------------------------------------------------------------------------------- bool RimEclipseWell::isWellPipeVisible(size_t frameIndex) { - CVF_ASSERT(m_wellIndex != cvf::UNDEFINED_SIZE_T); + CVF_ASSERT(m_resultWellIndex != cvf::UNDEFINED_SIZE_T); // Return the possibly cached value - return m_reservoirView->wellCollection()->isWellPipesVisible(frameIndex)[m_wellIndex]; + return m_reservoirView->wellCollection()->isWellPipesVisible(frameIndex)[m_resultWellIndex]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseWell::setWellResults(RigSingleWellResultsData* wellResults, size_t resultWellIndex) +{ + m_wellResults = wellResults; m_resultWellIndex = resultWellIndex; } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWell.h b/ApplicationCode/ProjectDataModel/RimEclipseWell.h index e1b938a7f9..a3912ad7ba 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWell.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseWell.h @@ -47,11 +47,11 @@ class RimEclipseWell : public caf::PdmObject virtual ~RimEclipseWell(); void setReservoirView(RimEclipseView* ownerReservoirView); - void setWellIndex(size_t val) { m_wellIndex = val; } - void setWellResults(RigSingleWellResultsData* wellResults) { m_wellResults = wellResults;} + void setWellResults(RigSingleWellResultsData* wellResults, size_t resultWellIndex); RigSingleWellResultsData* wellResults() { return m_wellResults.p(); } - + size_t resultWellIndex() { return m_resultWellIndex; } + bool isWellPipeVisible(size_t frameIndex); bool calculateWellPipeVisibility(size_t frameIndex); @@ -76,7 +76,7 @@ class RimEclipseWell : public caf::PdmObject private: cvf::ref m_wellResults; - size_t m_wellIndex; + size_t m_resultWellIndex; RimEclipseView* m_reservoirView; }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp index e01da35ac5..73e335a3a7 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp @@ -330,7 +330,7 @@ void RimEclipseWellCollection::calculateIsWellPipesVisible(size_t frameIndex) for (size_t i = 0; i < wells().size(); ++i) { - m_isWellPipesVisible[frameIndex][i] = wells[i]->calculateWellPipeVisibility(frameIndex); + m_isWellPipesVisible[frameIndex][wells[i]->resultWellIndex()] = wells[i]->calculateWellPipeVisibility(frameIndex); } } From 2a98f5b116e9569e43a33147e2d5443d8327a45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 11 Dec 2015 17:45:09 +0100 Subject: [PATCH 262/290] (#707) Renamed to make the use of resultWellIndex more clear --- .../RivCellEdgeGeometryUtils.cpp | 6 ++--- .../RivTernaryTextureCoordsCreator.cpp | 5 +++-- .../RivTextureCoordsCreator.cpp | 5 +++-- .../ProjectDataModel/RimEclipseWell.cpp | 2 +- .../RimEclipseWellCollection.cpp | 18 +++++++-------- .../RimEclipseWellCollection.h | 4 ++-- .../ReservoirDataModel/RigCaseData.cpp | 22 +++++++++---------- .../ReservoirDataModel/RigCaseData.h | 6 ++--- .../RigPipeInCellEvaluator.h | 8 +++---- 9 files changed, 39 insertions(+), 37 deletions(-) diff --git a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp index ce3409c162..fef803b19e 100644 --- a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp +++ b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp @@ -86,12 +86,12 @@ void RivCellEdgeGeometryUtils::addCellEdgeResultsToDrawableGeo( double ignoredScalarValue = cellEdgeResultColors->ignoredScalarValue(); const std::vector* isWellPipeVisible = NULL; - cvf::ref gridCellToWellindexMap; + cvf::cref gridCellToWellindexMap; if (opacityLevel < 1.0f) { - isWellPipeVisible = &(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex)); - gridCellToWellindexMap = eclipseCase->gridCellToWellIndex(gridIndex); + isWellPipeVisible = &(cellResultColors->reservoirView()->wellCollection()->resultWellPipeVisibilities(timeStepIndex)); + gridCellToWellindexMap = eclipseCase->gridCellToResultWellIndex(gridIndex); } #pragma omp parallel for diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp index 05774f17ab..af3985b783 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp @@ -62,8 +62,9 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( m_resultAccessor = new RigTernaryResultAccessor(); m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); - cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), - eclipseCase->gridCellToWellIndex(gridIndex)); + cvf::ref pipeInCellEval = + new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->resultWellPipeVisibilities(timeStepIndex), + eclipseCase->gridCellToResultWellIndex(gridIndex)); const RivTernaryScalarMapper* mapper = ternaryLegendConfig->scalarMapper(); diff --git a/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp index 91dbabe2db..4f520b2c3d 100644 --- a/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTextureCoordsCreator.cpp @@ -41,8 +41,9 @@ RivTextureCoordsCreator::RivTextureCoordsCreator(RimEclipseCellColors* cellResul m_resultAccessor = RigResultAccessorFactory::createResultAccessor(eclipseCase, gridIndex, timeStepIndex, cellResultColors); - cvf::ref pipeInCellEval = new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->isWellPipesVisible(timeStepIndex), - eclipseCase->gridCellToWellIndex(gridIndex)); + cvf::ref pipeInCellEval = + new RigPipeInCellEvaluator(cellResultColors->reservoirView()->wellCollection()->resultWellPipeVisibilities(timeStepIndex), + eclipseCase->gridCellToResultWellIndex(gridIndex)); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp index 2e9c9b3a89..4fa6c14651 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWell.cpp @@ -257,7 +257,7 @@ bool RimEclipseWell::isWellPipeVisible(size_t frameIndex) CVF_ASSERT(m_resultWellIndex != cvf::UNDEFINED_SIZE_T); // Return the possibly cached value - return m_reservoirView->wellCollection()->isWellPipesVisible(frameIndex)[m_resultWellIndex]; + return m_reservoirView->wellCollection()->resultWellPipeVisibilities(frameIndex)[m_resultWellIndex]; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp index 73e335a3a7..be76cd33c8 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.cpp @@ -301,10 +301,10 @@ caf::PdmFieldHandle* RimEclipseWellCollection::objectToggleField() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RimEclipseWellCollection::isWellPipesVisible(size_t frameIndex) +const std::vector& RimEclipseWellCollection::resultWellPipeVisibilities(size_t frameIndex) { calculateIsWellPipesVisible(frameIndex); - return m_isWellPipesVisible[frameIndex]; + return m_framesOfResultWellPipeVisibilities[frameIndex]; } //-------------------------------------------------------------------------------------------------- @@ -312,7 +312,7 @@ const std::vector& RimEclipseWellCollection::isWellPipesVisible(size //-------------------------------------------------------------------------------------------------- void RimEclipseWellCollection::scheduleIsWellPipesVisibleRecalculation() { - m_isWellPipesVisible.clear(); + m_framesOfResultWellPipeVisibilities.clear(); } //-------------------------------------------------------------------------------------------------- @@ -320,17 +320,17 @@ void RimEclipseWellCollection::scheduleIsWellPipesVisibleRecalculation() //-------------------------------------------------------------------------------------------------- void RimEclipseWellCollection::calculateIsWellPipesVisible(size_t frameIndex) { - if (m_isWellPipesVisible.size() > frameIndex && m_isWellPipesVisible[frameIndex].size()) return; + if (m_framesOfResultWellPipeVisibilities.size() > frameIndex && m_framesOfResultWellPipeVisibilities[frameIndex].size()) return; - if (m_isWellPipesVisible.size() <= frameIndex) - m_isWellPipesVisible.resize(frameIndex+1); + if (m_framesOfResultWellPipeVisibilities.size() <= frameIndex) + m_framesOfResultWellPipeVisibilities.resize(frameIndex+1); - if (m_isWellPipesVisible[frameIndex].size() <= wells().size()) - m_isWellPipesVisible[frameIndex].resize(wells().size(), false); + if (m_framesOfResultWellPipeVisibilities[frameIndex].size() <= wells().size()) + m_framesOfResultWellPipeVisibilities[frameIndex].resize(wells().size(), false); for (size_t i = 0; i < wells().size(); ++i) { - m_isWellPipesVisible[frameIndex][wells[i]->resultWellIndex()] = wells[i]->calculateWellPipeVisibility(frameIndex); + m_framesOfResultWellPipeVisibilities[frameIndex][wells[i]->resultWellIndex()] = wells[i]->calculateWellPipeVisibility(frameIndex); } } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h index 9822f693ca..7aa4cf554b 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseWellCollection.h @@ -109,7 +109,7 @@ class RimEclipseWellCollection : public caf::PdmObject bool hasVisibleWellPipes(); void sortWellsByName(); - const std::vector& isWellPipesVisible(size_t frameIndex); + const std::vector& resultWellPipeVisibilities(size_t frameIndex); void scheduleIsWellPipesVisibleRecalculation(); protected: @@ -122,5 +122,5 @@ class RimEclipseWellCollection : public caf::PdmObject RimEclipseView* m_reservoirView; std::vector< std::vector< cvf::ubyte > > - m_isWellPipesVisible; + m_framesOfResultWellPipeVisibilities; }; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp index de4ce29adf..2f86949a8b 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp @@ -143,7 +143,7 @@ void RigCaseData::computeWellCellsPrGrid() // Allocate and initialize the arrays m_wellCellsInGrid.resize(grids.size()); - m_gridCellToWellIndex.resize(grids.size()); + m_gridCellToResultWellIndex.resize(grids.size()); for (gIdx = 0; gIdx < grids.size(); ++gIdx) { @@ -152,11 +152,11 @@ void RigCaseData::computeWellCellsPrGrid() m_wellCellsInGrid[gIdx] = new cvf::UByteArray; m_wellCellsInGrid[gIdx]->resize(grids[gIdx]->cellCount()); - m_gridCellToWellIndex[gIdx] = new cvf::UIntArray; - m_gridCellToWellIndex[gIdx]->resize(grids[gIdx]->cellCount()); + m_gridCellToResultWellIndex[gIdx] = new cvf::UIntArray; + m_gridCellToResultWellIndex[gIdx]->resize(grids[gIdx]->cellCount()); } m_wellCellsInGrid[gIdx]->setAll(false); - m_gridCellToWellIndex[gIdx]->setAll(cvf::UNDEFINED_UINT); + m_gridCellToResultWellIndex[gIdx]->setAll(cvf::UNDEFINED_UINT); } // Fill arrays with data @@ -178,7 +178,7 @@ void RigCaseData::computeWellCellsPrGrid() || m_fractureActiveCellInfo->isActive(reservoirCellIndex)) { m_wellCellsInGrid[gridIndex]->set(gridCellIndex, true); - m_gridCellToWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); + m_gridCellToResultWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); } } @@ -195,7 +195,7 @@ void RigCaseData::computeWellCellsPrGrid() if(gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size()) { m_wellCellsInGrid[gridIndex]->set(gridCellIndex, true); - m_gridCellToWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); + m_gridCellToResultWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); } } } @@ -210,7 +210,7 @@ void RigCaseData::setWellResults(const cvf::Collection { m_wellResults = data; m_wellCellsInGrid.clear(); - m_gridCellToWellIndex.clear(); + m_gridCellToResultWellIndex.clear(); computeWellCellsPrGrid(); } @@ -218,7 +218,7 @@ void RigCaseData::setWellResults(const cvf::Collection //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::UByteArray* RigCaseData::wellCellsInGrid(size_t gridIndex) +const cvf::UByteArray* RigCaseData::wellCellsInGrid(size_t gridIndex) { computeWellCellsPrGrid(); CVF_ASSERT(gridIndex < m_wellCellsInGrid.size()); @@ -230,12 +230,12 @@ cvf::UByteArray* RigCaseData::wellCellsInGrid(size_t gridIndex) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::UIntArray* RigCaseData::gridCellToWellIndex(size_t gridIndex) +const cvf::UIntArray* RigCaseData::gridCellToResultWellIndex(size_t gridIndex) { computeWellCellsPrGrid(); - CVF_ASSERT(gridIndex < m_gridCellToWellIndex.size()); + CVF_ASSERT(gridIndex < m_gridCellToResultWellIndex.size()); - return m_gridCellToWellIndex[gridIndex].p(); + return m_gridCellToResultWellIndex[gridIndex].p(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigCaseData.h b/ApplicationCode/ReservoirDataModel/RigCaseData.h index 7ab31b2be4..d259494d3f 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseData.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseData.h @@ -66,8 +66,8 @@ class RigCaseData : public cvf::Object void setWellResults(const cvf::Collection& data); const cvf::Collection& wellResults() { return m_wellResults; } - cvf::UByteArray* wellCellsInGrid(size_t gridIndex); - cvf::UIntArray* gridCellToWellIndex(size_t gridIndex); + const cvf::UByteArray* wellCellsInGrid(size_t gridIndex); + const cvf::UIntArray* gridCellToResultWellIndex(size_t gridIndex); RigCell& cellFromWellResultCell(const RigWellResultPoint& wellResultCell); bool findSharedSourceFace(cvf::StructGridInterface::FaceType& sharedSourceFace, const RigWellResultPoint& sourceWellCellResult, const RigWellResultPoint& otherWellCellResult) const; @@ -92,7 +92,7 @@ class RigCaseData : public cvf::Object cvf::Collection m_wellResults; //< A WellResults object for each well in the reservoir cvf::Collection m_wellCellsInGrid; //< A bool array pr grid with one bool pr cell telling wether the cell is a well cell or not - cvf::Collection m_gridCellToWellIndex; //< Array pr grid with index to well pr cell telling which well a cell is in + cvf::Collection m_gridCellToResultWellIndex; //< Array pr grid with index to well pr cell telling which well a cell is in UnitsType m_unitsType; }; diff --git a/ApplicationCode/ReservoirDataModel/RigPipeInCellEvaluator.h b/ApplicationCode/ReservoirDataModel/RigPipeInCellEvaluator.h index 5a435ca99e..32edb8244f 100644 --- a/ApplicationCode/ReservoirDataModel/RigPipeInCellEvaluator.h +++ b/ApplicationCode/ReservoirDataModel/RigPipeInCellEvaluator.h @@ -27,10 +27,10 @@ class RigPipeInCellEvaluator: public cvf::Object { public: - RigPipeInCellEvaluator(const std::vector& isWellPipeVisibleForWellIndex, - const cvf::UIntArray* gridCellToWellIndexMap) - : m_isWellPipeVisibleForWellIndex(isWellPipeVisibleForWellIndex), - m_gridCellToWellIndexMap(gridCellToWellIndexMap) + RigPipeInCellEvaluator(const std::vector& isWellPipeVisibleForResultWellIndex, + const cvf::UIntArray* gridCellToResultWellIndexMap) + : m_isWellPipeVisibleForWellIndex(isWellPipeVisibleForResultWellIndex), + m_gridCellToWellIndexMap(gridCellToResultWellIndexMap) { } From f436d882b59be3b705db98f10899067e5983c708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Fri, 11 Dec 2015 17:49:30 +0100 Subject: [PATCH 263/290] Upped to 1.5.105-RC after fix of #707 --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 1e9af80bb9..71087b3d56 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 104) +set(CMAKE_PATCH_VERSION 105) set(DEV_VERSION "-RC") From 6db74465b64e3b8bc2c824600bfa88b9c879883f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 09:53:59 +0100 Subject: [PATCH 264/290] Removed debug output --- ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp | 4 ++-- Fwk/AppFwk/cafViewer/cafViewer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp index 16665338da..7131355278 100644 --- a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp @@ -811,7 +811,7 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(QF QFile includeFile(absoluteFilename); if (includeFile.open(QFile::ReadOnly)) { - qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename; + //qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename; if (!readFaultsAndParseIncludeStatementsRecursively(includeFile, 0, faults, filenamesWithFaults, isEditKeywordDetected)) { @@ -875,7 +875,7 @@ void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Coll return; } - qDebug() << "Reading faults from\n " << data.fileName(); + // qDebug() << "Reading faults from\n " << data.fileName(); RigFault* fault = NULL; diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index c957fc0f02..a80b547b0d 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -1039,7 +1039,7 @@ void caf::Viewer::updateParallelProjectionCameraPosFromPointOfInterestMove(const double orthoHeight = camera->frontPlaneFrustumHeight(); - Trace::show(String::number(orthoHeight)); + //Trace::show(String::number(orthoHeight)); double neededDistToFocusPlane = calculateDistToPlaneOfInterest(m_cameraFieldOfViewYDeg, orthoHeight); @@ -1052,7 +1052,7 @@ void caf::Viewer::updateParallelProjectionCameraPosFromPointOfInterestMove(const Vec3d newEye = eye + (existingDistToFocusPlane - neededDistToFocusPlane) * camDir; - Trace::show(String::number(newEye.x()) + ", " + String::number(newEye.y()) + ", " +String::number(newEye.z())); + //Trace::show(String::number(newEye.x()) + ", " + String::number(newEye.y()) + ", " +String::number(newEye.z())); camera->setFromLookAt(newEye, newEye + 10.0*camDir, up); } From 4d6deef8abdbed9e3eb8a528daf7542345904dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 11:25:55 +0100 Subject: [PATCH 265/290] (#708) Fixed simulation well geometry and color mapping. Had been sligtly off since 1.5.0. --- .../RigSimulationWellCenterLineCalculator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp index fdfd37cc49..3e797092b8 100644 --- a/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp +++ b/ApplicationCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp @@ -184,7 +184,7 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(RimEclip cvf::Vec3d outOfPrevCell(centerPreviousCell); - //int intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); + int intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); //CVF_ASSERT(intersectionOk); //CVF_ASSERT(intersectionOk); if ((currentPoint - outOfPrevCell).lengthSquared() > 1e-3) @@ -282,7 +282,7 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterline(RimEclip cvf::Vec3d outOfPrevCell(centerPreviousCell); const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell(*prevWellResPoint); - //bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); + bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); //CVF_ASSERT(intersectionOk); //CVF_ASSERT(intersectionOk); if ((intoThisCell - outOfPrevCell).lengthSquared() > 1e-3) From bd1aeaf840150005b5ca3b6225de40f94a3ca397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 11:28:46 +0100 Subject: [PATCH 266/290] Upped to 1.5.106-RC after fix of final(?) regression-test-detected bug. --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 71087b3d56..365aad8cb1 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 105) +set(CMAKE_PATCH_VERSION 106) set(DEV_VERSION "-RC") From 891bce069db8502dd9a94334b04424d8d3242a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 14:37:00 +0100 Subject: [PATCH 267/290] (#587) Fixed missing initialization. Will probably fix this issue --- Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h index cf0104d443..642d0e41eb 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h @@ -56,7 +56,7 @@ class PdmUiItemInfo { public: PdmUiItemInfo() - : m_editorTypeName(""), m_isHidden(-1), m_isChildrenHidden(-1), m_isReadOnly(-1) + : m_editorTypeName(""), m_isHidden(-1), m_isChildrenHidden(-1), m_isReadOnly(-1), m_labelAlignment(LEFT) {} PdmUiItemInfo( QString uiName, QIcon icon = QIcon(), QString toolTip = "", QString whatsThis = "") From 0650cfdce2659bebd565bcb15797ab83db3e938c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 14:52:00 +0100 Subject: [PATCH 268/290] Fixed uninitialized memory read detected by valgrind. --- Fwk/AppFwk/cafAnimControl/cafFrameAnimationControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/cafAnimControl/cafFrameAnimationControl.cpp b/Fwk/AppFwk/cafAnimControl/cafFrameAnimationControl.cpp index 71ec537a8c..4a38b238dc 100644 --- a/Fwk/AppFwk/cafAnimControl/cafFrameAnimationControl.cpp +++ b/Fwk/AppFwk/cafAnimControl/cafFrameAnimationControl.cpp @@ -71,8 +71,8 @@ FrameAnimationControl::FrameAnimationControl(QObject* parent) //-------------------------------------------------------------------------------------------------- void FrameAnimationControl::setDefault() { - setNumFrames(0); setCurrentFrame(0); + setNumFrames(0); setTimeout(TIMEOUT_DEFAULT); setForward(true); setRepeatFromStart(false); From 6267f82805dac5ee899aa085d7b4d04d5c5877bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Mon, 14 Dec 2015 15:32:00 +0100 Subject: [PATCH 269/290] Upped to 1.5.107-RC after fix of valgrind detected issues --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 365aad8cb1..b45988f64b 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 106) +set(CMAKE_PATCH_VERSION 107) set(DEV_VERSION "-RC") From cd4c9e6ee009b567d4fa49fe28f7d545a0104f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 15 Dec 2015 13:41:32 +0100 Subject: [PATCH 270/290] (#709) Invalid cells destroyed the intersection calculation for well log Omit the invalid cells from the calculation. --- .../ReservoirDataModel/RigEclipseWellLogExtractor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp index 5b7d458bb6..b994d24d80 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseWellLogExtractor.cpp @@ -70,6 +70,9 @@ void RigEclipseWellLogExtractor::calculateIntersection() for (size_t cIdx = 0; cIdx < closeCells.size(); ++cIdx) { const RigCell& cell = m_caseData->mainGrid()->globalCellArray()[closeCells[cIdx]]; + + if (cell.isInvalid()) continue; + const caf::SizeTArray8& cornerIndices = cell.cornerIndices(); hexCorners[0] = nodeCoords[cornerIndices[0]]; From 7737a713c5fc3fd19ddb9532986edcf4f5aa4dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 15 Dec 2015 13:50:59 +0100 Subject: [PATCH 271/290] Removed invalid cells from bbox search tree. Improving performance on startup and avoid possible stack exhaust error. --- ApplicationCode/ReservoirDataModel/RigMainGrid.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp index 705da96221..0c1038860b 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp @@ -474,6 +474,9 @@ void RigMainGrid::buildCellSearchTree() for (size_t cIdx = 0; cIdx < cellCount; ++cIdx) { const caf::SizeTArray8& cellIndices = m_cells[cIdx].cornerIndices(); + + if (m_cells[cIdx].isInvalid()) continue; + cvf::BoundingBox& cellBB = cellBoundingBoxes[cIdx]; cellBB.add(m_nodes[cellIndices[0]]); cellBB.add(m_nodes[cellIndices[1]]); From fc7721dc2027da1b8fa1f572372d97f77c01fbca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Tue, 15 Dec 2015 14:02:27 +0100 Subject: [PATCH 272/290] Upped to 1.5.108-RC after fixing #709 --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index b45988f64b..444eca7915 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 107) +set(CMAKE_PATCH_VERSION 108) set(DEV_VERSION "-RC") From 0a15ccf57703b3576eee5eea09d16d75e6e6cc13 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 16 Dec 2015 09:45:56 +0100 Subject: [PATCH 273/290] Fixed missing selection of well path in project tree when clicking on a well path in 3D view --- .../RicWellPathViewerEventHandler.cpp | 2 ++ .../UserInterface/RiuViewerCommands.cpp | 21 ------------------- .../UserInterface/RiuViewerCommands.h | 1 - 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp index e7cf8cd56f..84b5c45229 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathViewerEventHandler.cpp @@ -82,6 +82,8 @@ bool RicWellPathViewerEventHandler::handleEvent(cvf::Object* eventObject) RiuMainWindow::instance()->setResultInfo(wellPathText); + RiuMainWindow::instance()->selectAsCurrentItem(wellPathSourceInfo->wellPath()); + return true; } } diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 3371f1848a..81e5fd5e94 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -456,8 +456,6 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM return; } } - - updateSelectionFromPickedPart(firstHitPart); } if (firstHitPart && firstHitPart->sourceInfo()) @@ -706,25 +704,6 @@ void RiuViewerCommands::ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::updateSelectionFromPickedPart(cvf::Part* part) -{ - if (part && part->sourceInfo()) - { - const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(part->sourceInfo()); - if (wellPathSourceInfo) - { - RimWellPath* wellPath = wellPathSourceInfo->wellPath(); - if (wellPath) - { - RiuMainWindow::instance()->selectAsCurrentItem(wellPath); - } - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 32eaa27e4d..f087dc40a6 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -68,7 +68,6 @@ private slots: void ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size_t* i, size_t* j, size_t* k); void createSliceRangeFilter(int ijOrk); void extractIntersectionData(const cvf::HitItemCollection& hitItems, cvf::Vec3d* localIntersectionPoint, cvf::Part** firstPart, uint* firstPartFaceHit, cvf::Part** nncPart, uint* nncPartFaceHit); - void updateSelectionFromPickedPart(cvf::Part* part); bool handleOverlayItemPicking(int winPosX, int winPosY); From e8cf78c2afd088f13b8c95402b2a573004327a65 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 17 Dec 2015 14:40:01 +0100 Subject: [PATCH 274/290] (#710) Clamp currentFrameIndex to available frame indices --- Fwk/AppFwk/cafViewer/cafViewer.cpp | 80 +++++++++++++++++------------- Fwk/AppFwk/cafViewer/cafViewer.h | 6 ++- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index a80b547b0d..e38636188a 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -37,39 +37,36 @@ #include "cafViewer.h" +#include "cafCadNavigation.h" +#include "cafFrameAnimationControl.h" +#include "cafNavigationPolicy.h" + #include "cvfCamera.h" -#include "cvfRendering.h" -#include "cvfRenderSequence.h" +#include "cvfDebugTimer.h" +#include "cvfDrawable.h" +#include "cvfDrawableGeo.h" +#include "cvfHitItemCollection.h" +#include "cvfManipulatorTrackball.h" +#include "cvfModel.h" #include "cvfOpenGLResourceManager.h" +#include "cvfOverlayImage.h" +#include "cvfPart.h" +#include "cvfRay.h" +#include "cvfRayIntersectSpec.h" #include "cvfRenderQueueSorter.h" +#include "cvfRenderSequence.h" +#include "cvfRendering.h" #include "cvfScene.h" -#include "cvfModel.h" #include "cvfTextureImage.h" -#include "cvfOverlayImage.h" - -#include "cvfqtOpenGLContext.h" - -#include "cvfRay.h" -#include "cvfPart.h" -#include "cvfDrawable.h" -#include "cvfDrawableGeo.h" #include "cvfTransform.h" -#include "cvfRayIntersectSpec.h" -#include "cvfHitItemCollection.h" -#include "cvfManipulatorTrackball.h" -#include "cvfDebugTimer.h" +#include "cvfqtOpenGLContext.h" #include "cvfqtPerformanceInfoHud.h" #include "cvfqtUtils.h" -#include "cafNavigationPolicy.h" -#include "cafCadNavigation.h" -#include "cafFrameAnimationControl.h" - -#include -#include #include -#include "cvfTrace.h" +#include +#include std::list caf::Viewer::sm_viewers; cvf::ref caf::Viewer::sm_openGLContextGroup; @@ -593,17 +590,7 @@ void caf::Viewer::slotSetCurrentFrame(int frameIndex) { if (m_frameScenes.size() == 0) return; - int clampedFrameIndex = frameIndex; - - if (static_cast(frameIndex) >= m_frameScenes.size()) - { - clampedFrameIndex = static_cast(m_frameScenes.size()) - 1; - } - - if (clampedFrameIndex < 0) - { - clampedFrameIndex = 0; - } + int clampedFrameIndex = clampFrameIndex(frameIndex); if (m_frameScenes.at(clampedFrameIndex) == NULL) return; @@ -777,9 +764,13 @@ void caf::Viewer::enableForcedImmediateMode(bool enable) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int caf::Viewer::currentFrameIndex() +int caf::Viewer::currentFrameIndex() const { - if (m_animationControl) return m_animationControl->currentFrame(); + if (m_animationControl) + { + int clampedFrameIndex = clampFrameIndex(m_animationControl->currentFrame()); + return clampedFrameIndex; + } else return 0; } @@ -1057,3 +1048,22 @@ void caf::Viewer::updateParallelProjectionCameraPosFromPointOfInterestMove(const } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int caf::Viewer::clampFrameIndex(int frameIndex) const +{ + size_t clampedFrameIndex = static_cast(frameIndex); + + if (clampedFrameIndex >= frameCount()) + { + clampedFrameIndex = frameCount() - 1; + } + else if (clampedFrameIndex < 0) + { + clampedFrameIndex = 0; + } + + return static_cast(clampedFrameIndex); +} + diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 8681294b52..be6c071e29 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -91,9 +91,10 @@ class Viewer : public caf::OpenGLWidget // Frame scenes for animation control void addFrame(cvf::Scene* scene); - size_t frameCount() { return m_frameScenes.size(); } + size_t frameCount() const { return m_frameScenes.size(); } cvf::Scene* frame(size_t frameIndex); void removeAllFrames(); + int currentFrameIndex() const; // Static models to be shown in all frames void addStaticModelOnce(cvf::Model* model); @@ -152,7 +153,6 @@ class Viewer : public caf::OpenGLWidget public slots: virtual void slotSetCurrentFrame(int frameIndex); virtual void slotEndAnimation(); - int currentFrameIndex(); public: virtual QSize sizeHint() const; @@ -196,6 +196,8 @@ public slots: void releaseOGlResourcesForCurrentFrame(); void debugShowRenderingSequencePartNames(); + int clampFrameIndex(int frameIndex) const; + bool m_showPerfInfoHud; size_t m_paintCounter; bool m_releaseOGLResourcesEachFrame; From 72459a339ff8a4a5f92582629f50cdd29fd5e0af Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Thu, 17 Dec 2015 14:51:16 +0100 Subject: [PATCH 275/290] Upped to 1.5.109-RC --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 444eca7915..b77aea90aa 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 108) +set(CMAKE_PATCH_VERSION 109) set(DEV_VERSION "-RC") From b9286dcd1d31285f65256c0727dc14a26efd5649 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 11:10:50 +0100 Subject: [PATCH 276/290] [AppFwk] Updated destructors in unit tests to make sure memory is released correctly --- .../cafPdmCore/cafPdmCore_UnitTests/Child.cpp | 1 + .../cafPdmCore/cafPdmCore_UnitTests/Parent.cpp | 2 ++ .../cafPdmChildArrayFieldHandleTest.cpp | 1 + .../cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp | 5 +++++ .../cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp | 11 +++++++++++ .../cafPdmBasicTest.cpp | 13 +++++++++++++ 6 files changed, 33 insertions(+) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Child.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Child.cpp index 9dd5e981fd..202bc77c51 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Child.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Child.cpp @@ -8,4 +8,5 @@ Child::Child() Child::~Child() { + delete m_testObj(); } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Parent.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Parent.cpp index 7f1d6fd2d1..50b9a6fdfc 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Parent.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/Parent.cpp @@ -11,6 +11,8 @@ Parent::Parent() Parent::~Parent() { + delete m_simpleObjectF(); + m_simpleObjectsField.deleteAllChildObjects(); } void Parent::doSome() diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmChildArrayFieldHandleTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmChildArrayFieldHandleTest.cpp index 0a85d52856..93465d7fad 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmChildArrayFieldHandleTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmChildArrayFieldHandleTest.cpp @@ -64,6 +64,7 @@ class ContainerObj : public caf::PdmObjectHandle ~ContainerObj() { derivedObjs.deleteAllChildObjects(); + derivedOtherObjs.deleteAllChildObjects(); } caf::PdmChildArrayField derivedObjs; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp index 6306af2b72..0c4dddf18c 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmCoreBasicTest.cpp @@ -436,6 +436,11 @@ TEST(BaseTest, PdmChildField) public: A(Child* a) :field2(a) {} + ~A() + { + delete field2(); + } + caf::PdmChildField field2; int b; }; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp index 9763036182..ed388c2496 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp @@ -176,6 +176,11 @@ class InheritedDemoObj : public DemoPdmObject CAF_PDM_XML_InitField(&m_childArrayField, "DemoPdmObjectects"); } + ~InheritedDemoObj() + { + m_childArrayField.deleteAllChildObjects(); + } + caf::PdmDataValueField m_texts; caf::PdmChildArrayField m_childArrayField; @@ -220,6 +225,12 @@ class ReferenceDemoPdmObject : public caf::PdmObjectHandle, public caf::PdmXmlOb CAF_PDM_XML_InitField(&m_simpleObjPtrField2, "SimpleObjPtrField2"); } + ~ReferenceDemoPdmObject() + { + delete m_pointersField(); + m_simpleObjPtrField2.deleteAllChildObjects(); + } + // Fields caf::PdmChildField m_pointersField; caf::PdmChildArrayField m_simpleObjPtrField2; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp index e28b2f6b5b..27ac4227fc 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp @@ -140,6 +140,7 @@ class DemoPdmObject: public caf::PdmObject ~DemoPdmObject() { + delete m_simpleObjPtrField(); delete m_simpleObjPtrField2(); } @@ -174,6 +175,11 @@ class InheritedDemoObj : public DemoPdmObject } + ~InheritedDemoObj() + { + m_simpleObjectsField.deleteAllChildObjects(); + } + caf::PdmField > m_texts; caf::PdmField< caf::AppEnum > m_testEnumField; caf::PdmChildArrayField m_simpleObjectsField; @@ -192,6 +198,11 @@ class MyPdmDocument : public caf::PdmDocument CAF_PDM_InitFieldNoDefault(&objects, "PdmObjects", "", "", "", "") } + ~MyPdmDocument() + { + objects.deleteAllChildObjects(); + } + caf::PdmChildArrayField objects; }; @@ -519,6 +530,8 @@ TEST(BaseTest, ReadWrite) EXPECT_EQ(size_t(1), demoObjs.size()); } + d2->m_simpleObjPtrField = NULL; + xmlDoc.objects.deleteAllChildObjects(); } { From ed3951fd0d2e3fc0399b6d5ec692bfc776c85fba Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 11:41:11 +0100 Subject: [PATCH 277/290] [AppFwk] Added CMakefile used to test AppFwk --- Fwk/AppFwk/CMakeLists.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Fwk/AppFwk/CMakeLists.txt diff --git a/Fwk/AppFwk/CMakeLists.txt b/Fwk/AppFwk/CMakeLists.txt new file mode 100644 index 0000000000..0f839543f3 --- /dev/null +++ b/Fwk/AppFwk/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 2.8) + +project (CeeApp) + + +find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) +include (${QT_USE_FILE}) + + +#libraries +add_subdirectory (cafProjectDataModel/cafPdmCore) +add_subdirectory (cafProjectDataModel/cafPdmUiCore) +add_subdirectory (cafProjectDataModel/cafPdmXml) + +add_subdirectory(cafProjectDataModel) +add_subdirectory(cafCommand) +add_subdirectory(cafUserInterface) + +#executables +add_subdirectory(cafTests/cafTestApplication) + +add_subdirectory (cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests) +add_subdirectory (cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) +add_subdirectory (cafProjectDataModel/cafProjectDataModel_UnitTests) + +# Organize sub-projects into folders on Visual Studio +# Turn on using solution folders +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +set_property(TARGET cafPdmCore cafPdmCore_UnitTests cafPdmXml cafPdmXml_UnitTests cafPdmUiCore PROPERTY FOLDER "PdmCore") + From 33c53830f6daeda162ac70e7dfb3e89e1e1a254c Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 13:00:13 +0100 Subject: [PATCH 278/290] [Fwk] Integrated improvements to command mananger --- .../cafCommand/cafCmdExecCommandManager.cpp | 45 +++++++++++++------ .../cafCommand/cafCmdExecCommandManager.h | 33 +++++++++++--- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.cpp b/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.cpp index b307849681..7ed84b8a39 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.cpp +++ b/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.cpp @@ -114,8 +114,17 @@ void CmdExecCommandManager::activateCommandSystem() if (!m_commandFeatureInterface) { m_commandFeatureInterface = new CmdUiCommandSystemImpl; - PdmUiCommandSystemProxy::instance()->setCommandInterface(m_commandFeatureInterface); } + + PdmUiCommandSystemProxy::instance()->setCommandInterface(m_commandFeatureInterface); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void CmdExecCommandManager::deactivateCommandSystem() +{ + PdmUiCommandSystemProxy::instance()->setCommandInterface(NULL); } //-------------------------------------------------------------------------------------------------- @@ -141,18 +150,7 @@ QUndoStack* CmdExecCommandManager::undoStack() //-------------------------------------------------------------------------------------------------- void CmdExecCommandManager::processExecuteCommand(CmdExecuteCommand* executeCommand) { - bool useUndo = false; - - if (dynamic_cast(executeCommand) && m_commandFeatureInterface->disableUndoForFieldChange()) - { - useUndo = false; - } - else if (m_commandFeatureInterface && m_commandFeatureInterface->isUndoEnabled()) - { - useUndo = true; - } - - if (useUndo) + if (isUndoEnabledForCurrentCommand(executeCommand)) { // Transfer ownership of execute command to wrapper object UndoRedoWrapper* undoRedoWrapper = new UndoRedoWrapper(executeCommand); @@ -178,7 +176,7 @@ void CmdExecCommandManager::processExecuteCommandsAsMacro(const QString& macroNa return; } - if (m_commandFeatureInterface && m_commandFeatureInterface->isUndoEnabled()) + if (isUndoEnabledForCurrentCommand(commands[0])) { m_undoStack->beginMacro(macroName); for (size_t i = 0; i < commands.size(); i++) @@ -202,5 +200,24 @@ void CmdExecCommandManager::processExecuteCommandsAsMacro(const QString& macroNa } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool CmdExecCommandManager::isUndoEnabledForCurrentCommand(CmdExecuteCommand* command) +{ + bool useUndo = false; + + if (dynamic_cast(command) && m_commandFeatureInterface->disableUndoForFieldChange()) + { + useUndo = false; + } + else if (m_commandFeatureInterface && m_commandFeatureInterface->isUndoEnabled()) + { + useUndo = true; + } + + return useUndo; +} + } // end namespace caf diff --git a/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.h b/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.h index 649e554c89..eecc4bb20b 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.h +++ b/Fwk/AppFwk/cafCommand/cafCmdExecCommandManager.h @@ -55,12 +55,6 @@ class CmdExecCommandManager public: static CmdExecCommandManager* instance(); - // Creates the object (CmdUiCommandSystemImpl) used to communicate from UI editors to advanced parts of the command system - // This includes support for undo system and default command features for add/delete of items in PdmChildArrayFieldHandle - // and creation of field changed commands so a change in an editor can be put into undo/redo - // CmdUiCommandSystemImpl is a requirement for using the undo system - void activateCommandSystem(); - // When the undoFeature is enabled, execute commands are inserted in the undo stack // The application can use the QUndoStack to display/modify execute commands wrapped in QUndoCommand objects void enableUndoCommandSystem(bool enable); @@ -75,12 +69,39 @@ class CmdExecCommandManager private: CmdExecCommandManager(); + // Creates the object (CmdUiCommandSystemImpl) used to communicate from UI editors to advanced parts of the command system + // This includes support for undo system and default command features for add/delete of items in PdmChildArrayFieldHandle + // and creation of field changed commands so a change in an editor can be put into undo/redo + // CmdUiCommandSystemImpl is a requirement for using the undo system + void activateCommandSystem(); + void deactivateCommandSystem(); + + bool isUndoEnabledForCurrentCommand(CmdExecuteCommand* command); + + friend class CmdExecCommandSystemDeactivator; + private: QUndoStack* m_undoStack; CmdUiCommandSystemImpl* m_commandFeatureInterface; }; +//================================================================================================== +/// Helper class used to temporarily disable the command system including undo/redo functionality +//================================================================================================== +class CmdExecCommandSystemDeactivator +{ +public: + CmdExecCommandSystemDeactivator() + { + CmdExecCommandManager::instance()->deactivateCommandSystem(); + } + + ~CmdExecCommandSystemDeactivator() + { + CmdExecCommandManager::instance()->activateCommandSystem(); + } +}; } // end namespace caf From 390b04be3be88c17346869b4b4cbeeaf2cf8b13a Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 13:32:48 +0100 Subject: [PATCH 279/290] [Fwk] Fixed typo --- Fwk/AppFwk/CommonCode/cafEffectGenerator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h index 3854e0c254..fc5a2ec63f 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h @@ -255,7 +255,7 @@ class MeshEffectGenerator : public EffectGenerator //================================================================================================== // -// MeshEffectGenerator +// TextEffectGenerator // //================================================================================================== class TextEffectGenerator : public EffectGenerator From 5296add1cb29e06b299596fb455305b09717a6f9 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 14:10:50 +0100 Subject: [PATCH 280/290] [Fwk] Fix for missing use of command framework for tree view model --- Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp | 2 +- Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp index 1070ca1279..35a053a93a 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp @@ -241,7 +241,7 @@ class DemoPdmObject: public caf::PdmObject CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want" ); CAF_PDM_InitField(&m_boolField, "BooleanValue", false, "Boolean:" , "", "Boolean:Enter some small number here", "Boolean:This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString("Demo Object Description Field"), "", "", "", ""); + CAF_PDM_InitField(&m_textField, "TextField", QString("Demo Object Description Field"), "Description Field", "", "", ""); CAF_PDM_InitField(&m_filePath, "FilePath", QString(""), "Filename", "", "", ""); CAF_PDM_InitField(&m_longText, "LongText", QString("Test text"), "Long Text", "", "", ""); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp index e38a6bdf61..b0146df257 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeViewModel.cpp @@ -39,6 +39,7 @@ #include "cafPdmField.h" #include "cafPdmObject.h" +#include "cafPdmUiCommandSystemProxy.h" #include "cafPdmUiDragDropInterface.h" #include "cafPdmUiTreeItemEditor.h" #include "cafPdmUiTreeOrdering.h" @@ -684,7 +685,7 @@ bool PdmUiTreeViewModel::setData(const QModelIndex &index, const QVariant &value PdmUiFieldHandle* userDescriptionUiField = uiObject->userDescriptionField()->uiCapability(); if (userDescriptionUiField) { - userDescriptionUiField->setValueFromUi(value); + PdmUiCommandSystemProxy::instance()->setUiValueToField(userDescriptionUiField, value); } return true; @@ -698,7 +699,7 @@ bool PdmUiTreeViewModel::setData(const QModelIndex &index, const QVariant &value PdmUiFieldHandle* toggleUiField = uiObject->objectToggleField()->uiCapability(); if (toggleUiField) { - toggleUiField->setValueFromUi(value); + PdmUiCommandSystemProxy::instance()->setUiValueToField(toggleUiField, toggleOn); } return true; From f00ecd9a5ae999efe4cc5a90dd23849f6c6f75f3 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 22 Dec 2015 15:00:27 +0100 Subject: [PATCH 281/290] System : Include runtime dlls on Windows msvcp/msvcr/vcomp is now included in the install package on Windows --- ApplicationCode/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 218ce46306..46fdebb4bf 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -505,6 +505,12 @@ if (RESINSIGHT_PRIVATE_INSTALL) set (RESINSIGHT_FILES ${RESINSIGHT_FILES} ${RI_ALL_ODB_DLLS}) endif() + # CRT + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP ON) + set(CMAKE_INSTALL_OPENMP_LIBRARIES ON) + include(InstallRequiredSystemLibraries) + install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ${RESINSIGHT_FINAL_NAME}) + endif() set (RESINSIGHT_FILES ${RESINSIGHT_FILES} ${RESINSIGHT_LICENSE_FILES}) From 1c4c1d254e413dd3715558aaf7cb77c528c2de1f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 6 Jan 2016 23:01:27 +0100 Subject: [PATCH 282/290] (#711) Use most recent activated Eclipse view if a well log plot is active Octave scripts must have an Eclipse view to communicate with. If a WLP is active, evaluate recently used views to find the most recently Eclipse view used. --- .../SocketInterface/RiaSocketServer.cpp | 54 ++++++++++++------- .../UserInterface/RiuMainWindow.cpp | 8 +++ ApplicationCode/UserInterface/RiuMainWindow.h | 3 +- 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/ApplicationCode/SocketInterface/RiaSocketServer.cpp b/ApplicationCode/SocketInterface/RiaSocketServer.cpp index 04fac0bcc6..e27a4661e6 100644 --- a/ApplicationCode/SocketInterface/RiaSocketServer.cpp +++ b/ApplicationCode/SocketInterface/RiaSocketServer.cpp @@ -22,35 +22,37 @@ #include "RiaSocketCommand.h" #include "RiaSocketTools.h" -#include -#include - -#include - #include "RiaApplication.h" -#include "RiuMainWindow.h" -#include "RimEclipseView.h" -#include "RimProject.h" -#include "RimEclipseCase.h" -#include "RimEclipseCellColors.h" +#include "RigCaseCellResultsData.h" +#include "RigCaseData.h" +#include "RigGridBase.h" + +#include "Rim3dOverlayInfoConfig.h" +#include "RimCaseCollection.h" #include "RimCellEdgeColors.h" #include "RimCellRangeFilterCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCaseCollection.h" +#include "RimEclipseCellColors.h" #include "RimEclipsePropertyFilterCollection.h" +#include "RimEclipseView.h" #include "RimEclipseWellCollection.h" -#include "Rim3dOverlayInfoConfig.h" #include "RimIdenticalGridCaseGroup.h" -#include "RimScriptCollection.h" -#include "RimCaseCollection.h" +#include "RimOilField.h" +#include "RimProject.h" #include "RimReservoirCellResultsStorage.h" +#include "RimScriptCollection.h" -#include "RigCaseData.h" -#include "RigCaseCellResultsData.h" +#include "RiuMainWindow.h" +#include "RiuViewer.h" #include "cafFactory.h" -#include "RigGridBase.h" -#include "RimOilField.h" -#include "RimEclipseCaseCollection.h" + +#include +#include + +#include //-------------------------------------------------------------------------------------------------- @@ -155,6 +157,22 @@ RimEclipseCase* RiaSocketServer::findReservoir(int caseId) { return riv->eclipseCase(); } + + // If the active mdi window is different from an Eclipse view, search through available mdi windows to find the last activated + // Eclipse view. The sub windows are returned with the most recent activated window at the back. + QList subWindows = RiuMainWindow::instance()->subWindowList(QMdiArea::ActivationHistoryOrder); + for (int i = subWindows.size() - 1; i > -1; i--) + { + RiuViewer* viewer = subWindows[i]->widget()->findChild(); + if (viewer) + { + RimEclipseView* riv = dynamic_cast(viewer->ownerReservoirView()); + if (riv) + { + return riv->eclipseCase(); + } + } + } } else { diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index c89a57062b..cc6283c46b 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1167,6 +1167,14 @@ QMdiSubWindow* RiuMainWindow::findMdiSubWindow(QWidget* viewer) return NULL; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RiuMainWindow::subWindowList(QMdiArea::WindowOrder order) +{ + return m_mdiArea->subWindowList(order); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index c4215b4229..b6dbb8fc6c 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -23,6 +23,7 @@ #include #include #include +#include class QActionGroup; class QComboBox; @@ -30,7 +31,6 @@ class QFrame; class QItemSelection; class QLabel; class QLineEdit; -class QMdiArea; class QMdiSubWindow; class QSpinBox; class QTreeView; @@ -112,6 +112,7 @@ class RiuMainWindow : public QMainWindow void tileWindows(); bool isAnyMdiSubWindowVisible(); QMdiSubWindow* findMdiSubWindow(QWidget* viewer); + QList subWindowList(QMdiArea::WindowOrder order); RiuResultQwtPlot* resultPlot(); From 0e8191d6ebb7dcde5ab5e94cc0c277a7ca2e6224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 7 Jan 2016 14:24:59 +0100 Subject: [PATCH 283/290] (#712) Set well head connection status to closed always as they are no part of the connection table in Eclipse This to remedy that ERT returns open as connection status for well heads. --- ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp index 2ae9551118..1d6334e8d5 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp @@ -1179,6 +1179,10 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid, boo if (ert_wellhead) { wellResFrame.m_wellHead = createWellResultPoint(grids[gridNr], ert_wellhead, -1, -1 ); + + // HACK: Ert returns open as "this is equally wrong as closed for well heads". + // Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016 + wellResFrame.m_wellHead.m_isOpen = false; break; } } @@ -1528,6 +1532,10 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid, boo if (ert_wellhead) { wellResFrame.m_wellHead = createWellResultPoint(grids[gridNr], ert_wellhead, -1, -1 ); + // HACK: Ert returns open as "this is equally wrong as closed for well heads". + // Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016 + wellResFrame.m_wellHead.m_isOpen = false; + //std::cout << "Wellhead YES at timeIdx: " << timeIdx << " wellIdx: " << wellIdx << " Grid: " << gridNr << std::endl; } else From cc9f20e912dd2bc5fab095573bbf48d32f340372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Thu, 7 Jan 2016 14:25:40 +0100 Subject: [PATCH 284/290] Upped to version 1.5.110-RC --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index b77aea90aa..8516063c98 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 109) +set(CMAKE_PATCH_VERSION 110) set(DEV_VERSION "-RC") From 7b24b3a96b4e81e4b608d02fb07b88ed0e8e20c4 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 8 Jan 2016 09:25:17 +0100 Subject: [PATCH 285/290] (#713) Removed temporary workaround for NNC data import in ECLIPSE 2015 --- ThirdParty/Ert/devel/libecl/src/ecl_grid.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ThirdParty/Ert/devel/libecl/src/ecl_grid.c b/ThirdParty/Ert/devel/libecl/src/ecl_grid.c index 0f41998c79..9c73783e56 100644 --- a/ThirdParty/Ert/devel/libecl/src/ecl_grid.c +++ b/ThirdParty/Ert/devel/libecl/src/ecl_grid.c @@ -2287,10 +2287,6 @@ static void ecl_grid_init_nnc(ecl_grid_type * main_grid, ecl_file_type * ecl_fil int num_nnchead_kw = ecl_file_get_num_named_kw( ecl_file , NNCHEAD_KW ); int i; - if(num_nnchead_kw > 0 && main_grid->eclipse_version == 2015){ - return; //Eclipse 2015 has an error with nnc. - } - for (i = 0; i < num_nnchead_kw; i++) { ecl_file_push_block(ecl_file); /* <---------------------------------------------------------------- */ ecl_file_select_block(ecl_file , NNCHEAD_KW , i); From d4ec42e9a29fa1bb9eaaeb599e4de2a0b9d274cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 10 Jan 2016 21:31:54 +0100 Subject: [PATCH 286/290] (#712) Made a possible well cell connection in the wellhead control the connection color of the well pipe. --- .../RigSingleWellResultsData.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp index 3b178eb0cb..b3af8e7f06 100644 --- a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.cpp @@ -283,11 +283,6 @@ const RigWellResultPoint* RigWellResultFrame::findResultCell(size_t gridIndex, s { CVF_ASSERT(gridIndex != cvf::UNDEFINED_SIZE_T && gridCellIndex != cvf::UNDEFINED_SIZE_T); - if (m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex ) - { - return &m_wellHead; - } - for (size_t wb = 0; wb < m_wellResultBranches.size(); ++wb) { for (size_t wc = 0; wc < m_wellResultBranches[wb].m_branchResultPoints.size(); ++wc) @@ -300,5 +295,14 @@ const RigWellResultPoint* RigWellResultFrame::findResultCell(size_t gridIndex, s } } + // If we could not find the cell among the real connections, we try the wellhead. + // The wellhead does however not have a real connection state, and is thereby always rendered as closed + // If we have a real connection in the wellhead, we should not end here. See Github issue #712 + + if (m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex ) + { + return &m_wellHead; + } + return NULL; } From f7d5d9202959140b6e782ba198f27c3f15fed998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20St=C3=B8ren?= Date: Sun, 10 Jan 2016 21:39:30 +0100 Subject: [PATCH 287/290] Upped to version 1.5.111-RC after fixing #712 --- ResInsightVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 8516063c98..73fefd142b 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,7 +1,7 @@ set(CMAKE_MAJOR_VERSION 1) set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 110) +set(CMAKE_PATCH_VERSION 111) set(DEV_VERSION "-RC") From 5fb04e95266eda026bfc383b2d75f7e4b3dae46f Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 11 Jan 2016 07:59:44 +0100 Subject: [PATCH 288/290] [System] Added support for display of regression images on top of each other in regression report Use a slider concept (using CSS) to switch between generated and base image --- .../Application/RiaApplication.cpp | 13 +++ .../Application/RiaImageCompareReporter.cpp | 84 ++++++++++++++++++- .../Application/RiaImageCompareReporter.h | 8 ++ .../Application/RiaRegressionTest.cpp | 2 + .../Application/RiaRegressionTest.h | 1 + 5 files changed, 106 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index a6577f6890..950b5b3892 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -1757,6 +1757,19 @@ void RiaApplication::runRegressionTest(const QString& testRootPath) RiaImageCompareReporter imageCompareReporter; + // Minor workaround + // Use registry to define if interactive diff images should be created + // Defined by user in RiaRegressionTest + { + QSettings settings; + + bool useInteractiveDiff = settings.value("showInteractiveDiffImages").toBool(); + if (useInteractiveDiff) + { + imageCompareReporter.showInteractiveOnly(); + } + } + for (int dirIdx = 0; dirIdx < folderList.size(); ++dirIdx) { QDir testCaseFolder(folderList[dirIdx].filePath()); diff --git a/ApplicationCode/Application/RiaImageCompareReporter.cpp b/ApplicationCode/Application/RiaImageCompareReporter.cpp index c3ec958414..cf140fe3ab 100644 --- a/ApplicationCode/Application/RiaImageCompareReporter.cpp +++ b/ApplicationCode/Application/RiaImageCompareReporter.cpp @@ -23,6 +23,9 @@ RiaImageCompareReporter::RiaImageCompareReporter(void) { + m_showOriginal = true; + m_showGenerated = true; + m_showInteractiveDiff = false; } @@ -68,6 +71,12 @@ void RiaImageCompareReporter::generateHTMLReport(const std::string& fileName) html += "\n"; html += "\n"; html += "Regression-Test Report\n"; + + if (m_showInteractiveDiff) + { + html += cssString(); + } + html += "\n"; html += "\n"; html += "\n"; @@ -93,8 +102,21 @@ void RiaImageCompareReporter::generateHTMLReport(const std::string& fileName) html += " \n"; html += "
\n"; - html += " \n"; - html += " \n"; + if (m_showOriginal) + { + html += " \n"; + } + + if (m_showGenerated) + { + html += " \n"; + } + + if (m_showInteractiveDiff) + { + html += " \n"; + } + html += " \n"; html += " \n"; @@ -110,6 +132,16 @@ void RiaImageCompareReporter::generateHTMLReport(const std::string& fileName) output << html; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaImageCompareReporter::showInteractiveOnly() +{ + m_showOriginal = false; + m_showGenerated = false; + m_showInteractiveDiff = true; +} + //-------------------------------------------------------------------------------------------------- /// Retuns the names of the *.png files in a directory. The names are without path, but with extention //-------------------------------------------------------------------------------------------------- @@ -133,3 +165,51 @@ std::vector RiaImageCompareReporter::getPngFilesInDirectory(const s return fileNames; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::string RiaImageCompareReporter::cssString() const +{ + std::string html; + + html += ""; + + return html; +} diff --git a/ApplicationCode/Application/RiaImageCompareReporter.h b/ApplicationCode/Application/RiaImageCompareReporter.h index 01afad29cd..e580a55a52 100644 --- a/ApplicationCode/Application/RiaImageCompareReporter.h +++ b/ApplicationCode/Application/RiaImageCompareReporter.h @@ -30,10 +30,14 @@ class RiaImageCompareReporter void addImageDirectoryComparisonSet(const std::string& title, const std::string& baseImageDir, const std::string& newImagesDir, const std::string& diffImagesDir ); void generateHTMLReport(const std::string& filenName); + void showInteractiveOnly(); + private: static std::vector getPngFilesInDirectory(const std::string& searchPath); + std::string cssString() const; +private: struct DirSet { DirSet(const std::string& title, const std::string& baseImageDir, const std::string& newImagesDir, const std::string& diffImagesDir ) @@ -50,5 +54,9 @@ class RiaImageCompareReporter }; std::vector m_directorySets; + + bool m_showOriginal; + bool m_showGenerated; + bool m_showInteractiveDiff; }; diff --git a/ApplicationCode/Application/RiaRegressionTest.cpp b/ApplicationCode/Application/RiaRegressionTest.cpp index 9fb9377b65..f05e1f28e6 100644 --- a/ApplicationCode/Application/RiaRegressionTest.cpp +++ b/ApplicationCode/Application/RiaRegressionTest.cpp @@ -32,6 +32,8 @@ RiaRegressionTest::RiaRegressionTest(void) CAF_PDM_InitFieldNoDefault(®ressionTestFolder, "regressionTestFolder", "Regression Test Folder", "", "", ""); regressionTestFolder.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&showInteractiveDiffImages, "showInteractiveDiffImages", false, "Interactive diff images", "", "", ""); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/RiaRegressionTest.h b/ApplicationCode/Application/RiaRegressionTest.h index daa941dc61..9462c626e9 100644 --- a/ApplicationCode/Application/RiaRegressionTest.h +++ b/ApplicationCode/Application/RiaRegressionTest.h @@ -35,6 +35,7 @@ class RiaRegressionTest : public caf::PdmObject public: caf::PdmField applicationWorkingFolder; caf::PdmField regressionTestFolder; + caf::PdmField showInteractiveDiffImages; protected: virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute); From 4476e608166df4c0c3b7f7cfcd8004ed4ebb3e45 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 11 Jan 2016 09:23:09 +0100 Subject: [PATCH 289/290] Set version number to 1.6.0 for release --- ResInsightVersion.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 73fefd142b..02f067d341 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,8 +1,8 @@ set(CMAKE_MAJOR_VERSION 1) -set(CMAKE_MINOR_VERSION 5) -set(CMAKE_PATCH_VERSION 111) -set(DEV_VERSION "-RC") +set(CMAKE_MINOR_VERSION 6) +set(CMAKE_PATCH_VERSION 0) +#set(DEV_VERSION "-RC") # https://github.com/CRAVA/crava/tree/master/libs/nrlib From cb16f3c3222148eefdbd3de36fc49bdd82223714 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Mon, 11 Jan 2016 09:23:09 +0100 Subject: [PATCH 290/290] Fixed issues when loading Odb-projects into ResInsight with no Odb support --- .../GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp | 2 +- ApplicationCode/ProjectDataModel/RimViewController.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp index ba58d3d236..f15c8bb79d 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechVizLogic.cpp @@ -114,7 +114,7 @@ void RivGeoMechVizLogic::scheduleGeometryRegen(RivCellSetEnum geometryType) this->scheduleRegenOfDirectlyDependentGeometry(geometryType); int frameCount = 0; - if (m_geomechView->geoMechCase()->geoMechData()) + if (m_geomechView->geoMechCase() && m_geomechView->geoMechCase()->geoMechData()) { frameCount = m_geomechView->geoMechCase()->geoMechData()->femPartResults()->frameCount(); } diff --git a/ApplicationCode/ProjectDataModel/RimViewController.cpp b/ApplicationCode/ProjectDataModel/RimViewController.cpp index b177d98674..f1ad0f2f3b 100644 --- a/ApplicationCode/ProjectDataModel/RimViewController.cpp +++ b/ApplicationCode/ProjectDataModel/RimViewController.cpp @@ -785,7 +785,7 @@ bool RimViewController::isRangeFilterMappingApliccable() if (eclipseView && geomView) { - if (eclipseView->eclipseCase()->reservoirData() && geomView->geoMechCase()->geoMechData()) + if (eclipseView->eclipseCase()->reservoirData() && geomView->geoMechCase() && geomView->geoMechCase()->geoMechData()) { RigMainGrid* eclGrid = eclipseView->eclipseCase()->reservoirData()->mainGrid(); RigFemPart* femPart = geomView->geoMechCase()->geoMechData()->femParts()->part(0);
Min P10 Mean P90 Max
%1 %2 %3 %4 %5
\"" \"" \"" \""
\""