From 7d52a5dff557117c0f8710eb27e61b328323ac90 Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Tue, 25 Nov 2014 00:02:21 -0500 Subject: Adjust ref undo to ensure group area listeners are used. When undoing row deletion (and possibly other similar undo's). And write test for it. Change-Id: I04b4fd9932f4236f124dcd25967355c6055dec33 (cherry picked from commit 0dae7466fff1e742543ef7512b7dd22472c75624) --- sc/inc/cellvalue.hxx | 2 +- sc/inc/clipcontext.hxx | 5 ++ sc/inc/column.hxx | 17 +++-- sc/inc/document.hxx | 2 + sc/inc/formulacell.hxx | 9 +-- sc/inc/grouparealistener.hxx | 6 +- sc/inc/stringutil.hxx | 3 + sc/inc/table.hxx | 5 +- sc/inc/types.hxx | 7 +++ sc/qa/unit/ucalc.hxx | 25 +++++++- sc/qa/unit/ucalc_sharedformula.cxx | 101 ++++++++++++++++++++++++++++++ sc/source/core/data/bcaslot.cxx | 24 +++++++ sc/source/core/data/cellvalue.cxx | 4 +- sc/source/core/data/clipcontext.cxx | 14 ++++- sc/source/core/data/column.cxx | 36 +++++++++-- sc/source/core/data/column3.cxx | 43 +++++++++---- sc/source/core/data/column4.cxx | 2 - sc/source/core/data/document.cxx | 28 +++++---- sc/source/core/data/document10.cxx | 34 ++++++++++ sc/source/core/data/formulacell.cxx | 59 +++++++++++++++-- sc/source/core/data/table2.cxx | 14 ++++- sc/source/core/inc/bcaslot.hxx | 5 ++ sc/source/core/tool/grouparealistener.cxx | 17 ++++- sc/source/core/tool/stringutil.cxx | 3 +- sc/source/ui/undo/refundo.cxx | 38 ++++++----- 25 files changed, 427 insertions(+), 76 deletions(-) (limited to 'sc') diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx index 9154e30ddacd..3a2d3c8678d1 100644 --- a/sc/inc/cellvalue.hxx +++ b/sc/inc/cellvalue.hxx @@ -76,7 +76,7 @@ struct SC_DLLPUBLIC ScCellValue */ void release( ScDocument& rDoc, const ScAddress& rPos ); - void release( ScColumn& rColumn, SCROW nRow ); + void release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType = sc::SingleCellListening ); OUString getString( const ScDocument* pDoc ); diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx index 3891274d7283..aa783e4aa203 100644 --- a/sc/inc/clipcontext.hxx +++ b/sc/inc/clipcontext.hxx @@ -144,9 +144,14 @@ public: class CopyToDocContext : public ClipContextBase { + bool mbStartListening; + public: CopyToDocContext(ScDocument& rDoc); virtual ~CopyToDocContext(); + + void setStartListening( bool b ); + bool isStartListening() const; }; class MixDocContext : public ClipContextBase diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 102af126fc78..7f883a63ed76 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -314,8 +314,12 @@ public: * @return pCell if it was successfully inserted, NULL otherwise. pCell * is deleted automatically on failure to insert. */ - ScFormulaCell* SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool bSingle = false ); - ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell ); + ScFormulaCell* SetFormulaCell( + SCROW nRow, ScFormulaCell* pCell, + sc::StartListeningType eListenType = sc::SingleCellListening ); + ScFormulaCell* SetFormulaCell( + sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell, + sc::StartListeningType eListenType = sc::SingleCellListening ); bool SetFormulaCells( SCROW nRow, std::vector& rCells ); @@ -639,10 +643,15 @@ private: sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow ); sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow ); + void AttachNewFormulaCell( - const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin = true, bool bSingle = false ); + const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, + bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening ); + void AttachNewFormulaCell( - const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin = true, bool bSingle = false ); + const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, + bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening ); + void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength ); void BroadcastNewCell( SCROW nRow ); bool UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, const sc::CellStoreType::iterator& itr ); diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 554ee3a9afc1..31fde4db04c5 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1916,6 +1916,8 @@ public: void SetHardRecalcState( bool bVal ) { bHardRecalcState = bVal; } void StartAllListeners(); void StartNeededListeners(); + void StartAllListeners( const ScRange& rRange ); + void EndAllListeners( const ScRange& rRange ); const ScFormulaCell* GetFormulaTree() const { return pFormulaTree; } bool HasForcedFormulas() const { return bHasForcedFormulas; } void SetForcedFormulas( bool bVal ) { bHasForcedFormulas = bVal; } diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 50a6f6cb3a64..86b8045ee1d6 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -58,7 +57,11 @@ class ScTokenArray; struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable { - typedef boost::ptr_vector AreaListenersType; +private: + struct Impl; + Impl* mpImpl; + +public: mutable size_t mnRefCount; @@ -73,8 +76,6 @@ struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable sal_uInt8 meCalcState; sal_uInt8 meKernelState; - AreaListenersType maAreaListeners; - ScFormulaCellGroup(); ~ScFormulaCellGroup(); diff --git a/sc/inc/grouparealistener.hxx b/sc/inc/grouparealistener.hxx index 5abb0e8ebb92..2c6ea50e2f8c 100644 --- a/sc/inc/grouparealistener.hxx +++ b/sc/inc/grouparealistener.hxx @@ -32,6 +32,7 @@ class FormulaGroupAreaListener : public SvtListener FormulaGroupAreaListener(); // disabled public: + FormulaGroupAreaListener( const ScRange& rRange, ScFormulaCell** ppTopCell, SCROW nGroupLen, bool bStartFixed, bool bEndFixed ); @@ -52,10 +53,11 @@ public: */ void collectFormulaCells( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector& rCells ) const; -#if DEBUG_AREA_BROADCASTER ScAddress getTopCellPos() const; + const ScRange& getRange() const; SCROW getGroupLength() const; -#endif + bool isStartFixed() const; + bool isEndFixed() const; private: void notifyCellChange( const SfxHint& rHint, const ScAddress& rPos ); diff --git a/sc/inc/stringutil.hxx b/sc/inc/stringutil.hxx index 0d536db87836..ef7bd50f3db6 100644 --- a/sc/inc/stringutil.hxx +++ b/sc/inc/stringutil.hxx @@ -23,6 +23,7 @@ #include #include "scdllapi.h" #include +#include class SvNumberFormatter; @@ -79,6 +80,8 @@ struct SC_DLLPUBLIC ScSetStringParam */ bool mbHandleApostrophe; + sc::StartListeningType meStartListening; + ScSetStringParam(); /** diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 0d0a5c43a9c0..df3372ecef3f 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -437,10 +437,13 @@ public: sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCsCOL nDx, SCsROW nDy, ScTable* pTable ); - void StartListeningFromClip( + void StartListeningFormulaCells( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + void EndListeningFormulaCells( + sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + void SetDirtyFromClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::ColumnSpanSet& rBroadcastSpans ); diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index e483b1eff98e..d92c9b5b9430 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -108,6 +108,13 @@ enum AreaOverlapType OneColumnInsideArea }; +enum StartListeningType +{ + ConvertToGroupListening, + SingleCellListening, + NoListening +}; + } #endif diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index 7cad0ad9d299..e20b069895ea 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -12,6 +12,7 @@ #include "helper/qahelper.hxx" #include "document.hxx" +#include struct TestImpl; class ScUndoPaste; @@ -55,9 +56,16 @@ public: static void setCalcAsShown(ScDocument* pDoc, bool bCalcAsShown); + template - static ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount) + static ScRange insertRangeData( + ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount, + bool bGroupListening = false ) { + // TODO : Ideally bGroupListening should be always true for all tests. + // Eventually we want to drop this parameter once all tests pass with + // group listening turned on. + ScRange aRange(rPos); aRange.aEnd.SetCol(rPos.Col()+_Size-1); aRange.aEnd.SetRow(rPos.Row()+nRowCount-1); @@ -73,10 +81,21 @@ public: SCCOL nCol = i + rPos.Col(); SCROW nRow = j + rPos.Row(); - pDoc->SetString(nCol, nRow, rPos.Tab(), OUString(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8)); + OUString aStr(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8); + if (bGroupListening) + { + ScSetStringParam aParam; // Leave default. + aParam.meStartListening = sc::NoListening; + pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, &aParam); + } + else + pDoc->SetString(nCol, nRow, rPos.Tab(), aStr, NULL); } } + if (bGroupListening) + pDoc->StartAllListeners(aRange); + printRange(pDoc, aRange, "Range data content"); return aRange; } @@ -300,6 +319,7 @@ public: void testSharedFormulasRefUpdateMove(); void testSharedFormulasRefUpdateMove2(); void testSharedFormulasRefUpdateRange(); + void testSharedFormulasRefUpdateRangeDeleteRow(); void testSharedFormulasRefUpdateExternal(); void testSharedFormulasInsertRow(); void testSharedFormulasDeleteRows(); @@ -529,6 +549,7 @@ public: CPPUNIT_TEST(testSharedFormulasRefUpdateMove); CPPUNIT_TEST(testSharedFormulasRefUpdateMove2); CPPUNIT_TEST(testSharedFormulasRefUpdateRange); + CPPUNIT_TEST(testSharedFormulasRefUpdateRangeDeleteRow); CPPUNIT_TEST(testSharedFormulasRefUpdateExternal); CPPUNIT_TEST(testSharedFormulasInsertRow); CPPUNIT_TEST(testSharedFormulasDeleteRows); diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx index 16d55771f9d7..811612379163 100644 --- a/sc/qa/unit/ucalc_sharedformula.cxx +++ b/sc/qa/unit/ucalc_sharedformula.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -580,6 +581,106 @@ void Test::testSharedFormulasRefUpdateRange() m_pDoc->DeleteTab(0); } +void Test::testSharedFormulasRefUpdateRangeDeleteRow() +{ + sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc. + m_pDoc->InsertTab(0, "Formula"); + + ScRange aWholeArea(0, 0, 0, 100, 100, 0); // Large enough for all references used in the test. + + const char* aData[][3] = { + { "1", "2", "=SUM(A1:B1)" }, + { "3", "4", "=SUM(A2:B2)" }, + { 0, 0, 0 }, + { "5", "6", "=SUM(A4:B4)" }, + { "7", "8", "=SUM(A5:B5)" } + }; + + insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData), true); + + // Check initial formula values. + CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0))); + CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0))); + CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0))); + CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0))); + + // Check the area listener status. + ScBroadcastAreaSlotMachine* pBASM = m_pDoc->GetBASM(); + CPPUNIT_ASSERT(pBASM); + std::vector aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside); + std::sort(aListeners.begin(), aListeners.end(), sc::AreaListener::SortByArea()); + + CPPUNIT_ASSERT_MESSAGE("There should only be 2 area listeners.", aListeners.size() == 2); + // First one should be group-listening on A1:B2. + CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0)); + CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening); + // Second one should be group-listening on A4:B5. + CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0)); + CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening); + + // Make sure that C1:C2 and C4:C5 are formula groups. + const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0)); + CPPUNIT_ASSERT(pFC); + CPPUNIT_ASSERT_EQUAL(static_cast(0), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), pFC->GetSharedLength()); + + pFC = m_pDoc->GetFormulaCell(ScAddress(2,3,0)); + CPPUNIT_ASSERT(pFC); + CPPUNIT_ASSERT_EQUAL(static_cast(3), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), pFC->GetSharedLength()); + + // Delete row 3. This will merge the two formula groups. + ScDocFunc& rFunc = getDocShell().GetDocFunc(); + ScMarkData aMark; + aMark.SelectOneTable(0); + rFunc.DeleteCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, DEL_DELROWS, true, true); + + // Make sure C1:C4 belong to the same group. + pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0)); + CPPUNIT_ASSERT(pFC); + CPPUNIT_ASSERT_EQUAL(static_cast(0), pFC->GetSharedTopRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(4), pFC->GetSharedLength()); + + // We should only have one listener group-listening on A1:B4. + aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside); + CPPUNIT_ASSERT_MESSAGE("There should only be 1 area listener.", aListeners.size() == 1); + CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B4.", aListeners[0].maArea == ScRange(0,0,0,1,3,0)); + CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening); + + // Change the value of B4 and make sure the value of C4 changes. + rFunc.SetValueCell(ScAddress(1,3,0), 100.0, false); + CPPUNIT_ASSERT_EQUAL(107.0, m_pDoc->GetValue(ScAddress(2,3,0))); + + SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager(); + CPPUNIT_ASSERT(pUndoMgr); + + // Undo the value change in B4, and make sure C4 follows. + pUndoMgr->Undo(); + CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,3,0))); + + // Undo the deletion of row 3. + pUndoMgr->Undo(); + + // Check the values of formula cells again. + CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(2,0,0))); + CPPUNIT_ASSERT_EQUAL( 7.0, m_pDoc->GetValue(ScAddress(2,1,0))); + CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,3,0))); + CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc->GetValue(ScAddress(2,4,0))); + + aListeners = pBASM->GetAllListeners(aWholeArea, sc::AreaInside); + std::sort(aListeners.begin(), aListeners.end(), sc::AreaListener::SortByArea()); + + CPPUNIT_ASSERT_MESSAGE("There should only be 2 area listeners.", aListeners.size() == 2); + // First one should be group-listening on A1:B2. + CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0)); + CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening); + // Second one should be group-listening on A4:B5. + CPPUNIT_ASSERT_MESSAGE("This listener should be listening on A1:B2.", aListeners[0].maArea == ScRange(0,0,0,1,1,0)); + CPPUNIT_ASSERT_MESSAGE("This listener should be group-listening.", aListeners[0].mbGroupListening); + + m_pDoc->DeleteTab(0); +} + void Test::testSharedFormulasRefUpdateExternal() { sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc. diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx index 0678a7febc70..4290fbd402ea 100644 --- a/sc/source/core/data/bcaslot.cxx +++ b/sc/source/core/data/bcaslot.cxx @@ -64,6 +64,30 @@ // STATIC DATA ----------------------------------------------------------- +namespace sc { + +bool AreaListener::SortByArea::operator ()( const AreaListener& rLeft, const AreaListener& rRight ) const +{ + if (rLeft.maArea.aStart.Tab() != rRight.maArea.aStart.Tab()) + return rLeft.maArea.aStart.Tab() < rRight.maArea.aStart.Tab(); + + if (rLeft.maArea.aStart.Col() != rRight.maArea.aStart.Col()) + return rLeft.maArea.aStart.Col() < rRight.maArea.aStart.Col(); + + if (rLeft.maArea.aStart.Row() != rRight.maArea.aStart.Row()) + return rLeft.maArea.aStart.Row() < rRight.maArea.aStart.Row(); + + if (rLeft.maArea.aEnd.Tab() != rRight.maArea.aEnd.Tab()) + return rLeft.maArea.aEnd.Tab() < rRight.maArea.aEnd.Tab(); + + if (rLeft.maArea.aEnd.Col() != rRight.maArea.aEnd.Col()) + return rLeft.maArea.aEnd.Col() < rRight.maArea.aEnd.Col(); + + return rLeft.maArea.aEnd.Row() < rRight.maArea.aEnd.Row(); +} + +} + struct ScSlotData { SCROW nStartRow; // first row of this segment diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx index b9eb32b2bc34..8a69d12dafbe 100644 --- a/sc/source/core/data/cellvalue.cxx +++ b/sc/source/core/data/cellvalue.cxx @@ -440,7 +440,7 @@ void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos ) mfValue = 0.0; } -void ScCellValue::release( ScColumn& rColumn, SCROW nRow ) +void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType ) { switch (meType) { @@ -460,7 +460,7 @@ void ScCellValue::release( ScColumn& rColumn, SCROW nRow ) break; case CELLTYPE_FORMULA: // This formula cell instance is directly placed in the document without copying. - rColumn.SetFormulaCell(nRow, mpFormula); + rColumn.SetFormulaCell(nRow, mpFormula, eListenType); break; default: rColumn.Delete(nRow); diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx index 5fd08da7ef0c..83003273b62b 100644 --- a/sc/source/core/data/clipcontext.cxx +++ b/sc/source/core/data/clipcontext.cxx @@ -327,9 +327,21 @@ bool CopyToClipContext::isCloneNotes() const return mbCloneNotes; } -CopyToDocContext::CopyToDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {} +CopyToDocContext::CopyToDocContext(ScDocument& rDoc) : + ClipContextBase(rDoc), mbStartListening(true) {} + CopyToDocContext::~CopyToDocContext() {} +void CopyToDocContext::setStartListening( bool b ) +{ + mbStartListening = b; +} + +bool CopyToDocContext::isStartListening() const +{ + return mbStartListening; +} + MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {} MixDocContext::~MixDocContext() {} diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index c0e2991912c3..d9532307409e 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -1232,6 +1232,8 @@ class CopyAsLinkHandler sc::ColumnBlockPosition* mpDestPos; InsertDeleteFlags mnCopyFlags; + sc::StartListeningType meListenType; + void setDefaultAttrToDest(size_t nRow) { maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set( @@ -1263,7 +1265,7 @@ class CopyAsLinkHandler for (size_t i = 0; i < nDataSize; ++i) { SCROW nRow = nTopRow + i; - mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow)); + mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow), meListenType); } setDefaultAttrsToDest(nTopRow, nDataSize); @@ -1276,7 +1278,11 @@ class CopyAsLinkHandler public: CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) : - mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags) + mrSrcCol(rSrcCol), + mrDestCol(rDestCol), + mpDestPos(pDestPos), + mnCopyFlags(nCopyFlags), + meListenType(sc::SingleCellListening) { if (mpDestPos) maDestPos = *mpDestPos; @@ -1288,6 +1294,11 @@ public: *mpDestPos = maDestPos; } + void setStartListening( bool b ) + { + meListenType = b ? sc::SingleCellListening : sc::NoListening; + } + void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize) { size_t nRow = aNode.position + nOffset; @@ -1353,6 +1364,8 @@ class CopyByCloneHandler svl::SharedStringPool* mpSharedStringPool; InsertDeleteFlags mnCopyFlags; + sc::StartListeningType meListenType; + void setDefaultAttrToDest(size_t nRow) { maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set( @@ -1396,7 +1409,7 @@ class CopyByCloneHandler // Clone as formula cell. ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos); pCell->SetDirtyVar(); - mrDestCol.SetFormulaCell(maDestPos, nRow, pCell); + mrDestCol.SetFormulaCell(maDestPos, nRow, pCell, meListenType); setDefaultAttrToDest(nRow); return; } @@ -1412,7 +1425,7 @@ class CopyByCloneHandler // error codes are cloned with values ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos); pErrCell->SetErrCode(nErr); - mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell); + mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell, meListenType); setDefaultAttrToDest(nRow); return; } @@ -1466,8 +1479,12 @@ class CopyByCloneHandler public: CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool) : - mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mpSharedStringPool(pSharedStringPool), - mnCopyFlags(nCopyFlags) + mrSrcCol(rSrcCol), + mrDestCol(rDestCol), + mpDestPos(pDestPos), + mpSharedStringPool(pSharedStringPool), + mnCopyFlags(nCopyFlags), + meListenType(sc::SingleCellListening) { if (mpDestPos) maDestPos = *mpDestPos; @@ -1479,6 +1496,11 @@ public: *mpDestPos = maDestPos; } + void setStartListening( bool b ) + { + meListenType = b ? sc::SingleCellListening : sc::NoListening; + } + void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize) { size_t nRow = aNode.position + nOffset; @@ -1642,6 +1664,7 @@ void ScColumn::CopyToColumn( if (bAsLink) { CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags); + aFunc.setStartListening(rCxt.isStartListening()); sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2); } else @@ -1653,6 +1676,7 @@ void ScColumn::CopyToColumn( &rColumn.pDocument->GetSharedStringPool() : NULL; CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags, pSharedStringPool); + aFunc.setStartListening(rCxt.isStartListening()); sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2); } diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index ae58aecf50a5..803bd3520811 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -377,13 +377,15 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy } void ScColumn::AttachNewFormulaCell( - const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin, bool bSingle ) + const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, + bool bJoin, sc::StartListeningType eListenType ) { - AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, bSingle); + AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, eListenType); } void ScColumn::AttachNewFormulaCell( - const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin, bool bSingle ) + const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, + bool bJoin, sc::StartListeningType eListenType ) { if (bJoin) // See if this new formula cell can join an existing shared formula group. @@ -394,9 +396,12 @@ void ScColumn::AttachNewFormulaCell( // we call StartListeningFromClip and BroadcastFromClip. // If we insert into the Clipboard/andoDoc, we do not use a Broadcast. // After Import we call CalcAfterLoad and in there Listening. - if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc()) + if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) + return; + + switch (eListenType) { - if (bSingle) + case sc::ConvertToGroupListening: { boost::shared_ptr pPosSet(new sc::ColumnBlockPositionSet(*pDocument)); sc::StartListeningContext aStartCxt(*pDocument, pPosSet); @@ -404,12 +409,18 @@ void ScColumn::AttachNewFormulaCell( SCROW nRow = aPos.first->position + aPos.second; StartListeningFormulaCells(aStartCxt, aEndCxt, nRow, nRow); } - else + break; + case sc::SingleCellListening: rCell.StartListeningTo(pDocument); + break; + case sc::NoListening: + default: + ; - if (!pDocument->IsCalcingAfterLoad()) - rCell.SetDirty(); } + + if (!pDocument->IsCalcingAfterLoad()) + rCell.SetDirty(); } void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength ) @@ -1734,7 +1745,10 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString, ScCellValue aNewCell; bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam); - aNewCell.release(*this, nRow); + if (pParam) + aNewCell.release(*this, nRow, pParam->meStartListening); + else + aNewCell.release(*this, nRow); // Do not set Formats and Formulas here anymore! // These are queried during output @@ -1834,7 +1848,8 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul AttachNewFormulaCell(it, nRow, *pCell); } -ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool bSingle ) +ScFormulaCell* ScColumn::SetFormulaCell( + SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType ) { sc::CellStoreType::iterator it = GetPositionToInsert(nRow); sal_uInt32 nCellFormat = GetNumberFormat(nRow); @@ -1845,11 +1860,13 @@ ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, bool CellStorageModified(); - AttachNewFormulaCell(it, nRow, *pCell, true, bSingle); + AttachNewFormulaCell(it, nRow, *pCell, true, eListenType); return pCell; } -ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell ) +ScFormulaCell* ScColumn::SetFormulaCell( + sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell, + sc::StartListeningType eListenType ) { rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); sal_uInt32 nCellFormat = GetNumberFormat(nRow); @@ -1861,7 +1878,7 @@ ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCR CellStorageModified(); - AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell); + AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, true, eListenType); return pCell; } diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 42d166a0e7c0..ab804ddf4340 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -1240,8 +1240,6 @@ public: { return mnEndRow; } - -private: }; class EndListeningFormulaCellsHandler diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index a206c09b5e04..660b39469133 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -1960,8 +1960,8 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, PutInOrder( nTab1, nTab2 ); if (ValidTab(nTab1) && ValidTab(nTab2)) { - bool bOldAutoCalc = pDestDoc->GetAutoCalc(); - pDestDoc->SetAutoCalc( false ); // avoid multiple calculations + sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations + if (nTab1 > 0) CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, false, pDestDoc, pMarks ); @@ -1976,7 +1976,6 @@ void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, if (nTab2 < MAXTAB) CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, false, pDestDoc, pMarks ); - pDestDoc->SetAutoCalc( bOldAutoCalc ); } } @@ -1989,21 +1988,26 @@ void ScDocument::CopyToDocument(const ScRange& rRange, if( pDestDoc->aDocName.isEmpty() ) pDestDoc->aDocName = aDocName; - bool bOldAutoCalc = pDestDoc->GetAutoCalc(); - pDestDoc->SetAutoCalc( false ); // avoid multiple calculations + + sc::AutoCalcSwitch aACSwitch(*pDestDoc, false); // avoid multiple calculations + sc::CopyToDocContext aCxt(*pDestDoc); + aCxt.setStartListening(false); + SCTAB nMinSizeBothTabs = static_cast(std::min(maTabs.size(), pDestDoc->maTabs.size())); for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab() && i < nMinSizeBothTabs; i++) { - if (!TableExists(i) || !pDestDoc->TableExists(i)) + ScTable* pTab = FetchTable(i); + ScTable* pDestTab = pDestDoc->FetchTable(i); + if (!pTab || !pDestTab) continue; - maTabs[i]->CopyToTable(aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), - aNewRange.aEnd.Col(), aNewRange.aEnd.Row(), - nFlags, bOnlyMarked, pDestDoc->maTabs[i], - pMarks, false, bColRowFlags); + pTab->CopyToTable( + aCxt, aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aEnd.Row(), + nFlags, bOnlyMarked, pDestTab, pMarks, false, bColRowFlags); } - pDestDoc->SetAutoCalc( bOldAutoCalc ); + + pDestDoc->StartAllListeners(aNewRange); } void ScDocument::UndoToDocument(const ScRange& rRange, @@ -2452,7 +2456,7 @@ void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1, ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end(); for (; itr != itrEnd && *itr < nMax; ++itr) if (maTabs[*itr]) - maTabs[*itr]->StartListeningFromClip(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2); + maTabs[*itr]->StartListeningFormulaCells(aStartCxt, aEndCxt, nCol1, nRow1, nCol2, nRow2); } } diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index d1b41687fb3e..c01b2647a755 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -423,4 +423,38 @@ void ScDocument::StartNeededListeners() std::for_each(maTabs.begin(), maTabs.end(), StartNeededListenersHandler(*this)); } +void ScDocument::StartAllListeners( const ScRange& rRange ) +{ + boost::shared_ptr pPosSet(new sc::ColumnBlockPositionSet(*this)); + sc::StartListeningContext aStartCxt(*this, pPosSet); + sc::EndListeningContext aEndCxt(*this, pPosSet); + + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + pTab->StartListeningFormulaCells( + aStartCxt, aEndCxt, + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); + } +} + +void ScDocument::EndAllListeners( const ScRange& rRange ) +{ + sc::EndListeningContext aEndCxt(*this); + + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + pTab->EndListeningFormulaCells( + aEndCxt, + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index dfeda726016f..a34d3fb139f4 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -61,6 +61,7 @@ #include #include +#include using namespace formula; @@ -382,6 +383,40 @@ void adjustDBRange(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScD pToken->SetIndex(pNewDBData->GetIndex()); } +struct AreaListenerKey +{ + ScRange maRange; + bool mbStartFixed; + bool mbEndFixed; + + AreaListenerKey( const ScRange& rRange, bool bStartFixed, bool bEndFixed ) : + maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {} + + bool operator < ( const AreaListenerKey& r ) const + { + if (maRange.aStart.Tab() != r.maRange.aStart.Tab()) + return maRange.aStart.Tab() < r.maRange.aStart.Tab(); + if (maRange.aStart.Col() != r.maRange.aStart.Col()) + return maRange.aStart.Col() < r.maRange.aStart.Col(); + if (maRange.aStart.Row() != r.maRange.aStart.Row()) + return maRange.aStart.Row() < r.maRange.aStart.Row(); + if (maRange.aEnd.Tab() != r.maRange.aEnd.Tab()) + return maRange.aEnd.Tab() < r.maRange.aEnd.Tab(); + if (maRange.aEnd.Col() != r.maRange.aEnd.Col()) + return maRange.aEnd.Col() < r.maRange.aEnd.Col(); + if (maRange.aEnd.Row() != r.maRange.aEnd.Row()) + return maRange.aEnd.Row() < r.maRange.aEnd.Row(); + if (mbStartFixed != r.mbStartFixed) + return r.mbStartFixed; + if (mbEndFixed != r.mbEndFixed) + return r.mbEndFixed; + + return false; + } +}; + +typedef boost::ptr_map AreaListenersType; + } #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION @@ -406,7 +441,13 @@ int ScFormulaCellGroup::snCount = 0; rtl::Reference ScFormulaCellGroup::sxCompilationThread; #endif +struct ScFormulaCellGroup::Impl +{ + AreaListenersType maAreaListeners; +}; + ScFormulaCellGroup::ScFormulaCellGroup() : + mpImpl(new Impl), mnRefCount(0), mpCode(NULL), mpCompiledFormula(NULL), @@ -450,6 +491,7 @@ ScFormulaCellGroup::~ScFormulaCellGroup() #endif delete mpCode; delete mpCompiledFormula; + delete mpImpl; } void ScFormulaCellGroup::scheduleCompilation() @@ -512,24 +554,29 @@ void ScFormulaCellGroup::compileOpenCLKernel() sc::FormulaGroupAreaListener* ScFormulaCellGroup::getAreaListener( ScFormulaCell** ppTopCell, const ScRange& rRange, bool bStartFixed, bool bEndFixed ) { - // TODO : Find existing one with the same criteria. - maAreaListeners.push_back(new sc::FormulaGroupAreaListener(rRange, ppTopCell, mnLength, bStartFixed, bEndFixed)); - return &maAreaListeners.back(); + AreaListenerKey aKey(rRange, bStartFixed, bEndFixed); + + std::pair r = + mpImpl->maAreaListeners.insert( + aKey, new sc::FormulaGroupAreaListener( + rRange, ppTopCell, mnLength, bStartFixed, bEndFixed)); + + return r.first->second; } void ScFormulaCellGroup::endAllGroupListening( ScDocument& rDoc ) { - AreaListenersType::iterator it = maAreaListeners.begin(), itEnd = maAreaListeners.end(); + AreaListenersType::iterator it = mpImpl->maAreaListeners.begin(), itEnd = mpImpl->maAreaListeners.end(); for (; it != itEnd; ++it) { - sc::FormulaGroupAreaListener* pListener = &(*it); + sc::FormulaGroupAreaListener* pListener = it->second; ScRange aListenRange = pListener->getListeningRange(); // This "always listen" special range is never grouped. bool bGroupListening = (aListenRange != BCA_LISTEN_ALWAYS); rDoc.EndListeningArea(aListenRange, bGroupListening, pListener); } - maAreaListeners.clear(); + mpImpl->maAreaListeners.clear(); } ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos ) : diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 97355424c8c3..608ec13014a4 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -1057,7 +1057,7 @@ void ScTable::SetDirtyFromClip( aCol[i].SetDirtyFromClip(nRow1, nRow2, rBroadcastSpans); } -void ScTable::StartListeningFromClip( +void ScTable::StartListeningFormulaCells( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { @@ -1068,6 +1068,16 @@ void ScTable::StartListeningFromClip( aCol[i].StartListeningFormulaCells(rStartCxt, rEndCxt, nRow1, nRow2); } +void ScTable::EndListeningFormulaCells( + sc::EndListeningContext& rEndCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) +{ + if (nCol2 > MAXCOL) nCol2 = MAXCOL; + if (nRow2 > MAXROW) nRow2 = MAXROW; + if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2)) + for (SCCOL i = nCol1; i <= nCol2; ++i) + aCol[i].EndListeningFormulaCells(rEndCxt, nRow1, nRow2); +} + void ScTable::CopyToTable( sc::CopyToDocContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScTable* pDestTab, const ScMarkData* pMarkData, @@ -1413,7 +1423,7 @@ ScFormulaCell* ScTable::SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* p return NULL; } - return aCol[nCol].SetFormulaCell(nRow, pCell, true); + return aCol[nCol].SetFormulaCell(nRow, pCell, sc::ConvertToGroupListening); } bool ScTable::SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector& rCells ) diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx index 63e5a6b8802a..7eea13654fad 100644 --- a/sc/source/core/inc/bcaslot.hxx +++ b/sc/source/core/inc/bcaslot.hxx @@ -40,6 +40,11 @@ struct AreaListener ScRange maArea; bool mbGroupListening; SvtListener* mpListener; + + struct SortByArea : std::binary_function + { + bool operator() ( const AreaListener& rLeft, const AreaListener& rRight ) const; + }; }; } diff --git a/sc/source/core/tool/grouparealistener.cxx b/sc/source/core/tool/grouparealistener.cxx index e93d2fc92364..4a13398c2e46 100644 --- a/sc/source/core/tool/grouparealistener.cxx +++ b/sc/source/core/tool/grouparealistener.cxx @@ -219,18 +219,31 @@ void FormulaGroupAreaListener::collectFormulaCells( } } -#if DEBUG_AREA_BROADCASTER ScAddress FormulaGroupAreaListener::getTopCellPos() const { const ScFormulaCell& rFC = **mppTopCell; return rFC.aPos; } +const ScRange& FormulaGroupAreaListener::getRange() const +{ + return maRange; +} + SCROW FormulaGroupAreaListener::getGroupLength() const { return mnGroupLen; } -#endif + +bool FormulaGroupAreaListener::isStartFixed() const +{ + return mbStartFixed; +} + +bool FormulaGroupAreaListener::isEndFixed() const +{ + return mbEndFixed; +} void FormulaGroupAreaListener::notifyCellChange( const SfxHint& rHint, const ScAddress& rPos ) { diff --git a/sc/source/core/tool/stringutil.cxx b/sc/source/core/tool/stringutil.cxx index ce83c33d6af5..158b54f1a3d5 100644 --- a/sc/source/core/tool/stringutil.cxx +++ b/sc/source/core/tool/stringutil.cxx @@ -29,7 +29,8 @@ ScSetStringParam::ScSetStringParam() : mpNumFormatter(NULL), mbDetectNumberFormat(true), meSetTextNumFormat(Never), - mbHandleApostrophe(true) + mbHandleApostrophe(true), + meStartListening(sc::SingleCellListening) { } diff --git a/sc/source/ui/undo/refundo.cxx b/sc/source/ui/undo/refundo.cxx index 623e7b6a7a18..a5c38548d337 100644 --- a/sc/source/ui/undo/refundo.cxx +++ b/sc/source/ui/undo/refundo.cxx @@ -35,28 +35,36 @@ #include ScRefUndoData::ScRefUndoData( const ScDocument* pDoc ) : - pUnoRefs( NULL ) + pDBCollection(NULL), + pRangeName(NULL), + pPrintRanges(pDoc->CreatePrintRangeSaver()), + pDPCollection(NULL), + pDetOpList(NULL), + pChartListenerCollection(NULL), + pAreaLinks(NULL), + pUnoRefs(NULL) { - ScDBCollection* pOldDBColl = pDoc->GetDBCollection(); - pDBCollection = pOldDBColl ? new ScDBCollection(*pOldDBColl) : NULL; + const ScDBCollection* pOldDBColl = pDoc->GetDBCollection(); + if (pOldDBColl && !pOldDBColl->empty()) + pDBCollection = new ScDBCollection(*pOldDBColl); - ScRangeName* pOldRanges = ((ScDocument*)pDoc)->GetRangeName(); //! const - pRangeName = pOldRanges ? new ScRangeName(*pOldRanges) : NULL; - - pPrintRanges = pDoc->CreatePrintRangeSaver(); // recreated + const ScRangeName* pOldRanges = pDoc->GetRangeName(); + if (pOldRanges && !pOldRanges->empty()) + pRangeName = new ScRangeName(*pOldRanges); // when handling Pivot solely keep the range? - ScDPCollection* pOldDP = ((ScDocument*)pDoc)->GetDPCollection(); //! const - pDPCollection = pOldDP ? new ScDPCollection(*pOldDP) : NULL; + const ScDPCollection* pOldDP = pDoc->GetDPCollection(); + if (pOldDP && pOldDP->GetCount()) + pDPCollection = new ScDPCollection(*pOldDP); - ScDetOpList* pOldDetOp = pDoc->GetDetOpList(); - pDetOpList = pOldDetOp ? new ScDetOpList(*pOldDetOp) : 0; + const ScDetOpList* pOldDetOp = pDoc->GetDetOpList(); + if (pOldDetOp && pOldDetOp->Count()) + pDetOpList = new ScDetOpList(*pOldDetOp); - ScChartListenerCollection* pOldChartListenerCollection = - pDoc->GetChartListenerCollection(); - pChartListenerCollection = pOldChartListenerCollection ? - new ScChartListenerCollection( *pOldChartListenerCollection ) : NULL; + const ScChartListenerCollection* pOldChartLisColl = pDoc->GetChartListenerCollection(); + if (pOldChartLisColl) + pChartListenerCollection = new ScChartListenerCollection(*pOldChartLisColl); pAreaLinks = ScAreaLinkSaveCollection::CreateFromDoc(pDoc); // returns NULL if empty -- cgit v1.2.3