chart2/source/inc/BaseCoordinateSystem.hxx             |    6 
 chart2/source/inc/ExplicitCategoriesProvider.hxx       |    3 
 chart2/source/model/main/BaseCoordinateSystem.cxx      |    8 +
 chart2/source/tools/AxisHelper.cxx                     |    3 
 chart2/source/tools/ExplicitCategoriesProvider.cxx     |  118 +++++++++--------
 chart2/source/view/axes/VCartesianCoordinateSystem.cxx |    2 
 chart2/source/view/axes/VCoordinateSystem.cxx          |   10 -
 chart2/source/view/axes/VPolarCoordinateSystem.cxx     |    2 
 chart2/source/view/inc/VCoordinateSystem.hxx           |    5 
 chart2/source/view/main/ChartView.cxx                  |    2 
 chart2/source/view/main/SeriesPlotterContainer.cxx     |   16 +-
 chart2/source/view/main/SeriesPlotterContainer.hxx     |    2 
 12 files changed, 93 insertions(+), 84 deletions(-)

New commits:
commit eeb8ca44ac7994c0552749e190a193a44c956769
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Fri Apr 4 10:02:06 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Apr 4 17:49:31 2025 +0200

    tdf#147874 slow sheet switching with large chart2 (2)
    
    ExplicitCategoriesProvider is rather expensive to create, and we do it
    twice.
    
    So store it on the BaseCoordinateSystem object and share it, which means
    we only need to construct it once.
    
    This reduces switching time from 2s to 1s.
    
    Note that I am not sure that this is the best location to store this,
    the entire architecture of chart2 is a little opaque.
    
    Change-Id: Ic9dc9573f7495bcb76de14caa7cc7d5ad61d9ed1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183700
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/chart2/source/inc/BaseCoordinateSystem.hxx 
b/chart2/source/inc/BaseCoordinateSystem.hxx
index 71f226abcd51..e9e6f095c541 100644
--- a/chart2/source/inc/BaseCoordinateSystem.hxx
+++ b/chart2/source/inc/BaseCoordinateSystem.hxx
@@ -33,6 +33,8 @@ namespace chart
 {
 class Axis;
 class ChartType;
+class ExplicitCategoriesProvider;
+class ChartModel;
 
 namespace impl
 {
@@ -100,6 +102,8 @@ public:
     void setChartTypes( const std::vector< rtl::Reference< ::chart::ChartType 
> >& aChartTypes );
     const std::vector< rtl::Reference<::chart::ChartType > > & 
getChartTypes2() const { return m_aChartTypes; }
 
+    ExplicitCategoriesProvider& getExplicitCategoriesProvider(ChartModel& 
rModel);
+
 protected:
 
     // ____ XModifyListener ____
@@ -122,6 +126,8 @@ private:
     typedef std::vector< std::vector< rtl::Reference< ::chart::Axis > > > 
tAxisVecVecType;
     tAxisVecVecType m_aAllAxis; //outer sequence is the dimension; inner 
sequence is the axis index that indicates main or secondary axis
     std::vector< rtl::Reference<::chart::ChartType > >          m_aChartTypes;
+    // cache this here so we can share it across different parts of the code, 
it is expensive to create
+    std::unique_ptr<ExplicitCategoriesProvider> mxExplicitCategoriesProvider;
 };
 
 } //  namespace chart
diff --git a/chart2/source/model/main/BaseCoordinateSystem.cxx 
b/chart2/source/model/main/BaseCoordinateSystem.cxx
index 31473161e54e..607c04af0073 100644
--- a/chart2/source/model/main/BaseCoordinateSystem.cxx
+++ b/chart2/source/model/main/BaseCoordinateSystem.cxx
@@ -24,6 +24,7 @@
 #include <ModifyListenerHelper.hxx>
 #include <Axis.hxx>
 #include <ChartType.hxx>
+#include <ExplicitCategoriesProvider.hxx>
 #include <com/sun/star/chart2/AxisType.hpp>
 #include <com/sun/star/container/NoSuchElementException.hpp>
 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
@@ -318,6 +319,13 @@ void BaseCoordinateSystem::setChartTypes( const 
std::vector< rtl::Reference< Cha
     fireModifyEvent();
 }
 
+ExplicitCategoriesProvider& 
BaseCoordinateSystem::getExplicitCategoriesProvider(ChartModel& rModel)
+{
+    if (!mxExplicitCategoriesProvider)
+        mxExplicitCategoriesProvider = 
std::make_unique<ExplicitCategoriesProvider>(this, rModel);
+    return *mxExplicitCategoriesProvider;
+}
+
 // ____ XModifyBroadcaster ____
 void SAL_CALL BaseCoordinateSystem::addModifyListener( const Reference< 
util::XModifyListener >& aListener )
 {
diff --git a/chart2/source/tools/AxisHelper.cxx 
b/chart2/source/tools/AxisHelper.cxx
index 48da6b5a0e26..d82652fe3012 100644
--- a/chart2/source/tools/AxisHelper.cxx
+++ b/chart2/source/tools/AxisHelper.cxx
@@ -111,8 +111,7 @@ chart2::ScaleData AxisHelper::getDateCheckedScale( const 
rtl::Reference< Axis >&
     }
     if( aScale.AxisType == AxisType::DATE )
     {
-        ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, 
rModel );
-        if( !aExplicitCategoriesProvider.isDateAxis() )
+        if( !xCooSys->getExplicitCategoriesProvider(rModel).isDateAxis() )
             aScale.AxisType = AxisType::CATEGORY;
     }
     return aScale;
diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx 
b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
index 033aeaecd23a..5b714f1375d0 100644
--- a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx
@@ -136,7 +136,7 @@ void VCartesianCoordinateSystem::createVAxisList(
                 continue;
 
             rtl::Reference<Diagram> 
xDiagram(xChartDoc->getFirstChartDiagram());
-            AxisProperties aAxisProperties(xAxis, 
getExplicitCategoriesProvider(), xDiagram->getDataTableRef());
+            AxisProperties aAxisProperties(xAxis, 
&m_xCooSysModel->getExplicitCategoriesProvider(*xChartDoc), 
xDiagram->getDataTableRef());
             aAxisProperties.m_nDimensionIndex = nDimensionIndex;
             aAxisProperties.m_bSwapXAndY = bSwapXAndY;
             aAxisProperties.m_bIsMainAxis = (nAxisIndex==0);
diff --git a/chart2/source/view/axes/VCoordinateSystem.cxx 
b/chart2/source/view/axes/VCoordinateSystem.cxx
index 90bc5ed6bb7e..80d1f7d81c8e 100644
--- a/chart2/source/view/axes/VCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VCoordinateSystem.cxx
@@ -220,16 +220,6 @@ void VCoordinateSystem::impl_adjustDimensionAndIndex( 
sal_Int32& rDimensionIndex
         rAxisIndex = 0;
 }
 
-void VCoordinateSystem::setExplicitCategoriesProvider( 
ExplicitCategoriesProvider* pExplicitCategoriesProvider /*takes ownership*/ )
-{
-    m_apExplicitCategoriesProvider.reset(pExplicitCategoriesProvider);
-}
-
-ExplicitCategoriesProvider* VCoordinateSystem::getExplicitCategoriesProvider()
-{
-    return m_apExplicitCategoriesProvider.get();
-}
-
 std::vector< ExplicitScaleData > VCoordinateSystem::getExplicitScales( 
sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
 {
     std::vector< ExplicitScaleData > aRet(m_aExplicitScales);
diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.cxx 
b/chart2/source/view/axes/VPolarCoordinateSystem.cxx
index 36f0f3e35ba5..d45aeca7b762 100644
--- a/chart2/source/view/axes/VPolarCoordinateSystem.cxx
+++ b/chart2/source/view/axes/VPolarCoordinateSystem.cxx
@@ -96,7 +96,7 @@ void VPolarCoordinateSystem::createVAxisList(
                 continue;
 
             rtl::Reference<Diagram> 
xDiagram(xChartDoc->getFirstChartDiagram());
-            AxisProperties 
aAxisProperties(xAxis,getExplicitCategoriesProvider(), 
xDiagram->getDataTableRef());
+            AxisProperties aAxisProperties(xAxis, 
&m_xCooSysModel->getExplicitCategoriesProvider(*xChartDoc), 
xDiagram->getDataTableRef());
             aAxisProperties.init();
             if(aAxisProperties.m_bDisplayLabels)
                 aAxisProperties.m_nNumberFormatKey = 
getNumberFormatKeyForAxis(xAxis, xChartDoc);
diff --git a/chart2/source/view/inc/VCoordinateSystem.hxx 
b/chart2/source/view/inc/VCoordinateSystem.hxx
index 61dda842d02b..381f137d4c09 100644
--- a/chart2/source/view/inc/VCoordinateSystem.hxx
+++ b/chart2/source/view/inc/VCoordinateSystem.hxx
@@ -77,9 +77,6 @@ public:
     ExplicitScaleData getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 
nAxisIndex ) const;
     ExplicitIncrementData getExplicitIncrement( sal_Int32 nDimensionIndex, 
sal_Int32 nAxisIndex ) const;
 
-    void setExplicitCategoriesProvider( ExplicitCategoriesProvider* /*takes 
ownership*/ );
-    ExplicitCategoriesProvider* getExplicitCategoriesProvider();
-
     // returns a complete scale set for a given dimension and index; for 
example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary 
x axis, main y axis and main z axis
     std::vector< ExplicitScaleData > getExplicitScales( sal_Int32 
nDimensionIndex, sal_Int32 nAxisIndex ) const;
     // returns a complete increment set for a given dimension and index; for 
example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary 
x axis, main y axis and main z axis
@@ -200,8 +197,6 @@ private:
 
     tFullExplicitScaleMap       m_aSecondaryExplicitScales;
     tFullExplicitIncrementMap   m_aSecondaryExplicitIncrements;
-
-    std::unique_ptr< ExplicitCategoriesProvider > 
m_apExplicitCategoriesProvider;
 };
 
 } //namespace chart
diff --git a/chart2/source/view/main/ChartView.cxx 
b/chart2/source/view/main/ChartView.cxx
index 7fc3ec03a6f7..b82df788bcf6 100644
--- a/chart2/source/view/main/ChartView.cxx
+++ b/chart2/source/view/main/ChartView.cxx
@@ -535,7 +535,7 @@ awt::Rectangle ChartView::impl_createDiagramAndContent( 
const CreateShapeParam2D
 
     // - prepare list of all axis and how they are used
     Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier 
).getNullDate();
-    rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate);
+    rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate, 
mrChartModel);
     rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel );
     rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter();
     rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes();
diff --git a/chart2/source/view/main/SeriesPlotterContainer.cxx 
b/chart2/source/view/main/SeriesPlotterContainer.cxx
index 3f054b6ea5e0..714ae7288feb 100644
--- a/chart2/source/view/main/SeriesPlotterContainer.cxx
+++ b/chart2/source/view/main/SeriesPlotterContainer.cxx
@@ -125,7 +125,6 @@ VCoordinateSystem* SeriesPlotterContainer::addCooSysToList(
         ObjectIdentifier::createParticleForCoordinateSystem(xCooSys, 
&rChartModel));
     pVCooSys->setParticle(aCooSysParticle);
 
-    pVCooSys->setExplicitCategoriesProvider(new 
ExplicitCategoriesProvider(xCooSys, rChartModel));
     rVCooSysList.push_back(std::move(pVCooSys));
     return rVCooSysList.back().get();
 }
@@ -258,7 +257,8 @@ void 
SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(ChartModel& rChart
             
pPlotter->setNumberFormatsSupplier(rChartModel.getNumberFormatsSupplier());
             pPlotter->setColorScheme(xColorScheme);
             if (pVCooSys)
-                
pPlotter->setExplicitCategoriesProvider(pVCooSys->getExplicitCategoriesProvider());
+                pPlotter->setExplicitCategoriesProvider(
+                    &xCooSys->getExplicitCategoriesProvider(rChartModel));
             sal_Int32 nMissingValueTreatment
                 = xDiagram->getCorrectedMissingValueTreatment(xChartType);
 
@@ -375,7 +375,7 @@ bool 
SeriesPlotterContainer::isCategoryPositionShifted(const chart2::ScaleData&
     return rSourceScale.AxisType == AxisType::SERIES;
 }
 
-void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate)
+void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate, 
ChartModel& rChartModel)
 {
     m_aAxisUsageList.clear();
 
@@ -407,13 +407,13 @@ void SeriesPlotterContainer::initAxisUsageList(const 
Date& rNullDate)
                     // Create axis usage object for this axis.
 
                     chart2::ScaleData aSourceScale = xAxis->getScaleData();
-                    ExplicitCategoriesProvider* pCatProvider
-                        = pVCooSys->getExplicitCategoriesProvider();
+                    ExplicitCategoriesProvider& rCatProvider
+                        = xCooSys->getExplicitCategoriesProvider(rChartModel);
                     if (nDimIndex == 0)
-                        AxisHelper::checkDateAxis(aSourceScale, pCatProvider, 
bDateAxisAllowed);
+                        AxisHelper::checkDateAxis(aSourceScale, &rCatProvider, 
bDateAxisAllowed);
 
-                    bool bHasComplexCat = pCatProvider && 
pCatProvider->hasComplexCategories()
-                                          && bComplexCategoryAllowed;
+                    bool bHasComplexCat
+                        = rCatProvider.hasComplexCategories() && 
bComplexCategoryAllowed;
                     aSourceScale.ShiftedCategoryPosition
                         = isCategoryPositionShifted(aSourceScale, 
bHasComplexCat);
 
diff --git a/chart2/source/view/main/SeriesPlotterContainer.hxx 
b/chart2/source/view/main/SeriesPlotterContainer.hxx
index 38f3c8b909c8..485d4210d646 100644
--- a/chart2/source/view/main/SeriesPlotterContainer.hxx
+++ b/chart2/source/view/main/SeriesPlotterContainer.hxx
@@ -63,7 +63,7 @@ public:
      *  object and initialize its `aAutoScaling` member to the `ScaleData`
      *  object of the current axis.
      */
-    void initAxisUsageList(const Date& rNullDate);
+    void initAxisUsageList(const Date& rNullDate, ChartModel& rChartModel);
 
     /**
      * Perform automatic axis scaling and determine the amount and spacing of
commit 8611749d0acbf910a7003131e4419022eb4fe4bc
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Thu Apr 3 17:21:03 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Apr 4 17:49:22 2025 +0200

    tdf#147874 slow sheet switching with large chart2
    
    split out the initialisation and exit early if possible. Takes the
    switching time from 11sec to 2sec for me.
    
    Change-Id: If31962e9603a14271a638da19a26ea1b050967d2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183699
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/chart2/source/inc/ExplicitCategoriesProvider.hxx 
b/chart2/source/inc/ExplicitCategoriesProvider.hxx
index a7b97214f628..9e43abfc268e 100644
--- a/chart2/source/inc/ExplicitCategoriesProvider.hxx
+++ b/chart2/source/inc/ExplicitCategoriesProvider.hxx
@@ -27,6 +27,7 @@
 #include <vector>
 
 namespace chart { class ChartModel; }
+namespace com::sun::star::chart2::data { class XDataProvider; }
 namespace com::sun::star::chart2::data { class XDataSequence; }
 namespace com::sun::star::chart2::data { class XLabeledDataSequence; }
 namespace com::sun::star::uno { class Any; }
@@ -93,6 +94,8 @@ private:
     ExplicitCategoriesProvider(ExplicitCategoriesProvider const &) = delete;
     ExplicitCategoriesProvider& operator =(ExplicitCategoriesProvider const &) 
= delete;
 
+    void implInitSplit();
+
     bool volatile m_bDirty;
     unotools::WeakReference< ::chart::BaseCoordinateSystem >   m_xCooSysModel;
     ChartModel& mrModel;
diff --git a/chart2/source/tools/ExplicitCategoriesProvider.cxx 
b/chart2/source/tools/ExplicitCategoriesProvider.cxx
index d543b2b365fb..9a3ced3ba49d 100644
--- a/chart2/source/tools/ExplicitCategoriesProvider.cxx
+++ b/chart2/source/tools/ExplicitCategoriesProvider.cxx
@@ -75,70 +75,78 @@ ExplicitCategoriesProvider::ExplicitCategoriesProvider( 
const rtl::Reference< Ba
 
         if( m_xOriginalCategories.is() )
         {
-            uno::Reference< data::XDataProvider > xDataProvider( 
mrModel.getDataProvider() );
+            implInitSplit();
+            if( m_aSplitCategoriesList.empty() )
+                m_aSplitCategoriesList = { m_xOriginalCategories };
+        }
+    }
+    catch( const uno::Exception & )
+    {
+        DBG_UNHANDLED_EXCEPTION("chart2");
+    }
+}
 
-            OUString aCategoriesRange( DataSourceHelper::getRangeFromValues( 
m_xOriginalCategories ) );
-            if( xDataProvider.is() && !aCategoriesRange.isEmpty() )
-            {
-                const bool bFirstCellAsLabel = false;
-                const bool bHasCategories = false;
-                const uno::Sequence< sal_Int32 > aSequenceMapping;
+void ExplicitCategoriesProvider::implInitSplit()
+{
+    uno::Reference< data::XDataProvider > xDataProvider( 
mrModel.getDataProvider() );
+    if( !xDataProvider.is() )
+        return;
 
-                uno::Reference< data::XDataSource > xColumnCategoriesSource( 
xDataProvider->createDataSource(
-                            DataSourceHelper::createArguments( 
aCategoriesRange, aSequenceMapping, true /*bUseColumns*/
-                                , bFirstCellAsLabel, bHasCategories ) ) );
+    OUString aCategoriesRange( DataSourceHelper::getRangeFromValues( 
m_xOriginalCategories ) );
+    if( aCategoriesRange.isEmpty() )
+        return;
 
-                uno::Reference< data::XDataSource > xRowCategoriesSource( 
xDataProvider->createDataSource(
-                            DataSourceHelper::createArguments( 
aCategoriesRange, aSequenceMapping, false /*bUseColumns*/
-                                , bFirstCellAsLabel, bHasCategories ) ) );
+    const bool bFirstCellAsLabel = false;
+    const bool bHasCategories = false;
+    const uno::Sequence< sal_Int32 > aSequenceMapping;
 
-                if( xColumnCategoriesSource.is() &&  xRowCategoriesSource.is() 
)
-                {
-                    Sequence< Reference< data::XLabeledDataSequence> > 
aColumns = xColumnCategoriesSource->getDataSequences();
-                    Sequence< Reference< data::XLabeledDataSequence> > aRows = 
xRowCategoriesSource->getDataSequences();
+    uno::Reference< data::XDataSource > xRowCategoriesSource( 
xDataProvider->createDataSource(
+                DataSourceHelper::createArguments( aCategoriesRange, 
aSequenceMapping, false /*bUseColumns*/
+                    , bFirstCellAsLabel, bHasCategories ) ) );
+    if( !xRowCategoriesSource )
+        return;
 
-                    sal_Int32 nColumnCount = aColumns.getLength();
-                    sal_Int32 nRowCount = aRows.getLength();
-                    if( nColumnCount>1 && nRowCount>1 )
-                    {
-                        //we have complex categories
-                        //->split them in the direction of the first series
-                        //detect whether the first series is a row or a column
-                        bool bSeriesUsesColumns = true;
-                        std::vector< rtl::Reference< DataSeries > > aSeries = 
ChartModelHelper::getDataSeries( &mrModel );
-                        if( !aSeries.empty() )
-                        {
-                            const rtl::Reference< DataSeries >& xSeriesSource 
= aSeries.front();
-                            for(const auto& rArgument : 
xDataProvider->detectArguments( xSeriesSource))
-                            {
-                                if ( rArgument.Name == "DataRowSource" )
-                                {
-                                    css::chart::ChartDataRowSource eRowSource;
-                                    if( rArgument.Value >>= eRowSource )
-                                    {
-                                        bSeriesUsesColumns = (eRowSource == 
css::chart::ChartDataRowSource_COLUMNS);
-                                        break;
-                                    }
-                                }
-                            }
-                        }
-                        if( bSeriesUsesColumns )
-                            m_aSplitCategoriesList = 
comphelper::sequenceToContainer<std::vector<Reference<data::XLabeledDataSequence>>>(aColumns);
-                        else
-                            m_aSplitCategoriesList = 
comphelper::sequenceToContainer<std::vector<Reference<data::XLabeledDataSequence>>>(aRows);
-                    }
-                }
-            }
-            if( m_aSplitCategoriesList.empty() )
+    Sequence< Reference< data::XLabeledDataSequence> > aRows = 
xRowCategoriesSource->getDataSequences();
+    sal_Int32 nRowCount = aRows.getLength();
+    if( nRowCount<=1 )
+        return;
+
+    uno::Reference< data::XDataSource > xColumnCategoriesSource( 
xDataProvider->createDataSource(
+                DataSourceHelper::createArguments( aCategoriesRange, 
aSequenceMapping, true /*bUseColumns*/
+                    , bFirstCellAsLabel, bHasCategories ) ) );
+    if( !xColumnCategoriesSource )
+        return;
+
+    Sequence< Reference< data::XLabeledDataSequence> > aColumns = 
xColumnCategoriesSource->getDataSequences();
+    sal_Int32 nColumnCount = aColumns.getLength();
+    if( nColumnCount<=1 )
+        return;
+
+    //we have complex categories
+    //->split them in the direction of the first series
+    //detect whether the first series is a row or a column
+    bool bSeriesUsesColumns = true;
+    std::vector< rtl::Reference< DataSeries > > aSeries = 
ChartModelHelper::getDataSeries( &mrModel );
+    if( !aSeries.empty() )
+    {
+        const rtl::Reference< DataSeries >& xSeriesSource = aSeries.front();
+        for(const auto& rArgument : xDataProvider->detectArguments( 
xSeriesSource))
+        {
+            if ( rArgument.Name == "DataRowSource" )
             {
-                m_aSplitCategoriesList = { m_xOriginalCategories };
+                css::chart::ChartDataRowSource eRowSource;
+                if( rArgument.Value >>= eRowSource )
+                {
+                    bSeriesUsesColumns = (eRowSource == 
css::chart::ChartDataRowSource_COLUMNS);
+                    break;
+                }
             }
         }
     }
-    catch( const uno::Exception & )
-    {
-        DBG_UNHANDLED_EXCEPTION("chart2");
-    }
+    if( bSeriesUsesColumns )
+        m_aSplitCategoriesList = 
comphelper::sequenceToContainer<std::vector<Reference<data::XLabeledDataSequence>>>(aColumns);
+    else
+        m_aSplitCategoriesList = 
comphelper::sequenceToContainer<std::vector<Reference<data::XLabeledDataSequence>>>(aRows);
 }
 
 ExplicitCategoriesProvider::~ExplicitCategoriesProvider()

Reply via email to