[Libreoffice-commits] core.git: 2 commits - sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Mar 28 17:59:14 PDT 2014


 sc/qa/unit/ucalc.cxx             |   48 ++++++++++++++++++
 sc/qa/unit/ucalc.hxx             |    2 
 sc/source/core/data/document.cxx |  101 ++++++++++++---------------------------
 3 files changed, 82 insertions(+), 69 deletions(-)

New commits:
commit 2ec45841b97a994ef9dca854e142598a063877fd
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Mar 28 20:50:29 2014 -0400

    rhbz#1080196: Delete the destination first then paste.
    
    Deleting in-between pasting was causing the block iterators to become
    invalid when the deletion took place, which resulted in a segfault.
    
    Also cleaned up the bits about handling filtered rows.  It was using the
    old row flag which is empty these days (so it never would have worked).
    Plus we do bail out earlier if the destination contains a filtered row.
    
    Change-Id: I78d3ee8bce1647c1c8685f92a3df3c38cc014811

diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index e9417bf..421d64e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2820,21 +2820,6 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
         pClipDoc->GetClipParam().mbCutMode = false;
 }
 
-static SCROW lcl_getLastNonFilteredRow(
-    const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags, SCROW nBegRow, SCROW nEndRow,
-    SCROW nRowCount)
-{
-    SCROW nFilteredRow = rFlags.GetFirstForCondition(
-        nBegRow, nEndRow, CR_FILTERED, CR_FILTERED);
-
-    SCROW nRow = nFilteredRow - 1;
-    if (nRow - nBegRow + 1 > nRowCount)
-        // make sure the row range stays within the data size.
-        nRow = nBegRow + nRowCount - 1;
-
-    return nRow;
-}
-
 void ScDocument::CopyMultiRangeFromClip(
     const ScAddress& rDestPos, const ScMarkData& rMark, sal_uInt16 nInsFlag, ScDocument* pClipDoc,
     bool bResetCut, bool bAsLink, bool /*bIncludeFiltered*/, bool bSkipAttrForEmpty)
@@ -2846,83 +2831,62 @@ void ScDocument::CopyMultiRangeFromClip(
         // There is nothing in the clip doc to copy.
         return;
 
-    bool bOldAutoCalc = GetAutoCalc();
-    SetAutoCalc( false );   // avoid multiple recalculations
+    // Right now, we don't allow pasting into filtered rows, so we don't even handle it here.
 
+    sc::AutoCalcSwitch aACSwitch(*this, false); // turn of auto calc temporarily.
     NumFmtMergeHandler aNumFmtMergeHdl(this, pClipDoc);
 
+    ScRange aDestRange;
+    rMark.GetMarkArea(aDestRange);
+
+    bInsertingFromOtherDoc = true;  // kein Broadcast/Listener aufbauen bei Insert
+
     SCCOL nCol1 = rDestPos.Col();
     SCROW nRow1 = rDestPos.Row();
     ScClipParam& rClipParam = pClipDoc->GetClipParam();
 
+    if (!bSkipAttrForEmpty)
+    {
+        // Do the deletion first.
+        sal_uInt16 nDelFlag = IDF_CONTENTS;
+        SCCOL nColSize = rClipParam.getPasteColSize();
+        SCROW nRowSize = rClipParam.getPasteRowSize();
+
+        DeleteArea(nCol1, nRow1, nCol1+nColSize-1, nRow1+nRowSize-1, rMark, nDelFlag);
+    }
+
     sc::CopyFromClipContext aCxt(*this, NULL, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
     std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
     aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
 
-    ScRange aDestRange;
-    rMark.GetMarkArea(aDestRange);
-    SCROW nLastMarkedRow = aDestRange.aEnd.Row();
-
-    bInsertingFromOtherDoc = true;  // kein Broadcast/Listener aufbauen bei Insert
-
-    SCROW nBegRow = nRow1;
-    sal_uInt16 nDelFlag = IDF_CONTENTS;
-    const ScBitMaskCompressedArray<SCROW, sal_uInt8>& rFlags = GetRowFlagsArray(aCxt.getTabStart());
-
-    for ( size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i )
+    for (size_t i = 0, n = rClipParam.maRanges.size(); i < n; ++i)
     {
-        ScRange* p = rClipParam.maRanges[ i ];
-        // The begin row must not be filtered.
+        ScRange* p = rClipParam.maRanges[i];
 
         SCROW nRowCount = p->aEnd.Row() - p->aStart.Row() + 1;
-
         SCsCOL nDx = static_cast<SCsCOL>(nCol1 - p->aStart.Col());
-        SCsROW nDy = static_cast<SCsROW>(nBegRow - p->aStart.Row());
+        SCsROW nDy = static_cast<SCsROW>(nRow1 - p->aStart.Row());
         SCCOL nCol2 = nCol1 + p->aEnd.Col() - p->aStart.Col();
+        SCROW nEndRow = nRow1 + nRowCount - 1;
 
-        SCROW nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
-
-        if (!bSkipAttrForEmpty)
-            DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
+        CopyBlockFromClip(aCxt, nCol1, nRow1, nCol2, nEndRow, rMark, nDx, nDy);
 
-        CopyBlockFromClip(aCxt, nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy);
-        nRowCount -= nEndRow - nBegRow + 1;
-
-        while (nRowCount > 0)
+        switch (rClipParam.meDirection)
         {
-            // Get the first non-filtered row.
-            SCROW nNonFilteredRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
-            if (nNonFilteredRow > nLastMarkedRow)
-                return;
-
-            SCROW nRowsSkipped = nNonFilteredRow - nEndRow - 1;
-            nDy += nRowsSkipped;
-
-            nBegRow = nNonFilteredRow;
-            nEndRow = lcl_getLastNonFilteredRow(rFlags, nBegRow, nLastMarkedRow, nRowCount);
-
-            if (!bSkipAttrForEmpty)
-                DeleteArea(nCol1, nBegRow, nCol2, nEndRow, rMark, nDelFlag);
-
-            CopyBlockFromClip(aCxt, nCol1, nBegRow, nCol2, nEndRow, rMark, nDx, nDy);
-            nRowCount -= nEndRow - nBegRow + 1;
+            case ScClipParam::Row:
+                // Begin row for the next range being pasted.
+                nRow1 += nRowCount;
+            break;
+            case ScClipParam::Column:
+                nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
+            break;
+            default:
+                ;
         }
-
-        if (rClipParam.meDirection == ScClipParam::Row)
-            // Begin row for the next range being pasted.
-            nBegRow = rFlags.GetFirstForCondition(nEndRow+1, nLastMarkedRow, CR_FILTERED, 0);
-        else
-            nBegRow = nRow1;
-
-        if (rClipParam.meDirection == ScClipParam::Column)
-            nCol1 += p->aEnd.Col() - p->aStart.Col() + 1;
     }
 
     bInsertingFromOtherDoc = false;
 
-    ScRangeList aRanges;
-    aRanges.Append(aDestRange);
-
     // Listener aufbauen nachdem alles inserted wurde
     StartListeningFromClip(aDestRange.aStart.Col(), aDestRange.aStart.Row(),
                            aDestRange.aEnd.Col(), aDestRange.aEnd.Row(), rMark, nInsFlag );
@@ -2932,7 +2896,6 @@ void ScDocument::CopyMultiRangeFromClip(
 
     if (bResetCut)
         pClipDoc->GetClipParam().mbCutMode = false;
-    SetAutoCalc( bOldAutoCalc );
 }
 
 void ScDocument::SetClipArea( const ScRange& rArea, bool bCut )
commit 915b7b5b90636e7af892361b155c8a242b7fab2e
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Mar 28 17:57:34 2014 -0400

    rhbz#1080196: Write unit test for this.
    
    Change-Id: I1c83afa40eaf8c81ca3b436c6fb7d22f7eb9f223

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 3fdf42f..7bb90ca 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -3414,6 +3414,54 @@ void Test::testCopyPasteTranspose()
 
 }
 
+void Test::testCopyPasteMultiRange()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    // Fill A2:B6 with numbers.
+    for (SCROW nRow = 1; nRow <= 5; ++nRow)
+    {
+        for (SCCOL nCol = 0; nCol <= 1; ++nCol)
+        {
+            ScAddress aPos(nCol,nRow,0);
+            m_pDoc->SetValue(aPos, nRow+nCol);
+        }
+    }
+
+    // Fill D9:E11 with numbers.
+    for (SCROW nRow = 8; nRow <= 10; ++nRow)
+    {
+        for (SCCOL nCol = 3; nCol <= 4; ++nCol)
+        {
+            ScAddress aPos(nCol,nRow,0);
+            m_pDoc->SetValue(aPos, 10.0);
+        }
+    }
+
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+
+    // Copy A2:B2, A4:B4, and A6:B6 to clipboard.
+    ScDocument aClipDoc(SCDOCMODE_CLIP);
+    ScClipParam aClipParam;
+    aClipParam.maRanges.Append(ScRange(0,1,0,1,1,0)); // A2:B2
+    aClipParam.maRanges.Append(ScRange(0,3,0,1,3,0)); // A4:B4
+    aClipParam.maRanges.Append(ScRange(0,5,0,1,5,0)); // A6:B6
+    aClipParam.meDirection = ScClipParam::Row;
+    m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
+
+    // Paste to D9:E11, and make sure it won't crash (rhbz#1080196).
+    m_pDoc->CopyMultiRangeFromClip(ScAddress(3,8,0), aMark, IDF_CONTENTS, &aClipDoc);
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,8,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,8,0)));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,9,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(4,9,0)));
+    CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(3,10,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(4,10,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testCopyPasteSkipEmpty()
 {
     struct Check
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 9cfcefc..9ff8d7a 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -255,6 +255,7 @@ public:
     void testCopyPaste();
     void testCopyPasteAsLink();
     void testCopyPasteTranspose();
+    void testCopyPasteMultiRange();
     void testCopyPasteSkipEmpty();
     void testCopyPasteSkipEmptyConditionalFormatting();
     void testUndoCut();
@@ -435,6 +436,7 @@ public:
     CPPUNIT_TEST(testCopyPaste);
     CPPUNIT_TEST(testCopyPasteAsLink);
     CPPUNIT_TEST(testCopyPasteTranspose);
+    CPPUNIT_TEST(testCopyPasteMultiRange);
     CPPUNIT_TEST(testCopyPasteSkipEmpty);
     //CPPUNIT_TEST(testCopyPasteSkipEmptyConditionalFormatting);
     CPPUNIT_TEST(testUndoCut);


More information about the Libreoffice-commits mailing list