sc/qa/unit/copy_paste_test.cxx                           |   57 +++++
 sc/qa/unit/data/ods/tdf137625_autofillMergedUserlist.ods |binary
 sc/source/core/data/table4.cxx                           |  146 +++++++++++++--
 3 files changed, 184 insertions(+), 19 deletions(-)

New commits:
commit e8a88d6129948227b46d734a7eba999ec9d1a025
Author:     Attila Szűcs <szucs.atti...@nisz.hu>
AuthorDate: Thu Oct 22 17:44:40 2020 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Fri Oct 30 18:49:45 2020 +0100

    tdf#137625 sc: autofill user list sequences in merged cells
    
    Improve FillAuto, FillAnalyse to continue linear sequences
    of user list values in merged cells. (User lists are special
    string lists with values like day names Monday, Tuesday, ...)
    
    If values are user list values, but not in linear sequence, then
    the autofill will just fill with FILL_SIMPLE (pattern repeat).
    
    Note: the unit test depends on English system locale settings,
    check it in Tools->Options->LibreOffice Calc->Sort list,
    otherwise extend Sort list with English day names for manual
    testing.
    
    Co-authored-by: Tibor Nagy (NISZ)
    
    Change-Id: I7a1da5e82a18ba8ebd24af7e4b89c7651f3ec24a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104690
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sc/qa/unit/copy_paste_test.cxx b/sc/qa/unit/copy_paste_test.cxx
index 527afccaafe6..131954a0eb2c 100644
--- a/sc/qa/unit/copy_paste_test.cxx
+++ b/sc/qa/unit/copy_paste_test.cxx
@@ -47,6 +47,7 @@ public:
     void testTdf88782_autofillLinearNumbersInMergedCells();
     void tdf137621_autofillMergedBool();
     void tdf137205_autofillDatesInMergedCells();
+    void tdf137625_autofillMergedUserlist();
 
     CPPUNIT_TEST_SUITE(ScCopyPasteTest);
     CPPUNIT_TEST(testCopyPasteXLS);
@@ -60,6 +61,7 @@ public:
     CPPUNIT_TEST(testTdf88782_autofillLinearNumbersInMergedCells);
     CPPUNIT_TEST(tdf137621_autofillMergedBool);
     CPPUNIT_TEST(tdf137205_autofillDatesInMergedCells);
+    CPPUNIT_TEST(tdf137625_autofillMergedUserlist);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -751,6 +753,61 @@ void 
ScCopyPasteTest::tdf137205_autofillDatesInMergedCells()
     }
 }
 
+void ScCopyPasteTest::tdf137625_autofillMergedUserlist()
+{
+    ScDocShellRef xDocSh = 
loadDocAndSetupModelViewController("tdf137625_autofillMergedUserlist.", 
FORMAT_ODS, true);
+    ScDocument& rDoc = xDocSh->GetDocument();
+
+    // Get the document controller
+    ScTabViewShell* pView = xDocSh->GetBestViewShell(false);
+    CPPUNIT_ASSERT(pView != nullptr);
+
+    // fillauto userlist, these areas contain only merged cells
+    pView->FillAuto(FILL_TO_RIGHT, 7, 5, 12, 7, 6);   //H6:M8
+    pView->FillAuto(FILL_TO_LEFT, 7, 5, 12, 7, 6);    //H6:M8
+    pView->FillAuto(FILL_TO_BOTTOM, 1, 20, 3, 23, 4); //B21:D24
+    pView->FillAuto(FILL_TO_TOP, 1, 20, 3, 23, 4);    //B21:D24
+
+    // compare the results of fill-right / -left with the reference stored in 
the test file
+    // this compares the whole area blindly, for specific test cases, check 
the test file
+    for (int nCol = 1; nCol <= 18; nCol++)
+    {
+        for (int nRow = 5; nRow <= 7; nRow++)
+        {
+            CellType nType1 = rDoc.GetCellType(ScAddress(nCol, nRow, 0));
+            CellType nType2 = rDoc.GetCellType(ScAddress(nCol, nRow + 4, 0));
+            double* pValue1 = rDoc.GetValueCell(ScAddress(nCol, nRow, 0));
+            double* pValue2 = rDoc.GetValueCell(ScAddress(nCol, nRow + 4, 0));
+
+            CPPUNIT_ASSERT_EQUAL(nType1, nType2);
+            if (pValue2 != nullptr)
+                CPPUNIT_ASSERT_EQUAL(*pValue1, *pValue2);   //cells with 
userlist value
+            else
+                CPPUNIT_ASSERT_EQUAL(pValue1, pValue2);     //empty cells
+        }
+    }
+
+    // compare the results of fill-up / -down
+    for (int nCol = 1; nCol <= 3; nCol++)
+    {
+        for (int nRow = 16; nRow <= 27; nRow++)
+        {
+            CellType nType1 = rDoc.GetCellType(ScAddress(nCol, nRow, 0));
+            CellType nType2 = rDoc.GetCellType(ScAddress(nCol + 4, nRow, 0));
+            double* pValue1 = rDoc.GetValueCell(ScAddress(nCol, nRow, 0));
+            double* pValue2 = rDoc.GetValueCell(ScAddress(nCol + 4, nRow, 0));
+
+            CPPUNIT_ASSERT_EQUAL(nType1, nType2);
+            if (pValue2 != nullptr)
+                CPPUNIT_ASSERT_EQUAL(*pValue1, *pValue2);   //cells with 
userlist value
+            else
+                CPPUNIT_ASSERT_EQUAL(pValue1, pValue2);     //empty cells
+        }
+    }
+}
+
+
+
 ScCopyPasteTest::ScCopyPasteTest()
       : ScBootstrapFixture( "sc/qa/unit/data" )
 {
diff --git a/sc/qa/unit/data/ods/tdf137625_autofillMergedUserlist.ods 
b/sc/qa/unit/data/ods/tdf137625_autofillMergedUserlist.ods
new file mode 100644
index 000000000000..aee3815f0292
Binary files /dev/null and 
b/sc/qa/unit/data/ods/tdf137625_autofillMergedUserlist.ods differ
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index d947e16cddd9..7d556031429d 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -420,8 +420,59 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
             }
             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
+                OUString aStr;
+                GetString(nColCurr, nRowCurr, aStr);
+
+                bool bAllSame = true;
+                for (SCSIZE i = 0; i < nValueCount; ++i)
+                {
+                    OUString aTestStr;
+                    GetString(static_cast<SCCOL>(nCol1 + 
rNonOverlappedCellIdx[i] * nAddX),
+                              static_cast<SCROW>(nRow1 + 
rNonOverlappedCellIdx[i] * nAddY),
+                              aTestStr);
+                    if (aStr != aTestStr)
+                    {
+                        bAllSame = false;
+                        break;
+                    }
+                }
+                if (bAllSame && nValueCount > 1)
+                    return;
+
+                rListData = 
const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
+                if (rListData)
+                {
+                    bool bMatchCase = false;
+                    (void)rListData->GetSubIndex(aStr, rListIndex, bMatchCase);
+                    size_t nListStrCount = rListData->GetSubCount();
+                    sal_uInt16 nPrevListIndex, nInc = 0;
+                    for (SCSIZE i = 1; i < nValueCount && rListData; i++)
+                    {
+                        nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX;
+                        nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY;
+                        GetString(nColCurr, nRowCurr, aStr);
+
+                        nPrevListIndex = rListIndex;
+                        if (!rListData->GetSubIndex(aStr, rListIndex, 
bMatchCase))
+                            rListData = nullptr;
+                        else
+                        {
+                            sal_Int32 nIncCurr = rListIndex - nPrevListIndex;
+                            if (nIncCurr < 0)
+                                nIncCurr += nListStrCount;
+                            if (i == 1)
+                                nInc = nIncCurr;
+                            else if (nInc != nIncCurr)
+                                rListData = nullptr;
+                        }
+                    }
+                    if (rListData) {
+                        rInc = nInc;
+                        rSkipOverlappedCells = true;
+                        return;
+                    }
+                }
+                // TODO: check / handle if it is a string containing a number
             }
         }
     }
@@ -997,37 +1048,94 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL 
nCol2, SCROW nRow2,
         if (pListData)
         {
             sal_uInt16 nListCount = pListData->GetSubCount();
-            if ( !bPositive )
+            if (bSkipOverlappedCells)
             {
-                //  nListIndex of FillAnalyse points to the last entry -> 
adjust
-                sal_uLong nSub = nISrcStart - nISrcEnd;
-                for (sal_uLong i=0; i<nSub; i++)
+                int nFillerCount = 1 + ( nISrcEnd - nISrcStart ) * (bPositive 
? 1 : -1);
+                std::vector<bool> aIsNonEmptyCell(nFillerCount, false);
+                SCCOLROW nLastValueIdx;
+                if (bPositive)
                 {
-                    if (nListIndex == 0) nListIndex = nListCount;
-                    --nListIndex;
+                    nLastValueIdx = nISrcEnd - (nFillerCount - 1 - 
aNonOverlappedCellIdx.back());
+                    for (auto i : aNonOverlappedCellIdx)
+                        aIsNonEmptyCell[i] = true;
+                }
+                else
+                {
+                    nLastValueIdx = nISrcEnd + aNonOverlappedCellIdx[0];
+                    for (auto i : aNonOverlappedCellIdx)
+                        aIsNonEmptyCell[nFillerCount - 1 - i] = true;
                 }
-            }
 
-            rInner = nIStart;
-            while (true)        // #i53728# with "for (;;)" old solaris/x86 
compiler mis-optimizes
-            {
-                if(!ColHidden(nCol) && !RowHidden(nRow))
+                OUString aStr;
+                if (bVertical)
+                    GetString(rOuter, nLastValueIdx, aStr);
+                else
+                    GetString(nLastValueIdx, rOuter, aStr);
+
+                bool bMatchCase = false;
+                (void)pListData->GetSubIndex(aStr, nListIndex, bMatchCase);
+
+                sal_Int32 nFillerIdx = 0;
+                rInner = nIStart;
+                while (true)
                 {
-                    if (bPositive)
+                    if (aIsNonEmptyCell[nFillerIdx])
                     {
-                        ++nListIndex;
-                        if (nListIndex >= nListCount) nListIndex = 0;
+                        if (bPositive)
+                        {
+                            nListIndex += nInc;
+                            if (nListIndex >= nListCount) nListIndex -= 
nListCount;
+                        }
+                        else
+                        {
+                            if (nListIndex < nInc) nListIndex += nListCount;
+                            nListIndex -= nInc;
+                        }
+                        aCol[nCol].SetRawString(static_cast<SCROW>(nRow), 
pListData->GetSubStr(nListIndex));
+
                     }
+                    if (rInner == nIEnd) break;
+                    nFillerIdx = (nFillerIdx + 1) % nFillerCount;
+                    if (bPositive)
+                        ++rInner;
                     else
+                        --rInner;
+                }
+            }
+            else
+            {
+                if (!bPositive)
+                {
+                    //  nListIndex of FillAnalyse points to the last entry -> 
adjust
+                    sal_uLong nSub = nISrcStart - nISrcEnd;
+                    for (sal_uLong i = 0; i < nSub; i++)
                     {
                         if (nListIndex == 0) nListIndex = nListCount;
                         --nListIndex;
                     }
-                    aCol[nCol].SetRawString(static_cast<SCROW>(nRow), 
pListData->GetSubStr(nListIndex));
                 }
 
-                if (rInner == nIEnd) break;
-                if (bPositive) ++rInner; else --rInner;
+                rInner = nIStart;
+                while (true)        // #i53728# with "for (;;)" old 
solaris/x86 compiler mis-optimizes
+                {
+                    if (!ColHidden(nCol) && !RowHidden(nRow))
+                    {
+                        if (bPositive)
+                        {
+                            ++nListIndex;
+                            if (nListIndex >= nListCount) nListIndex = 0;
+                        }
+                        else
+                        {
+                            if (nListIndex == 0) nListIndex = nListCount;
+                            --nListIndex;
+                        }
+                        aCol[nCol].SetRawString(static_cast<SCROW>(nRow), 
pListData->GetSubStr(nListIndex));
+                    }
+
+                    if (rInner == nIEnd) break;
+                    if (bPositive) ++rInner; else --rInner;
+                }
             }
             if(pProgress)
             {
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to