tdf#34873 : Better way to show autofilter count

This patch modifies the commit 3536fe8f4cdbacf5702e743407f34d918b6f4d38
by keeping the filtered row count inside ScDBData instead of
ScTable as suggested by Eike Rathke. This significantly reduced the
code complexity involved.

Change-Id: I30ac26061d9665ce7a749e23a636f7fb3f69b176
Reviewed-on: https://gerrit.libreoffice.org/21720
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Eike Rathke <erack@redhat.com>
diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx
index bab0608..6778a94 100644
--- a/sc/inc/dbdata.hxx
+++ b/sc/inc/dbdata.hxx
@@ -97,6 +97,7 @@ private:

    ::std::vector< OUString > maTableColumnNames;   ///< names of table columns
    bool            mbTableColumnNamesDirty;
    SCSIZE          nFilteredRowCount;

    using ScRefreshTimer::operator==;

@@ -214,6 +215,8 @@ public:
                        SCsCOL nDx, SCsROW nDy, SCsTAB nDz);

    void ExtendDataArea(ScDocument* pDoc);
    void CalcSaveFilteredCount(SCSIZE nNonFilteredRowCount);
    void GetFilterSelCount(SCSIZE& nSelected, SCSIZE& nTotal);

private:

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index d6111dd..d2672fe 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -117,16 +117,6 @@ class ScHint;
class ScTable : private boost::noncopyable
{
private:
    // To store an Autofilter's filtered row count
    struct FilteredRowCountData {
        SCROW nStartRow;
        SCROW nEndRow;
        SCSIZE nCount;
        FilteredRowCountData(SCROW nRow1, SCROW nRow2, SCSIZE nVal) :
            nStartRow(nRow1), nEndRow(nRow2), nCount(nVal)
        {}
    };

    typedef ::std::vector< ScRange > ScRangeVec;

    ScColumn        aCol[MAXCOLCOUNT];
@@ -161,7 +151,6 @@ private:
    std::unique_ptr<ScFlatBoolRowSegments>  mpHiddenRows;
    std::unique_ptr<ScFlatBoolColSegments>  mpFilteredCols;
    std::unique_ptr<ScFlatBoolRowSegments>  mpFilteredRows;
    FilteredRowCountData                    maFilteredRowCount;

    ::std::set<SCROW>                      maRowPageBreaks;
    ::std::set<SCROW>                      maRowManualBreaks;
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 5f632d9..aa9fbb7 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -1470,37 +1470,9 @@ void ScDocument::GetFilterSelCount( SCCOL nCol, SCROW nRow, SCTAB nTab, SCSIZE& 
    nTotal = 0;
    if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] )
    {
        const ScDBData* pDBData = GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
        ScDBData* pDBData = GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
        if( pDBData && pDBData->HasAutoFilter() )
        {
            SCTAB nAreaTab;
            SCCOL nStartCol;
            SCROW nStartRow;
            SCCOL nEndCol;
            SCROW nEndRow;
            pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );

            if( pDBData->HasHeader() )
                ++nStartRow;

            nTotal = nEndRow - nStartRow + 1;

            ScTable::FilteredRowCountData* pFilteredRowCount = &(maTabs[nTab]->maFilteredRowCount);
            // Exact range match, cache hit, early exit
            if( ( pFilteredRowCount->nStartRow == nStartRow ) && ( pFilteredRowCount->nEndRow == nEndRow ) &&
                ( pFilteredRowCount->nCount != SCSIZE_MAX ) )
            {
                nSelected = nTotal - pFilteredRowCount->nCount;
                return;
            }

            // Compute the count
            nSelected = CountNonFilteredRows( nStartRow, nEndRow, nTab );
            // and store it in the cache
            pFilteredRowCount->nStartRow = nStartRow;
            pFilteredRowCount->nEndRow   = nEndRow;
            pFilteredRowCount->nCount    = nTotal - nSelected;
        }
            pDBData->GetFilterSelCount( nSelected, nTotal );
    }
}

diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index e09018d..2bc2705 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -245,7 +245,6 @@ ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName,
    mpHiddenRows(new ScFlatBoolRowSegments),
    mpFilteredCols(new ScFlatBoolColSegments),
    mpFilteredRows(new ScFlatBoolRowSegments),
    maFilteredRowCount(0, MAXROW, SCSIZE_MAX),
    pOutlineTable( nullptr ),
    pSheetEvents( nullptr ),
    nTableAreaX( 0 ),
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 23121cb..11c0d58 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -171,13 +171,6 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
        mpFilteredRows->insertSegment(nStartRow, nSize, true);
        mpHiddenRows->insertSegment(nStartRow, nSize, true);

        if( ( nStartRow <= maFilteredRowCount.nEndRow ) && ( maFilteredRowCount.nCount != SCSIZE_MAX ) )
        {
            if( nStartRow < maFilteredRowCount.nStartRow )
                maFilteredRowCount.nStartRow += nSize;
            maFilteredRowCount.nEndRow += nSize;
        }

        if (!maRowManualBreaks.empty())
        {
            // Copy all breaks up to nStartRow (non-inclusive).
@@ -224,53 +217,6 @@ void ScTable::DeleteRow(
                if (pUndoOutline)
                    *pUndoOutline = true;

        if( ( maFilteredRowCount.nCount != SCSIZE_MAX ) && ( nStartRow <= maFilteredRowCount.nEndRow ) )
        {
            SCROW nEndRow = nStartRow + nSize - 1;
            // rows to be deleted has some overlap with autofilter
            if( nEndRow >= maFilteredRowCount.nStartRow  )
            {
                SCROW nStartRowInside = ( nStartRow >= maFilteredRowCount.nStartRow ) ? nStartRow : maFilteredRowCount.nStartRow;
                SCROW nEndRowInside = ( nEndRow <= maFilteredRowCount.nEndRow ) ? nEndRow : maFilteredRowCount.nEndRow;

                // All rows inside the autofilter are to be deleted, so set dirty flag.
                if( ( nStartRowInside == maFilteredRowCount.nStartRow ) && ( nEndRowInside == maFilteredRowCount.nEndRow ) )
                    maFilteredRowCount.nCount = SCSIZE_MAX;
                else
                {
                    SCSIZE nChange = 0;
                    ScFlatBoolRowSegments::RangeData aData;
                    SCROW nRowItr = nStartRowInside;
                    while( nRowItr <= nEndRowInside )
                    {
                        if( !mpFilteredRows->getRangeData( nRowItr, aData ) )
                            break;
                        if( aData.mnRow2 > nEndRowInside )
                            aData.mnRow2 = nEndRowInside;

                        if( aData.mbValue )
                            nChange += aData.mnRow2 - nRowItr + 1;

                        nRowItr = aData.mnRow2 + 1;
                    }
                    if( nStartRowInside == maFilteredRowCount.nStartRow )
                        maFilteredRowCount.nStartRow = ( nEndRowInside + 1 - nSize );

                    if( nEndRowInside == maFilteredRowCount.nEndRow )
                        maFilteredRowCount.nEndRow = ( nStartRowInside - 1 );
                    else
                        maFilteredRowCount.nEndRow -= nSize;
                    maFilteredRowCount.nCount -= nChange;
                }
            }
            // No overlap but the rows to be deleted are above the autofilter area.
            else
            {
                maFilteredRowCount.nStartRow -= nSize;
                maFilteredRowCount.nEndRow -= nSize;
            }
        }

        mpFilteredRows->removeSegment(nStartRow, nStartRow+nSize);
        mpHiddenRows->removeSegment(nStartRow, nStartRow+nSize);

diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
index f353383..8ba078c 100644
--- a/sc/source/core/data/table5.cxx
+++ b/sc/source/core/data/table5.cxx
@@ -859,37 +859,6 @@ void ScTable::CopyRowFiltered(ScTable& rTable, SCROW nStartRow, SCROW nEndRow)

void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
{
    // First adjust the maFilteredRowCount cache
    if( ( nStartRow >= maFilteredRowCount.nStartRow ) || ( nEndRow <= maFilteredRowCount.nEndRow ) )
    {
        if( ( nStartRow >= maFilteredRowCount.nStartRow ) && ( nEndRow <= maFilteredRowCount.nEndRow ) &&
            ( maFilteredRowCount.nCount != SCSIZE_MAX ) )
        {
            SCSIZE nChange = 0;
            ScFlatBoolRowSegments::RangeData aData;
            SCROW nRowItr = nStartRow;
            while( nRowItr <= nEndRow )
            {
                if( !mpFilteredRows->getRangeData( nRowItr, aData ) )
                    break;
                if( aData.mnRow2 > nEndRow )
                    aData.mnRow2 = nEndRow;
                // rows not filtered and going to be filtered
                if( bFiltered && !aData.mbValue )
                    nChange += aData.mnRow2 - nRowItr + 1;
                // rows filtered and not going to be filtered any more
                else if( !bFiltered && aData.mbValue )
                    nChange -= aData.mnRow2 - nRowItr + 1;

                nRowItr = aData.mnRow2 + 1;
            }

            maFilteredRowCount.nCount += nChange;
        }
        else
            maFilteredRowCount.nCount = SCSIZE_MAX;
    }

    if (bFiltered)
        mpFilteredRows->setTrue(nStartRow, nEndRow);
    else
diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx
index 59fbb9b..d368657 100644
--- a/sc/source/core/tool/dbdata.cxx
+++ b/sc/source/core/tool/dbdata.cxx
@@ -79,7 +79,8 @@ ScDBData::ScDBData( const OUString& rName,
    nIndex      (0),
    bAutoFilter (false),
    bModified   (false),
    mbTableColumnNamesDirty(true)
    mbTableColumnNamesDirty(true),
    nFilteredRowCount(0)
{
    aUpper = ScGlobal::pCharClass->uppercase(aUpper);
}
@@ -113,7 +114,8 @@ ScDBData::ScDBData( const ScDBData& rData ) :
    bAutoFilter         (rData.bAutoFilter),
    bModified           (rData.bModified),
    maTableColumnNames  (rData.maTableColumnNames),
    mbTableColumnNamesDirty(rData.mbTableColumnNamesDirty)
    mbTableColumnNamesDirty(rData.mbTableColumnNamesDirty),
    nFilteredRowCount   (rData.nFilteredRowCount)
{
}

@@ -146,7 +148,8 @@ ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
    bAutoFilter         (rData.bAutoFilter),
    bModified           (rData.bModified),
    maTableColumnNames  (rData.maTableColumnNames),
    mbTableColumnNamesDirty (rData.mbTableColumnNamesDirty)
    mbTableColumnNamesDirty (rData.mbTableColumnNamesDirty),
    nFilteredRowCount   (rData.nFilteredRowCount)
{
    aUpper = ScGlobal::pCharClass->uppercase(aUpper);
}
@@ -185,6 +188,7 @@ ScDBData& ScDBData::operator= (const ScDBData& rData)
    bDBSelection        = rData.bDBSelection;
    nIndex              = rData.nIndex;
    bAutoFilter         = rData.bAutoFilter;
    nFilteredRowCount   = rData.nFilteredRowCount;

    if (bHeaderRangeDiffers)
        InvalidateTableColumnNames( true);
@@ -915,6 +919,22 @@ void ScDBData::Notify( const SfxHint& rHint )
    // recalculation.
}

void ScDBData::CalcSaveFilteredCount( SCSIZE nNonFilteredRowCount )
{
    SCSIZE nTotal = nEndRow - nStartRow + 1;
    if ( bHasHeader )
        nTotal -= 1;
    nFilteredRowCount = nTotal - nNonFilteredRowCount;
}

void ScDBData::GetFilterSelCount( SCSIZE& nSelected, SCSIZE& nTotal )
{
    nTotal = nEndRow - nStartRow + 1;
    if ( bHasHeader )
        nTotal -= 1;
    nSelected = nTotal - nFilteredRowCount;
}

namespace {

class FindByTable : public unary_function<std::unique_ptr<ScDBData>, bool>
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
index 54a5b97..306fd1b 100644
--- a/sc/source/ui/docshell/dbdocfun.cxx
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -785,6 +785,7 @@ bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,

    //  Filtern am Dokument ausfuehren
    SCSIZE nCount = rDoc.Query( nTab, rQueryParam, bKeepSub );
    pDBData->CalcSaveFilteredCount( nCount );
    if (bCopy)
    {
        aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;