diff options
-rw-r--r-- | sc/qa/unit/copy_paste_test.cxx | 33 | ||||
-rw-r--r-- | sc/qa/unit/data/ods/tdf137205_AutofillDatesInMergedCells.ods | bin | 0 -> 15460 bytes | |||
-rw-r--r-- | sc/source/core/data/table4.cxx | 142 |
3 files changed, 143 insertions, 32 deletions
diff --git a/sc/qa/unit/copy_paste_test.cxx b/sc/qa/unit/copy_paste_test.cxx index 325a883d212d..12e0b64a3532 100644 --- a/sc/qa/unit/copy_paste_test.cxx +++ b/sc/qa/unit/copy_paste_test.cxx @@ -45,6 +45,7 @@ public: void testTdf40993_fillMergedCells(); void testTdf43958_clickSelectOnMergedCells(); void testTdf88782_autofillLinearNumbersInMergedCells(); + void tdf137205_autofillDatesInMergedCells(); CPPUNIT_TEST_SUITE(ScCopyPasteTest); CPPUNIT_TEST(testCopyPasteXLS); @@ -56,6 +57,7 @@ public: CPPUNIT_TEST(testTdf40993_fillMergedCells); CPPUNIT_TEST(testTdf43958_clickSelectOnMergedCells); CPPUNIT_TEST(testTdf88782_autofillLinearNumbersInMergedCells); + CPPUNIT_TEST(tdf137205_autofillDatesInMergedCells); CPPUNIT_TEST_SUITE_END(); private: @@ -638,7 +640,7 @@ void ScCopyPasteTest::testTdf88782_autofillLinearNumbersInMergedCells() aMergeOptions.maTabs.insert(0); xDocSh->GetDocFunc().MergeCells(aMergeOptions, false, true, true, false); - // fillauto numbers, these areas contains mostly merged cells + // fillauto numbers, these areas contain 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 @@ -679,6 +681,35 @@ void ScCopyPasteTest::testTdf88782_autofillLinearNumbersInMergedCells() } } } +void ScCopyPasteTest::tdf137205_autofillDatesInMergedCells() +{ + ScDocShellRef xDocSh = loadDocAndSetupModelViewController("tdf137205_AutofillDatesInMergedCells.", FORMAT_ODS, true); + ScDocument& rDoc = xDocSh->GetDocument(); + + // Get the document controller + ScTabViewShell* pView = xDocSh->GetBestViewShell(false); + CPPUNIT_ASSERT(pView != nullptr); + + // fillauto dates, this areas contain only merged cells + pView->FillAuto(FILL_TO_RIGHT, 1, 5, 4, 7, 8); //B6:E8 + + // compare the results of fill-right with the reference stored in the test file + // this compare the whole area blindly, for concrete test cases, check the test file + for (int nCol = 5; nCol <= 12; nCol++) { + for (int nRow = 5; nRow <= 7; nRow++) { + CellType nType1 = rDoc.GetCellType(ScAddress(nCol, nRow, 0)); + CellType nType2 = rDoc.GetCellType(ScAddress(nCol, nRow + 5, 0)); + double* pValue1 = rDoc.GetValueCell(ScAddress(nCol, nRow, 0)); + double* pValue2 = rDoc.GetValueCell(ScAddress(nCol, nRow + 5, 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 + } + } +} ScCopyPasteTest::ScCopyPasteTest() : ScBootstrapFixture( "sc/qa/unit/data" ) diff --git a/sc/qa/unit/data/ods/tdf137205_AutofillDatesInMergedCells.ods b/sc/qa/unit/data/ods/tdf137205_AutofillDatesInMergedCells.ods Binary files differnew file mode 100644 index 000000000000..9a62d575dbd2 --- /dev/null +++ b/sc/qa/unit/data/ods/tdf137205_AutofillDatesInMergedCells.ods diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index e2d86480cc72..11570e3153a4 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -254,15 +254,15 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, { bool bHasOverlappedCells = false; bool bSkipOverlappedCells = true; - SCCOL nColAkt = nCol1; - SCROW nRowAkt = nRow1; + SCCOL nColCurr = nCol1; + SCROW nRowCurr = 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); + const ScPatternAttr* pPattern = GetPattern(nColCurr, nRowCurr); bool bOverlapped = pPattern->GetItemSet().GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET && pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped(); @@ -270,7 +270,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, if (bOverlapped) bHasOverlappedCells = true; - if (!bOverlapped || GetCellValue(nColAkt, nRowAkt).meType != CELLTYPE_NONE) + if (!bOverlapped || GetCellValue(nColCurr, nRowCurr).meType != CELLTYPE_NONE) { rNonOverlappedCellIdx[nValueCount++] = i; // if there is at least 1 non empty overlapped cell, then no cell should be skipped @@ -278,8 +278,8 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bSkipOverlappedCells = false; } - nColAkt += nAddX; - nRowAkt += nAddY; + nColCurr += nAddX; + nRowCurr += nAddY; } rNonOverlappedCellIdx.resize(nValueCount); @@ -293,26 +293,106 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, if (bSkipOverlappedCells) { - nColAkt = nCol1 + rNonOverlappedCellIdx[0] * nAddX; - nRowAkt = nRow1 + rNonOverlappedCellIdx[0] * nAddY; - ScRefCellValue aPrevCell, aAktCell; - aAktCell = GetCellValue(nColAkt, nRowAkt); - CellType eCellType = aAktCell.meType; + nColCurr = nCol1 + rNonOverlappedCellIdx[0] * nAddX; + nRowCurr = nRow1 + rNonOverlappedCellIdx[0] * nAddY; + ScRefCellValue aPrevCell, aCurrCell; + aCurrCell = GetCellValue(nColCurr, nRowCurr); + CellType eCellType = aCurrCell.meType; if (eCellType == CELLTYPE_VALUE) { - // TODO: Check / handle special cases of number formats: like date, boolean + // TODO: Check / handle special cases of number formats like boolean bool bVal = true; - if (nValueCount >= 2) + SvNumFormatType nCurrCellFormatType + = rDocument.GetFormatTable()->GetType(GetNumberFormat(nColCurr, nRowCurr)); + if (nCurrCellFormatType == SvNumFormatType::DATE) + { + if (nValueCount >= 2) + { + long nCmpInc = 0; + FillDateCmd eType = FILL_YEAR; // just some temporary default values + long nDDiff = 0, nMDiff = 0, nYDiff = 0; // to avoid warnings + Date aNullDate = rDocument.GetFormatTable()->GetNullDate(); + Date aCurrDate = aNullDate, aPrevDate = aNullDate; + aCurrDate.AddDays(aCurrCell.mfValue); + for (SCSIZE i = 1; i < nValueCount && bVal; i++) + { + aPrevCell = aCurrCell; + aPrevDate = aCurrDate; + nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX; + nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY; + aCurrCell = GetCellValue(nColCurr, nRowCurr); + if (aCurrCell.meType == CELLTYPE_VALUE) + { + aCurrDate = aNullDate + static_cast<sal_Int32>(aCurrCell.mfValue); + if (eType != FILL_DAY) { + nDDiff = aCurrDate.GetDay() + - static_cast<long>(aPrevDate.GetDay()); + nMDiff = aCurrDate.GetMonth() + - static_cast<long>(aPrevDate.GetMonth()); + nYDiff = aCurrDate.GetYear() + - static_cast<long>(aPrevDate.GetYear()); + } + if (i == 1) + { + if (nDDiff != 0) + { + eType = FILL_DAY; + nCmpInc = aCurrDate - aPrevDate; + } + else + { + eType = FILL_MONTH; + nCmpInc = nMDiff + 12 * nYDiff; + } + } + else if (eType == FILL_DAY) + { + if (aCurrDate - aPrevDate != nCmpInc) + bVal = false; + } + else + { + if (nDDiff || (nMDiff + 12 * nYDiff != nCmpInc)) + bVal = false; + } + } + else + bVal = false; // No date is also not ok + } + if (bVal) + { + if (eType == FILL_MONTH && (nCmpInc % 12 == 0)) + { + eType = FILL_YEAR; + nCmpInc /= 12; + } + rCmd = FILL_DATE; + rDateCmd = eType; + rInc = nCmpInc; + rSkipOverlappedCells = true; + return; + } + } + else + { + rCmd = FILL_DATE; + rDateCmd = FILL_DAY; + rInc = 1.0; + rSkipOverlappedCells = true; + return; + } + } + else 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) + aPrevCell = aCurrCell; + nColCurr = nCol1 + rNonOverlappedCellIdx[i] * nAddX; + nRowCurr = nRow1 + rNonOverlappedCellIdx[i] * nAddY; + aCurrCell = GetCellValue(nColCurr, nRowCurr); + if (aCurrCell.meType == CELLTYPE_VALUE) { - double nDiff = approxDiff(aAktCell.mfValue, aPrevCell.mfValue); + double nDiff = approxDiff(aCurrCell.mfValue, aPrevCell.mfValue); if (i == 1) rInc = nDiff; if (!::rtl::math::approxEqual(nDiff, rInc, 13)) @@ -892,18 +972,18 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nMinDigits; ScUserListData* pListData = nullptr; sal_uInt16 nListIndex; - bool nSkipOverlappedCells; + bool bSkipOverlappedCells; std::vector<sal_Int32> aNonOverlappedCellIdx; if (bVertical) FillAnalyse(static_cast<SCCOL>(nCol),nRow1, static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd, nInc, nMinDigits, pListData, nListIndex, - bHasFiltered, nSkipOverlappedCells, aNonOverlappedCellIdx); + bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx); else FillAnalyse(nCol1,static_cast<SCROW>(nRow), nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd, nInc, nMinDigits, pListData, nListIndex, - bHasFiltered, nSkipOverlappedCells, aNonOverlappedCellIdx); + bHasFiltered, bSkipOverlappedCells, aNonOverlappedCellIdx); if (pListData) { @@ -961,12 +1041,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, nSkipOverlappedCells, &aNonOverlappedCellIdx); + pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx); else FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2, static_cast<SCROW>(nRow), nFillCount, eFillDir, eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false, - pProgress, nSkipOverlappedCells, &aNonOverlappedCellIdx); + pProgress, bSkipOverlappedCells, &aNonOverlappedCellIdx); if (pProgress) nProgress = pProgress->GetState(); } @@ -1020,7 +1100,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW sal_uInt16 nMinDigits; ScUserListData* pListData = nullptr; sal_uInt16 nListIndex; - bool nSkipOverlappedCells; + bool bSkipOverlappedCells; std::vector<sal_Int32> aNonOverlappedCellIdx; // Todo: update this function to calculate with merged cell fills, @@ -1028,7 +1108,7 @@ OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW // 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); + true, bSkipOverlappedCells, aNonOverlappedCellIdx); if ( pListData ) // user defined list { @@ -1963,25 +2043,25 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, // create a vector to make it easier to decide if a cell need to be filled, or skipped. aIsNonEmptyCell.resize(nFillerCount, false); - SCCOLROW nfirstValueIdx; + SCCOLROW nFirstValueIdx; if (bPositive) { - nfirstValueIdx = nISource + (*pNonOverlappedCellIdx)[0]; + nFirstValueIdx = nISource + (*pNonOverlappedCellIdx)[0]; for (auto i : (*pNonOverlappedCellIdx)) aIsNonEmptyCell[i] = true; } else { - nfirstValueIdx = nISource - (nFillerCount - 1 - (*pNonOverlappedCellIdx).back()); + 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)); + aSrcCell = aCol[nOStart].GetCellValue(static_cast<SCROW>(nFirstValueIdx)); else - aSrcCell = aCol[nfirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart)); + aSrcCell = aCol[nFirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart)); } const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow)); |