diff options
-rw-r--r-- | sc/inc/column.hxx | 17 | ||||
-rw-r--r-- | sc/source/core/data/column3.cxx | 151 | ||||
-rw-r--r-- | sc/source/core/tool/sharedformula.cxx | 2 |
3 files changed, 139 insertions, 31 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index a885d0240a2c..8664c81c0c20 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -636,8 +636,16 @@ public: /** * Detach a formula cell that's about to be deleted, or removed from * document storage (if that ever happens). + * + * @param rNewSharedRows collects possible new shared row ranges (top and + * bottom of shared or remaining single twice) resulting from + * unsharing to reestablish listeners on. */ - void DetachFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ); + void DetachFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, + std::vector<SCROW>& rNewSharedRows ); + + /** Re-establish listeners on unshared formula groups */ + void StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows ); void DetachFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength ); @@ -692,15 +700,18 @@ public: bool ReservePatternCount( SCSIZE nReserve ); private: - sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow ); - sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow ); + sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows ); + sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow, + std::vector<SCROW>& rNewSharedRows ); void AttachNewFormulaCell( const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, + const std::vector<SCROW>& rNewSharedRows, bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening ); void AttachNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, + const std::vector<SCROW>& rNewSharedRows, bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening ); void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength ); diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index db46b236b853..2607ea4b74a8 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -256,9 +256,9 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* CellStorageModified(); } -sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow ) +sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows ) { - return GetPositionToInsert(maCells.begin(), nRow); + return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows); } void ScColumn::JoinNewFormulaCell( @@ -282,15 +282,74 @@ void ScColumn::JoinNewFormulaCell( } void ScColumn::DetachFormulaCell( - const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) + const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows ) { if (!GetDoc()->IsClipOrUndo()) + { +#if USE_FORMULA_GROUP_LISTENER + if (rCell.IsShared() && rCell.GetSharedLength() > 1) + { + // Record new spans (shared or remaining single) that will result + // from unsharing to reestablish listeners. + // Same cases as in unshareFormulaCell(). + // XXX NOTE: this is not part of unshareFormulaCell() because that + // is called in other contexts as well, for which passing and + // determining the rows vector would be superfluous. If that was + // needed, move it there. + const SCROW nSharedTopRow = rCell.GetSharedTopRow(); + const SCROW nSharedLength = rCell.GetSharedLength(); + if (rCell.aPos.Row() == nSharedTopRow) + { + // Top cell. + // Next row will be new shared top or single cell. + rNewSharedRows.push_back( nSharedTopRow + 1); + rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1); + } + else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1) + { + // Bottom cell. + // Current shared top row will be new shared top again or + // single cell. + rNewSharedRows.push_back( nSharedTopRow); + rNewSharedRows.push_back( rCell.aPos.Row() - 1); + } + else + { + // Some mid cell. + // Current shared top row will be new shared top again or + // single cell, plus a new shared top below or single cell. + rNewSharedRows.push_back( nSharedTopRow); + rNewSharedRows.push_back( rCell.aPos.Row() - 1); + rNewSharedRows.push_back( rCell.aPos.Row() + 1); + rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1); + } + } +#endif + // Have the dying formula cell stop listening. + // If in a shared formula group this ends the group listening. rCell.EndListeningTo(GetDoc()); + } sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell); } +void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows ) +{ + assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4); + ScDocument* pDoc = GetDoc(); + if (!rNewSharedRows.empty() && !pDoc->IsDelayedFormulaGrouping()) + { + std::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDoc)); + sc::StartListeningContext aStartCxt(*pDoc, pPosSet); + sc::EndListeningContext aEndCxt(*pDoc, pPosSet); + if (rNewSharedRows.size() >= 2) + StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]); + if (rNewSharedRows.size() >= 4) + StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]); + } +} + namespace { class AttachFormulaCellsHandler @@ -386,7 +445,8 @@ void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, S sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc); } -sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow ) +sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow, + std::vector<SCROW>& rNewSharedRows ) { // See if we are overwriting an existing formula cell. sc::CellStoreType::position_type aPos = maCells.position(it, nRow); @@ -394,7 +454,7 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy if (itRet->type == sc::element_type_formula) { ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second); - DetachFormulaCell(aPos, rCell); + DetachFormulaCell(aPos, rCell, rNewSharedRows); } return itRet; @@ -402,13 +462,15 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy void ScColumn::AttachNewFormulaCell( const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, + const std::vector<SCROW>& rNewSharedRows, bool bJoin, sc::StartListeningType eListenType ) { - AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, eListenType); + AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType); } void ScColumn::AttachNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, + const std::vector<SCROW>& rNewSharedRows, bool bJoin, sc::StartListeningType eListenType ) { if (bJoin) @@ -431,17 +493,28 @@ void ScColumn::AttachNewFormulaCell( std::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDocument)); sc::StartListeningContext aStartCxt(*pDocument, pPosSet); sc::EndListeningContext aEndCxt(*pDocument, pPosSet); - SCROW nRow = aPos.first->position + aPos.second; - StartListeningFormulaCells(aStartCxt, aEndCxt, nRow, nRow); + SCROW nStartRow, nEndRow; + nStartRow = nEndRow = aPos.first->position + aPos.second; + for (const SCROW nR : rNewSharedRows) + { + if (nStartRow > nR) + nStartRow = nR; + if (nEndRow < nR) + nEndRow = nR; + } + StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow); } break; case sc::SingleCellListening: rCell.StartListeningTo(pDocument); - break; + [[fallthrough]]; case sc::NoListening: default: - ; - + // Listeners for changed shared formula groups resulting from + // unshareFormulaCell() need to be re-established in all cases + // (unless the callers thought of that and take care of it, but..). + StartListeningUnshared( rNewSharedRows); + break; } if (!pDocument->IsCalcingAfterLoad()) @@ -1872,24 +1945,30 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString, void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText ) { pEditText->NormalizeString(GetDoc()->GetSharedStringPool()); - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); maCells.set(it, nRow, pEditText.release()); maCellTextAttrs.set(nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + BroadcastNewCell(nRow); } void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, std::unique_ptr<EditTextObject> pEditText ) { pEditText->NormalizeString(GetDoc()->GetSharedStringPool()); - rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); + std::vector<SCROW> aNewSharedRows; + rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows); rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText.release()); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + BroadcastNewCell(nRow); } @@ -1929,7 +2008,8 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form { ScAddress aPos(nCol, nRow, nTab); - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram); sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) @@ -1939,14 +2019,15 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form CellStorageModified(); - AttachNewFormulaCell(it, nRow, *pCell); + AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); } void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram ) { ScAddress aPos(nCol, nRow, nTab); - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram); sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) @@ -1956,14 +2037,15 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul CellStorageModified(); - AttachNewFormulaCell(it, nRow, *pCell); + AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); } ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType, bool bInheritNumFormatIfNeeded ) { - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded ) pCell->SetNeedNumberFormat(true); @@ -1972,7 +2054,8 @@ ScFormulaCell* ScColumn::SetFormulaCell( CellStorageModified(); - AttachNewFormulaCell(it, nRow, *pCell, true, eListenType); + AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType); + return pCell; } @@ -1981,7 +2064,8 @@ void ScColumn::SetFormulaCell( sc::StartListeningType eListenType, bool bInheritNumFormatIfNeeded ) { - rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); + std::vector<SCROW> aNewSharedRows; + rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows); sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow); if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded ) pCell->SetNeedNumberFormat(true); @@ -1991,7 +2075,7 @@ void ScColumn::SetFormulaCell( CellStorageModified(); - AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, true, eListenType); + AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType); } bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells ) @@ -2461,13 +2545,14 @@ void ScColumn::SetError( SCROW nRow, const FormulaError nError) ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab)); pCell->SetErrCode(nError); - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); it = maCells.set(it, nRow, pCell); maCellTextAttrs.set(nRow, sc::CellTextAttr()); CellStorageModified(); - AttachNewFormulaCell(it, nRow, *pCell); + AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows); } void ScColumn::SetRawString( SCROW nRow, const OUString& rStr ) @@ -2487,12 +2572,15 @@ void ScColumn::SetRawString( SCROW nRow, const svl::SharedString& rStr ) if (!ValidRow(nRow)) return; - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); maCells.set(it, nRow, rStr); maCellTextAttrs.set(nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + BroadcastNewCell(nRow); } @@ -2502,13 +2590,16 @@ void ScColumn::SetRawString( if (!ValidRow(nRow)) return; - rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); + std::vector<SCROW> aNewSharedRows; + rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows); rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + if (bBroadcast) BroadcastNewCell(nRow); } @@ -2518,12 +2609,15 @@ void ScColumn::SetValue( SCROW nRow, double fVal ) if (!ValidRow(nRow)) return; - sc::CellStoreType::iterator it = GetPositionToInsert(nRow); + std::vector<SCROW> aNewSharedRows; + sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows); maCells.set(it, nRow, fVal); maCellTextAttrs.set(nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + BroadcastNewCell(nRow); } @@ -2533,13 +2627,16 @@ void ScColumn::SetValue( if (!ValidRow(nRow)) return; - rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow); + std::vector<SCROW> aNewSharedRows; + rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows); rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal); rBlockPos.miCellTextAttrPos = maCellTextAttrs.set( rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr()); CellStorageModified(); + StartListeningUnshared( aNewSharedRows); + if (bBroadcast) BroadcastNewCell(nRow); } diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx index 4fa12a6dfaed..bcfa04594df8 100644 --- a/sc/source/core/tool/sharedformula.cxx +++ b/sc/source/core/tool/sharedformula.cxx @@ -248,9 +248,9 @@ void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type& a { // Move the top cell to the next formula cell down. ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1); - --xGroup->mnLength; xGroup->mpTopCell = &rNext; } + --xGroup->mnLength; } else if (rCell.aPos.Row() == rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1) { |