From 647e860435c781fbb111ae59bc70dc8e6776fed5 Mon Sep 17 00:00:00 2001 From: Eike Rathke Date: Wed, 26 Oct 2016 14:50:43 +0200 Subject: Resolves: tdf#92117 create only one Undo for all UnmergeCells() calls ... during DeleteCells() and InsertCells(), instead of one Undo per UnmergeCells() call. And actually create Undo only if bRecord requested. Change-Id: I4f1747c3f42f36e16be81f989f0af5d048ba9d9f --- sc/inc/markdata.hxx | 2 + sc/source/core/data/markdata.cxx | 5 ++ sc/source/ui/docshell/docfunc.cxx | 54 ++++++++++++++++---- sc/source/ui/inc/docfunc.hxx | 5 +- sc/source/ui/inc/undoblk.hxx | 9 +++- sc/source/ui/undo/undoblk.cxx | 105 +++++++++++++++++++++++--------------- sc/source/ui/unoobj/cellsuno.cxx | 2 +- sc/source/ui/view/viewfun2.cxx | 2 +- sc/source/ui/view/viewfun3.cxx | 4 +- 9 files changed, 130 insertions(+), 58 deletions(-) (limited to 'sc') diff --git a/sc/inc/markdata.hxx b/sc/inc/markdata.hxx index 0392971f0a1c..60c04d076bb8 100644 --- a/sc/inc/markdata.hxx +++ b/sc/inc/markdata.hxx @@ -143,10 +143,12 @@ public: // iterators for table access typedef std::set::iterator iterator; typedef std::set::const_iterator const_iterator; + typedef std::set::const_reverse_iterator const_reverse_iterator; iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; + const_reverse_iterator rbegin() const; }; #endif diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx index 39a5728cd6cd..70ec2c131def 100644 --- a/sc/source/core/data/markdata.cxx +++ b/sc/source/core/data/markdata.cxx @@ -814,4 +814,9 @@ ScMarkData::const_iterator ScMarkData::end() const return maTabMarked.end(); } +ScMarkData::const_reverse_iterator ScMarkData::rbegin() const +{ + return maTabMarked.rbegin(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index ce381dee395b..77c029fe7d73 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -1795,6 +1795,7 @@ bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, nViewShellId = pViewSh->GetViewShellId(); rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); } + std::unique_ptr pUndoRemoveMerge; itr = aMark.begin(); for (; itr != itrEnd && nTabCount; ++itr) @@ -1902,12 +1903,19 @@ bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, if( !qIncreaseRange.empty() ) { + if (bRecord && !pUndoRemoveMerge) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( &rDoc, *aMark.begin(), *aMark.rbegin()); + pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, pUndoDoc )); + } + for( ::std::vector::const_iterator iIter( qIncreaseRange.begin()); iIter != qIncreaseRange.end(); ++iIter ) { ScRange aRange( *iIter ); if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) { - UnmergeCells( aRange, true ); + UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() ); } } } @@ -1923,6 +1931,11 @@ bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, } } + if (bRecord && pUndoRemoveMerge) + { + rDocShell.GetUndoManager()->AddUndoAction( pUndoRemoveMerge.release()); + } + switch (eCmd) { case INS_CELLSDOWN: @@ -2228,6 +2241,7 @@ bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, nViewShellId = pViewSh->GetViewShellId(); rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId ); } + std::unique_ptr pUndoRemoveMerge; itr = aMark.begin(); for (; itr != itrEnd && *itr < nTabCount; ++itr) @@ -2337,12 +2351,19 @@ bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, if( !qDecreaseRange.empty() ) { + if (bRecord && !pUndoRemoveMerge) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( &rDoc, *aMark.begin(), *aMark.rbegin()); + pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, pUndoDoc )); + } + for( ::std::vector::const_iterator iIter( qDecreaseRange.begin()); iIter != qDecreaseRange.end(); ++iIter ) { ScRange aRange( *iIter ); if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) ) { - UnmergeCells( aRange, true ); + UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() ); } } } @@ -2357,6 +2378,11 @@ bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, } } + if (bRecord && pUndoRemoveMerge) + { + rDocShell.GetUndoManager()->AddUndoAction( pUndoRemoveMerge.release()); + } + // ausfuehren WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference @@ -2804,7 +2830,7 @@ bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos, // skipped rows and merged cells don't mix if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) - UnmergeCells( aPasteDest, false ); + UnmergeCells( aPasteDest, false, nullptr ); bool bDestHeight = AdjustRowHeight( ScRange( 0,nDestRow,nDestTab, MAXCOL,nDestEndRow,nDestEndTab ), @@ -4792,17 +4818,17 @@ bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, bool bContents, bo return true; } -bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord ) +bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ) { ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab(); for (SCTAB i = nTab1; i <= nTab2; ++i) aOption.maTabs.insert(i); - return UnmergeCells(aOption, bRecord); + return UnmergeCells(aOption, bRecord, pUndoRemoveMerge); } -bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord ) +bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ) { using ::std::set; @@ -4816,7 +4842,8 @@ bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord ) if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; - ScDocument* pUndoDoc = nullptr; + ScDocument* pUndoDoc = (pUndoRemoveMerge ? pUndoRemoveMerge->GetUndoDoc() : nullptr); + assert( pUndoDoc || !pUndoRemoveMerge ); for (set::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end(); itr != itrEnd; ++itr) { @@ -4859,8 +4886,17 @@ bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord ) if (bRecord) { - rDocShell.GetUndoManager()->AddUndoAction( - new ScUndoRemoveMerge( &rDocShell, rOption, pUndoDoc ) ); + if (pUndoRemoveMerge) + { + // If pUndoRemoveMerge was passed, the caller is responsible for + // adding it to Undo. Just add the current option. + pUndoRemoveMerge->AddCellMergeOption( rOption); + } + else + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRemoveMerge( &rDocShell, rOption, pUndoDoc ) ); + } } aModificator.SetDocumentModified(); diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx index f54893ed4613..e6757a749b79 100644 --- a/sc/source/ui/inc/docfunc.hxx +++ b/sc/source/ui/inc/docfunc.hxx @@ -45,6 +45,7 @@ class ScTableProtection; struct ScCellMergeOption; class ScConditionalFormat; class ScConditionalFormatList; +class ScUndoRemoveMerge; namespace sc { @@ -189,8 +190,8 @@ public: bool MergeCells( const ScCellMergeOption& rOption, bool bContents, bool bRecord, bool bApi, bool bEmptyMergedCells = false ); - bool UnmergeCells( const ScRange& rRange, bool bRecord ); - bool UnmergeCells( const ScCellMergeOption& rOption, bool bRecord ); + bool UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ); + bool UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge ); void SetNewRangeNames( ScRangeName* pNewRanges, bool bModifyDoc, SCTAB nTab = -1 ); // takes ownership of pNewRanges //nTab = -1 for local range names void ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab = -1 ); diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx index 9e09292d13ea..01af186c1ea1 100644 --- a/sc/source/ui/inc/undoblk.hxx +++ b/sc/source/ui/inc/undoblk.hxx @@ -901,6 +901,8 @@ public: ScUndoRemoveMerge( ScDocShell* pNewDocShell, const ScCellMergeOption& rOption, ScDocument* pNewUndoDoc ); + ScUndoRemoveMerge( ScDocShell* pNewDocShell, + ScDocument* pNewUndoDoc ); virtual ~ScUndoRemoveMerge() override; virtual void Undo() override; @@ -910,11 +912,14 @@ public: virtual OUString GetComment() const override; + ScDocument* GetUndoDoc(); + void AddCellMergeOption( const ScCellMergeOption& rOption ); + private: void SetCurTab(); - ScCellMergeOption maOption; - ScDocument* pUndoDoc; + std::vector maOptions; + ScDocument* pUndoDoc; }; class ScUndoBorder: public ScBlockUndo diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx index fab2d03f4d6d..ba29368f84b0 100644 --- a/sc/source/ui/undo/undoblk.cxx +++ b/sc/source/ui/undo/undoblk.cxx @@ -1398,7 +1398,7 @@ void ScUndoDragDrop::Redo() // skipped rows and merged cells don't mix if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) - pDocShell->GetDocFunc().UnmergeCells( aDestRange, false ); + pDocShell->GetDocFunc().UnmergeCells( aDestRange, false, nullptr ); for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++) { @@ -2108,7 +2108,14 @@ bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell, const ScCellMergeOption& rOption, ScDocument* pNewUndoDoc ) : ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ), - maOption(rOption), + pUndoDoc( pNewUndoDoc ) +{ + maOptions.push_back( rOption); +} + +ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell, + ScDocument* pNewUndoDoc ) : + ScBlockUndo( pNewDocShell, ScRange(), SC_UNDO_SIMPLE ), pUndoDoc( pNewUndoDoc ) { } @@ -2123,6 +2130,16 @@ OUString ScUndoRemoveMerge::GetComment() const return ScGlobal::GetRscString( STR_UNDO_REMERGE ); // "remove merge" } +ScDocument* ScUndoRemoveMerge::GetUndoDoc() +{ + return pUndoDoc; +} + +void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption ) +{ + maOptions.push_back( rOption); +} + void ScUndoRemoveMerge::Undo() { using ::std::set; @@ -2133,25 +2150,28 @@ void ScUndoRemoveMerge::Undo() ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); ScDocument& rDoc = pDocShell->GetDocument(); - for (set::const_iterator itr = maOption.maTabs.begin(), itrEnd = maOption.maTabs.end(); - itr != itrEnd; ++itr) + for (const auto & rOption : maOptions) { - OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!"); - if (!pUndoDoc) - continue; - // There is no need to extend merge area because it's already been extended. - ScRange aRange = maOption.getSingleRange(*itr); - rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB); - pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc); - - bool bDidPaint = false; - if ( pViewShell ) + for (set::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end(); + itr != itrEnd; ++itr) { - pViewShell->SetTabNo(*itr); - bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow); + OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!"); + if (!pUndoDoc) + continue; + // There is no need to extend merge area because it's already been extended. + ScRange aRange = rOption.getSingleRange(*itr); + rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB); + pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc); + + bool bDidPaint = false; + if ( pViewShell ) + { + pViewShell->SetTabNo(*itr); + bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow); + } + if (!bDidPaint) + ScUndoUtil::PaintMore(pDocShell, aRange); } - if (!bDidPaint) - ScUndoUtil::PaintMore(pDocShell, aRange); } EndUndo(); @@ -2167,36 +2187,39 @@ void ScUndoRemoveMerge::Redo() ScDocument& rDoc = pDocShell->GetDocument(); ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); - for (set::const_iterator itr = maOption.maTabs.begin(), itrEnd = maOption.maTabs.end(); - itr != itrEnd; ++itr) + for (const auto & rOption : maOptions) { - SCTAB nTab = *itr; - // There is no need to extend merge area because it's already been extended. - ScRange aRange = maOption.getSingleRange(nTab); + for (set::const_iterator itr = rOption.maTabs.begin(), itrEnd = rOption.maTabs.end(); + itr != itrEnd; ++itr) + { + SCTAB nTab = *itr; + // There is no need to extend merge area because it's already been extended. + ScRange aRange = rOption.getSingleRange(nTab); - const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE ); - ScPatternAttr aPattern( rDoc.GetPool() ); - aPattern.GetItemSet().Put( rDefAttr ); - rDoc.ApplyPatternAreaTab( maOption.mnStartCol, maOption.mnStartRow, - maOption.mnEndCol, maOption.mnEndRow, nTab, - aPattern ); + const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE ); + ScPatternAttr aPattern( rDoc.GetPool() ); + aPattern.GetItemSet().Put( rDefAttr ); + rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow, + rOption.mnEndCol, rOption.mnEndRow, nTab, + aPattern ); - rDoc.RemoveFlagsTab( maOption.mnStartCol, maOption.mnStartRow, - maOption.mnEndCol, maOption.mnEndRow, nTab, - ScMF::Hor | ScMF::Ver ); + rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow, + rOption.mnEndCol, rOption.mnEndRow, nTab, + ScMF::Hor | ScMF::Ver ); - rDoc.ExtendMerge(aRange, true); + rDoc.ExtendMerge(aRange, true); - // Paint + // Paint - bool bDidPaint = false; - if ( pViewShell ) - { - pViewShell->SetTabNo(nTab); - bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow); + bool bDidPaint = false; + if ( pViewShell ) + { + pViewShell->SetTabNo(nTab); + bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow); + } + if (!bDidPaint) + ScUndoUtil::PaintMore(pDocShell, aRange); } - if (!bDidPaint) - ScUndoUtil::PaintMore(pDocShell, aRange); } EndRedo(); diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 96ab146a85d5..7268c1f14b7f 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -5379,7 +5379,7 @@ void SAL_CALL ScCellRangeObj::merge( sal_Bool bMerge ) throw(uno::RuntimeExcepti if ( bMerge ) pDocSh->GetDocFunc().MergeCells( aMergeOption, false, true, true ); else - pDocSh->GetDocFunc().UnmergeCells( aMergeOption, true ); + pDocSh->GetDocFunc().UnmergeCells( aMergeOption, true, nullptr ); //! Fehler abfangen? } diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx index 15291d100942..76d600a14828 100644 --- a/sc/source/ui/view/viewfun2.cxx +++ b/sc/source/ui/view/viewfun2.cxx @@ -1208,7 +1208,7 @@ bool ScViewFunc::RemoveMerge() } while (bExtended); - bool bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, true/*bRecord*/ ); + bool bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, true/*bRecord*/, nullptr); aExtended = aOption.getFirstSingleRange(); MarkRange( aExtended ); diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx index 389ed2490926..780633f7b401 100644 --- a/sc/source/ui/view/viewfun3.cxx +++ b/sc/source/ui/view/viewfun3.cxx @@ -1201,7 +1201,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScRange aRange(nCol, nRow1, nStartTab); pDoc->ExtendOverlapped(aRange); pDoc->ExtendMerge(aRange, true); - rDocFunc.UnmergeCells(aRange, bRecord); + rDocFunc.UnmergeCells(aRange, bRecord, nullptr /*TODO: should pass combined UndoDoc if bRecord*/); } } } @@ -1302,7 +1302,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc, // skipped rows and merged cells don't mix if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) - rDocFunc.UnmergeCells( aUserRange, false ); + rDocFunc.UnmergeCells( aUserRange, false, nullptr ); pDoc->ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true ); // refresh // new range -- cgit