[Libreoffice-commits] core.git: Branch 'distro/nisz/libreoffice-7-0' - sc/inc sc/qa sc/source

Attila Szűcs (via logerrit) logerrit at kemper.freedesktop.org
Tue Feb 23 14:29:26 UTC 2021


 sc/inc/document.hxx                                                 |    2 
 sc/inc/table.hxx                                                    |    8 
 sc/qa/unit/copy_paste_test.cxx                                      |   60 +++
 sc/qa/unit/data/ods/tdf88782_AutofillLinearNumbersInMergedCells.ods |binary
 sc/source/core/data/table4.cxx                                      |  171 +++++++++-
 sc/source/ui/inc/cellmergeoption.hxx                                |    6 
 sc/source/ui/inc/docfunc.hxx                                        |    3 
 7 files changed, 234 insertions(+), 16 deletions(-)

New commits:
commit d06786634e1299557de4ace7ce420466cf17d269
Author:     Attila Szűcs <szucs.attila3 at nisz.hu>
AuthorDate: Thu Oct 1 14:40:08 2020 +0200
Commit:     Gabor Kelemen <kelemen.gabor2 at nisz.hu>
CommitDate: Tue Feb 23 15:28:52 2021 +0100

    tdf#88782 sc: autofill number sequences in merged cells
    
    Improve FillAuto, FillAnalyse and FillSeries to continue
    linear sequences of numbers in merged cells by skipping
    the empty overlapped cells of the merged area, like other
    spreadsheets do. For example this fix autofill, when merged
    cells are used to highlight nth numbers. Instead of 1, 2 ->
    1, 2, 2, 3, we get 1, 2 -> 1, 2, 3, 4 on the following fill:
    
    +-+-+-+    +-+-+-+-+-+-+
    |1| 2 | -> |1| 2 |3| 4 |
    +-+-+-+    +-+-+-+-+-+-+
    
    See the unit test document for more complex examples, and
    use merge/unmerge to check the work of the algorithm. For
    example, column C of the test document contains cells
    
    EMPTY, EMPTY, EMPTY, 2, EMPTY, 4, EMPTY
    
    calculated as 2, 4 during fill by skipping empty
    overlapped cells, but keeping also the merged structure,
    resulting the requested continuation of the linear sequence:
    
    EMPTY, EMPTY, EMPTY, 6, EMPTY, 8, EMPTY
    
    Note: special formats are not handled yet like date, string,
    boolean and userlist.
    
    Co-authored-by: Tibor Nagy (NISZ)
    
    Change-Id: Ib431e8968f5d71e321b0e57cfb173534a0f5da31
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103765
    Tested-by: László Németh <nemeth at numbertext.org>
    Reviewed-by: László Németh <nemeth at numbertext.org>
    (cherry picked from commit 03dfa09886b6fd0ebda7abe7d5e142da172e8cc2)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111330
    Tested-by: Gabor Kelemen <kelemen.gabor2 at nisz.hu>
    Reviewed-by: Gabor Kelemen <kelemen.gabor2 at nisz.hu>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 971377559ce9..2b91d9fc32c3 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1172,7 +1172,7 @@ public:
      * @return pointer to the double value stored in a numeric cell, or NULL
      *         if the cell at specified position is not a numeric cell.
      */
-    double* GetValueCell( const ScAddress& rPos );
+    SC_DLLPUBLIC double*                      GetValueCell( const ScAddress& rPos );
 
     SC_DLLPUBLIC svl::SharedStringPool&       GetSharedStringPool();
     const svl::SharedStringPool&              GetSharedStringPool() const;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 12f8bb87bc89..5b3c09a18fc0 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1103,11 +1103,15 @@ private:
                                 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd,
                                 FillDateCmd eFillDateCmd,
                                 double nStepValue, double nMaxValue, sal_uInt16 nMinDigits,
-                                bool bAttribs, ScProgress* pProgress );
+                                bool bAttribs, ScProgress* pProgress,
+                                bool bSkipOverlappedCells = false,
+                                std::vector<sal_Int32>* pNonOverlappedCellIdx = nullptr);
     void        FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                                 FillCmd& rCmd, FillDateCmd& rDateCmd,
                                 double& rInc, sal_uInt16& rMinDigits,
-                                ScUserListData*& rListData, sal_uInt16& rListIndex);
+                                ScUserListData*& rListData, sal_uInt16& rListIndex,
+                                bool bHasFiltered, bool& rSkipOverlappedCells,
+                                std::vector<sal_Int32>& rNonOverlappedCellIdx );
     void        FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                         sal_uLong nFillCount, FillDir eFillDir, ScProgress* pProgress );
 
diff --git a/sc/qa/unit/copy_paste_test.cxx b/sc/qa/unit/copy_paste_test.cxx
index 22c0f832e64a..592be6cf518c 100644
--- a/sc/qa/unit/copy_paste_test.cxx
+++ b/sc/qa/unit/copy_paste_test.cxx
@@ -12,6 +12,8 @@
 #include <comphelper/processfactory.hxx>
 
 #include <docsh.hxx>
+#include <docfunc.hxx>
+#include <cellmergeoption.hxx>
 #include <tabvwsh.hxx>
 #include <impex.hxx>
 #include <viewfunc.hxx>
@@ -42,6 +44,7 @@ public:
     void testTdf53431_fillOnAutofilter();
     void testTdf40993_fillMergedCells();
     void testTdf43958_clickSelectOnMergedCells();
+    void testTdf88782_autofillLinearNumbersInMergedCells();
 
     CPPUNIT_TEST_SUITE(ScCopyPasteTest);
     CPPUNIT_TEST(testCopyPasteXLS);
@@ -52,6 +55,7 @@ public:
     CPPUNIT_TEST(testTdf53431_fillOnAutofilter);
     CPPUNIT_TEST(testTdf40993_fillMergedCells);
     CPPUNIT_TEST(testTdf43958_clickSelectOnMergedCells);
+    CPPUNIT_TEST(testTdf88782_autofillLinearNumbersInMergedCells);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -620,6 +624,62 @@ void ScCopyPasteTest::testTdf43958_clickSelectOnMergedCells()
     lcl_clickAndCheckCurrentArea(2, 8, 2, 8);    // C9
 }
 
+void ScCopyPasteTest::testTdf88782_autofillLinearNumbersInMergedCells()
+{
+    ScDocShellRef xDocSh = loadDocAndSetupModelViewController("tdf88782_AutofillLinearNumbersInMergedCells.", FORMAT_ODS, true);
+    ScDocument& rDoc = xDocSh->GetDocument();
+
+    // Get the document controller
+    ScTabViewShell* pView = xDocSh->GetBestViewShell(false);
+    CPPUNIT_ASSERT(pView != nullptr);
+
+    // merge the yellow cells
+    ScCellMergeOption aMergeOptions(9, 11, 10, 13);     //J12:K14
+    aMergeOptions.maTabs.insert(0);
+    xDocSh->GetDocFunc().MergeCells(aMergeOptions, false, true, true, false);
+
+    // fillauto numbers, these areas contains mostly merged cells
+    pView->FillAuto(FILL_TO_BOTTOM, 1, 8, 3, 14, 7);    // B9:D15 ->  B9:D22
+    pView->FillAuto(FILL_TO_BOTTOM, 5, 8, 7, 17, 10);   // F9:H18 ->  F9:H28
+    pView->FillAuto(FILL_TO_BOTTOM, 9, 8, 10, 13, 6);   // J9:K14 ->  J9:K20
+    pView->FillAuto(FILL_TO_RIGHT, 9, 30, 16, 35, 8);   //J31:Q36 -> J31:Y36
+    pView->FillAuto(FILL_TO_LEFT, 9, 30, 16, 35, 8);    //J31:Q36 -> B31:Q36
+
+    // compare the results of fill-down with the reference stored in the test file
+    // this compare the whole area blindly, for concrete test cases, check the test file
+    // the test file have instructions / explanations, so that is easy to understand
+    for (int nCol = 1; nCol <= 10; nCol++) {
+        for (int nRow = 8; nRow <= 27; nRow++) {
+            CellType nType1 = rDoc.GetCellType(ScAddress(nCol, nRow, 0));
+            CellType nType2 = rDoc.GetCellType(ScAddress(nCol + 22, nRow, 0));
+            double* pValue1 = rDoc.GetValueCell(ScAddress(nCol, nRow, 0));
+            double* pValue2 = rDoc.GetValueCell(ScAddress(nCol + 22, nRow, 0));
+
+            CPPUNIT_ASSERT_EQUAL(nType1, nType2);
+            if (pValue2 != nullptr)
+                CPPUNIT_ASSERT_EQUAL(*pValue1, *pValue2);   //cells with number value
+            else
+                CPPUNIT_ASSERT_EQUAL(pValue1, pValue2);     //empty cells
+        }
+    }
+
+    // compare the results of fill-right and left with the reference stored in the test file
+    for (int nCol = 1; nCol <= 24; nCol++) {
+        for (int nRow = 30; nRow <= 35; nRow++) {
+            CellType nType1 = rDoc.GetCellType(ScAddress(nCol, nRow, 0));
+            CellType nType2 = rDoc.GetCellType(ScAddress(nCol, nRow + 16, 0));
+            double* pValue1 = rDoc.GetValueCell(ScAddress(nCol, nRow, 0));
+            double* pValue2 = rDoc.GetValueCell(ScAddress(nCol, nRow + 16, 0));
+
+            CPPUNIT_ASSERT_EQUAL(nType1, nType2);
+            if (pValue2 != nullptr)
+                CPPUNIT_ASSERT_EQUAL(*pValue1, *pValue2);
+            else
+                CPPUNIT_ASSERT_EQUAL(pValue1, pValue2);
+        }
+    }
+}
+
 ScCopyPasteTest::ScCopyPasteTest()
       : ScBootstrapFixture( "sc/qa/unit/data" )
 {
diff --git a/sc/qa/unit/data/ods/tdf88782_AutofillLinearNumbersInMergedCells.ods b/sc/qa/unit/data/ods/tdf88782_AutofillLinearNumbersInMergedCells.ods
new file mode 100644
index 000000000000..99fea7087010
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf88782_AutofillLinearNumbersInMergedCells.ods differ
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 3d6c16b95ca5..18747e24c708 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -215,7 +215,9 @@ double approxDiff( double a, double b )
 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                             FillCmd& rCmd, FillDateCmd& rDateCmd,
                             double& rInc, sal_uInt16& rMinDigits,
-                            ScUserListData*& rListData, sal_uInt16& rListIndex)
+                            ScUserListData*& rListData, sal_uInt16& rListIndex,
+                            bool bHasFiltered, bool& rSkipOverlappedCells,
+                            std::vector<sal_Int32>& rNonOverlappedCellIdx)
 {
     OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
 
@@ -223,6 +225,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     rMinDigits = 0;
     rListData = nullptr;
     rCmd = FILL_SIMPLE;
+    rSkipOverlappedCells = false;
     if ( nScFillModeMouseModifier & KEY_MOD1 )
         return ;        // Ctrl-key: Copy
 
@@ -242,6 +245,100 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
     }
 
+    // Try to analyse the merged cells only if there are no filtered rows in the destination area
+    // Else fallback to the old way to avoid regression.
+    // Filling merged cells into an area with filtered (hidden) rows, is a very complex task
+    // that is not implemented, but not even decided how to do, even excel can't handle that well
+    if (!bHasFiltered)
+    {
+        bool bHasOverlappedCells = false;
+        bool bSkipOverlappedCells = true;
+        SCCOL nColAkt = nCol1;
+        SCROW nRowAkt = nRow1;
+
+        // collect cells that are not empty or not overlapped
+        rNonOverlappedCellIdx.resize(nCount);
+        SCSIZE nValueCount = 0;
+        for (SCSIZE i = 0; i < nCount; ++i)
+        {
+            const ScPatternAttr* pPattern = GetPattern(nColAkt, nRowAkt);
+            bool bOverlapped
+                = pPattern->GetItemSet().GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET
+                  && pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped();
+
+            if (bOverlapped)
+                bHasOverlappedCells = true;
+
+            if (!bOverlapped || GetCellValue(nColAkt, nRowAkt).meType != CELLTYPE_NONE)
+            {
+                rNonOverlappedCellIdx[nValueCount++] = i;
+                // if there is at least 1 non empty overlapped cell, then no cell should be skipped
+                if (bOverlapped)
+                    bSkipOverlappedCells = false;
+            }
+
+            nColAkt += nAddX;
+            nRowAkt += nAddY;
+        }
+        rNonOverlappedCellIdx.resize(nValueCount);
+
+        // if all the values are overlapped CELLTYPE_NONE, then there is no need to analyse it.
+        if (nValueCount == 0)
+            return;
+
+        // if there is no overlapped cells, there is nothing to skip
+        if (!bHasOverlappedCells)
+            bSkipOverlappedCells = false;
+
+        if (bSkipOverlappedCells)
+        {
+            nColAkt = nCol1 + rNonOverlappedCellIdx[0] * nAddX;
+            nRowAkt = nRow1 + rNonOverlappedCellIdx[0] * nAddY;
+            ScRefCellValue aPrevCell, aAktCell;
+            aAktCell = GetCellValue(nColAkt, nRowAkt);
+            CellType eCellType = aAktCell.meType;
+            if (eCellType == CELLTYPE_VALUE)
+            {
+                // TODO: Check / handle special cases of number formats: like date, boolean
+                bool bVal = true;
+                if (nValueCount >= 2)
+                {
+                    for (SCSIZE i = 1; i < nValueCount && bVal; i++)
+                    {
+                        aPrevCell = aAktCell;
+                        nColAkt = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
+                        nRowAkt = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
+                        aAktCell = GetCellValue(nColAkt, nRowAkt);
+                        if (aAktCell.meType == CELLTYPE_VALUE)
+                        {
+                            double nDiff = approxDiff(aAktCell.mfValue, aPrevCell.mfValue);
+                            if (i == 1)
+                                rInc = nDiff;
+                            if (!::rtl::math::approxEqual(nDiff, rInc, 13))
+                                bVal = false;
+                        }
+                        else
+                            bVal = false;
+                    }
+                    if (bVal)
+                    {
+                        rCmd = FILL_LINEAR;
+                        rSkipOverlappedCells = true;
+                        return;
+                    }
+                }
+            }
+            else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
+            {
+                // TODO: check / handle if it is a sequence of userlist string
+                // or if the strings are composition of a number sequence and a constant string
+            }
+        }
+    }
+
+    //if it is not a FILL_LINEAR - CELLTYPE_VALUE - with merged cells [without hidden values]
+    //then do it in the old way
+
     SCCOL nCol = nCol1;
     SCROW nRow = nRow1;
 
@@ -795,14 +892,18 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         sal_uInt16 nMinDigits;
         ScUserListData* pListData = nullptr;
         sal_uInt16 nListIndex;
+        bool nSkipOverlappedCells;
+        std::vector<sal_Int32> aNonOverlappedCellIdx;
         if (bVertical)
             FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
                     static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
-                    nInc,nMinDigits, pListData,nListIndex);
+                    nInc, nMinDigits, pListData, nListIndex,
+                    bHasFiltered, nSkipOverlappedCells, aNonOverlappedCellIdx);
         else
             FillAnalyse(nCol1,static_cast<SCROW>(nRow),
                     nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
-                    nInc,nMinDigits, pListData,nListIndex);
+                    nInc, nMinDigits, pListData, nListIndex,
+                    bHasFiltered, nSkipOverlappedCells, aNonOverlappedCellIdx);
 
         if (pListData)
         {
@@ -860,12 +961,12 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                 FillSeries( static_cast<SCCOL>(nCol), nRow1,
                         static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
                         eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
-                        pProgress );
+                        pProgress, nSkipOverlappedCells, &aNonOverlappedCellIdx);
             else
                 FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
                         static_cast<SCROW>(nRow), nFillCount, eFillDir,
                         eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
-                        pProgress );
+                        pProgress, nSkipOverlappedCells, &aNonOverlappedCellIdx);
             if (pProgress)
                 nProgress = pProgress->GetState();
         }
@@ -919,8 +1020,15 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW
         sal_uInt16 nMinDigits;
         ScUserListData* pListData = nullptr;
         sal_uInt16 nListIndex;
+        bool nSkipOverlappedCells;
+        std::vector<sal_Int32> aNonOverlappedCellIdx;
 
-        FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
+        // Todo: update this function to calculate with merged cell fills,
+        //       after FillAnalyse / FillSeries fully handle them.
+        // Now FillAnalyse called as if there are filtered rows, so it will work in the old way.
+        FillAnalyse(nCol1, nRow1, nCol2, nRow2, eFillCmd, eDateCmd,
+                    nInc, nMinDigits, pListData, nListIndex,
+                    true, nSkipOverlappedCells, aNonOverlappedCellIdx);
 
         if ( pListData )                            // user defined list
         {
@@ -1693,7 +1801,8 @@ inline bool isOverflow( const double& rVal, const double& rMax, const double& rS
 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                     sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
                     double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
-                    bool bAttribs, ScProgress* pProgress )
+                    bool bAttribs, ScProgress* pProgress,
+                    bool bSkipOverlappedCells, std::vector<sal_Int32>* pNonOverlappedCellIdx )
 {
     // The term 'inner' here refers to the loop in the filling direction i.e.
     // when filling vertically, the inner position is the row position whereas
@@ -1718,9 +1827,12 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     SCCOLROW nIEnd;
     SCCOLROW nISource;
     ScRange aFillRange;
+    sal_uLong nFillerCount;
+    std::vector<bool> aIsNonEmptyCell;
 
     if (bVertical)
     {
+        nFillerCount = (nRow2 - nRow1) + 1;
         nFillCount += (nRow2 - nRow1);
         if (nFillCount == 0)
             return;
@@ -1745,6 +1857,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     }
     else
     {
+        nFillerCount = (nCol2 - nCol1) + 1;
         nFillCount += (nCol2 - nCol1);
         if (nFillCount == 0)
             return;
@@ -1781,6 +1894,8 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         // at least as long as the area to be filled and does not end earlier,
         // so we can treat it as entire area for performance reasons at least
         // in the vertical case.
+        // This is not exact in case of merged cell fills with skipping overlapped parts, but
+        // it is still a good upper estimation.
         ScCellValue aSrcCell;
         if (bVertical)
             aSrcCell = aCol[static_cast<SCCOL>(nOStart)].GetCellValue(static_cast<SCROW>(nISource));
@@ -1841,6 +1956,34 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
         // Source cell value. We need to clone the value since it may be inserted repeatedly.
         ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
 
+        // Maybe another source cell need to be searched, if the fill is going trough merged cells,
+        // where overlapped parts does not contain any information, so they can be skipped.
+        if (bSkipOverlappedCells)
+        {
+            // create a vector to make it easier to decide if a cell need to be filled, or skipped.
+            aIsNonEmptyCell.resize(nFillerCount, false);
+
+            SCCOLROW nfirstValueIdx;
+            if (bPositive)
+            {
+                nfirstValueIdx = nISource + (*pNonOverlappedCellIdx)[0];
+                for (auto i : (*pNonOverlappedCellIdx))
+                    aIsNonEmptyCell[i] = true;
+            }
+            else
+            {
+                nfirstValueIdx = nISource - (nFillerCount - 1 - (*pNonOverlappedCellIdx).back());
+                for (auto i : (*pNonOverlappedCellIdx))
+                    aIsNonEmptyCell[nFillerCount - 1 - i] = true;
+            }
+
+            //Set the real source cell
+            if (bVertical)
+                aSrcCell = aCol[nOStart].GetCellValue(static_cast<SCROW>(nfirstValueIdx));
+            else
+                aSrcCell = aCol[nfirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart));
+        }
+
         const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
         const ScCondFormatItem& rCondFormatItem = pSrcPattern->GetItem(ATTR_CONDITIONAL);
         const ScCondFormatIndexes& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
@@ -1899,14 +2042,24 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
 
                 bool bError = false;
                 bool bOverflow = false;
+                bool bNonEmpty = true;
 
                 sal_uInt16 nDayOfMonth = 0;
+                sal_Int32 nFillerIdx = 0;
+                if (bSkipOverlappedCells && !aIsNonEmptyCell[0])
+                    --nIndex;
                 rInner = nIStart;
                 while (true)
                 {
+                    if (bSkipOverlappedCells)
+                    {
+                        nFillerIdx = (nFillerIdx + 1) % nFillerCount;
+                        bNonEmpty = aIsNonEmptyCell[nFillerIdx];
+                    }
+
                     if(!ColHidden(nCol) && !RowHidden(nRow))
                     {
-                        if (!bError)
+                        if (!bError && bNonEmpty)
                         {
                             switch (eFillCmd)
                             {
@@ -1943,7 +2096,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
 
                         if (bError)
                             aCol[nCol].SetError(static_cast<SCROW>(nRow), FormulaError::NoValue);
-                        else if (!bOverflow)
+                        else if (!bOverflow && bNonEmpty)
                             aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
 
                         if (bAttribs && !bEntireArea && !bOverflow)
diff --git a/sc/source/ui/inc/cellmergeoption.hxx b/sc/source/ui/inc/cellmergeoption.hxx
index ff4a7cbebcc9..937b9079960d 100644
--- a/sc/source/ui/inc/cellmergeoption.hxx
+++ b/sc/source/ui/inc/cellmergeoption.hxx
@@ -24,9 +24,9 @@ struct ScCellMergeOption
     bool mbCenter;
 
     explicit ScCellMergeOption(const ScRange& rRange);
-    explicit ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow,
-                               SCCOL nEndCol, SCROW nEndRow,
-                               bool bCenter = false);
+    SC_DLLPUBLIC explicit ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow,
+                                            SCCOL nEndCol, SCROW nEndRow,
+                                            bool bCenter = false);
 
     ScRange getSingleRange(SCTAB nTab) const;
     ScRange getFirstSingleRange() const;
diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx
index e3a8117a5493..1984c0da440a 100644
--- a/sc/source/ui/inc/docfunc.hxx
+++ b/sc/source/ui/inc/docfunc.hxx
@@ -191,7 +191,8 @@ public:
 
     void            ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd );
 
-    bool            MergeCells( const ScCellMergeOption& rOption, bool bContents,
+    SC_DLLPUBLIC bool
+                    MergeCells( const ScCellMergeOption& rOption, bool bContents,
                                         bool bRecord, bool bApi, bool bEmptyMergedCells = false );
     bool            UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge );
     bool            UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge );


More information about the Libreoffice-commits mailing list