From 5c6ee09126631342939ae8766fe36083d8c011e3 Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Mon, 2 Jun 2014 18:29:27 -0400 Subject: fdo#81309: Adjust references during sort. Change-Id: I2b98610f6b774400ecfaffe2905201c27fcab33f --- sc/source/core/data/documen3.cxx | 27 +- sc/source/core/data/document10.cxx | 18 + sc/source/core/data/formulacell.cxx | 38 +- sc/source/core/data/sortparam.cxx | 51 +++ sc/source/core/data/table3.cxx | 467 +++++++++++++++++------ sc/source/core/data/table7.cxx | 17 + sc/source/core/tool/listenerquery.cxx | 72 ++++ sc/source/core/tool/refhint.cxx | 29 +- sc/source/core/tool/sharedformula.cxx | 29 ++ sc/source/core/tool/token.cxx | 71 +++- sc/source/filter/xml/XMLExportDatabaseRanges.cxx | 1 + sc/source/filter/xml/xmldrani.cxx | 1 + sc/source/ui/docshell/dbdocfun.cxx | 161 +------- sc/source/ui/inc/undodat.hxx | 4 +- sc/source/ui/undo/undobase.cxx | 1 + sc/source/ui/undo/undodat.cxx | 18 +- sc/source/ui/undo/undosort.cxx | 55 +++ sc/source/ui/unoobj/cellsuno.cxx | 1 + sc/source/ui/unoobj/datauno.cxx | 1 + 19 files changed, 763 insertions(+), 299 deletions(-) create mode 100644 sc/source/core/tool/listenerquery.cxx create mode 100644 sc/source/ui/undo/undosort.cxx (limited to 'sc/source') diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index e8719fcffff5..34badd8c61d3 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -1335,17 +1335,30 @@ bool ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, b return false; } -void ScDocument::Sort(SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress) +void ScDocument::Sort( + SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress, sc::ReorderParam* pUndo ) { if ( ValidTab(nTab) && nTab < static_cast(maTabs.size()) && maTabs[nTab] ) { bool bOldEnableIdle = IsIdleEnabled(); EnableIdle(false); - maTabs[nTab]->Sort(rSortParam, bKeepQuery, pProgress); + maTabs[nTab]->Sort(rSortParam, bKeepQuery, pProgress, pUndo); EnableIdle(bOldEnableIdle); } } +void ScDocument::Reorder( const sc::ReorderParam& rParam, ScProgress* pProgress ) +{ + ScTable* pTab = FetchTable(rParam.maSortRange.aStart.Tab()); + if (!pTab) + return; + + bool bOldEnableIdle = IsIdleEnabled(); + EnableIdle(false); + pTab->Reorder(rParam, pProgress); + EnableIdle(bOldEnableIdle); +} + SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub) { if ( ValidTab(nTab) && nTab < static_cast(maTabs.size()) && maTabs[nTab] ) @@ -1999,4 +2012,14 @@ bool ScDocument::ReservePatternCount( SCTAB nTab, SCCOL nCol, SCSIZE nReserve ) return false; } +void ScDocument::GetSortParam( ScSortParam& rParam, SCTAB nTab ) +{ + rParam = mSheetSortParams[ nTab ]; +} + +void ScDocument::SetSortParam( ScSortParam& rParam, SCTAB nTab ) +{ + mSheetSortParams[ nTab ] = rParam; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index a1733629d790..d44bc33839a2 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -288,4 +288,22 @@ bool ScDocument::HasUniformRowHeight( SCTAB nTab, SCROW nRow1, SCROW nRow2 ) con return pTab->HasUniformRowHeight(nRow1, nRow2); } +void ScDocument::UnshareFormulaCells( SCTAB nTab, SCCOL nCol, std::vector& rRows ) +{ + ScTable* pTab = FetchTable(nTab); + if (!pTab) + return; + + pTab->UnshareFormulaCells(nCol, rRows); +} + +void ScDocument::RegroupFormulaCells( SCTAB nTab, SCCOL nCol ) +{ + ScTable* pTab = FetchTable(nTab); + if (!pTab) + return; + + pTab->RegroupFormulaCells(nCol); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 44d080741445..8d9dee1e38d3 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -56,6 +56,8 @@ #include "refupdatecontext.hxx" #include #include +#include +#include #include @@ -1938,8 +1940,23 @@ void ScFormulaCell::Notify( const SfxHint& rHint ) const sc::RefColReorderHint& rRefColReorder = static_cast(rRefHint); if (!IsShared() || IsSharedTop()) - pCode->MoveReference( - aPos, rRefColReorder.getTab(), rRefColReorder.getStartRow(), rRefColReorder.getEndRow(), rRefColReorder.getColMap()); + pCode->MoveReferenceColReorder( + aPos, rRefColReorder.getTab(), + rRefColReorder.getStartRow(), + rRefColReorder.getEndRow(), + rRefColReorder.getColMap()); + } + break; + case sc::RefHint::RowReordered: + { + const sc::RefRowReorderHint& rRefRowReorder = + static_cast(rRefHint); + if (!IsShared() || IsSharedTop()) + pCode->MoveReferenceRowReorder( + aPos, rRefRowReorder.getTab(), + rRefRowReorder.getStartColumn(), + rRefRowReorder.getEndColumn(), + rRefRowReorder.getRowMap()); } break; default: @@ -1984,6 +2001,23 @@ void ScFormulaCell::Notify( const SfxHint& rHint ) } } +void ScFormulaCell::Query( SvtListener::QueryBase& rQuery ) const +{ + switch (rQuery.getId()) + { + case SC_LISTENER_QUERY_FORMULA_GROUP_POS: + { + sc::RefQueryFormulaGroup& rRefQuery = + static_cast(rQuery); + if (IsShared()) + rRefQuery.add(aPos); + } + break; + default: + ; + } +} + void ScFormulaCell::SetDirty( bool bDirtyFlag ) { if ( !IsInChangeTrack() ) diff --git a/sc/source/core/data/sortparam.cxx b/sc/source/core/data/sortparam.cxx index 56448cf7d0a9..1e265b3e9a7f 100644 --- a/sc/source/core/data/sortparam.cxx +++ b/sc/source/core/data/sortparam.cxx @@ -235,4 +235,55 @@ void ScSortParam::MoveToDest() } } +namespace sc { + +namespace { + +struct ReorderIndex +{ + struct LessByPos2 : std::binary_function + { + bool operator() ( const ReorderIndex& r1, const ReorderIndex& r2 ) const + { + return r1.mnPos2 < r2.mnPos2; + } + }; + + SCCOLROW mnPos1; + SCCOLROW mnPos2; + + ReorderIndex( SCCOLROW nPos1, SCCOLROW nPos2 ) : mnPos1(nPos1), mnPos2(nPos2) {} +}; + +} + +void ReorderParam::reverse() +{ + SCCOLROW nStart; + if (mbByRow) + nStart = maSortRange.aStart.Row(); + else + nStart = maSortRange.aStart.Col(); + + size_t n = maOrderIndices.size(); + std::vector aBucket; + aBucket.reserve(n); + for (size_t i = 0; i < n; ++i) + { + SCCOLROW nPos1 = i + nStart; + SCCOLROW nPos2 = maOrderIndices[i]; + aBucket.push_back(ReorderIndex(nPos1, nPos2)); + } + + std::sort(aBucket.begin(), aBucket.end(), ReorderIndex::LessByPos2()); + std::vector aNew; + aNew.reserve(n); + for (size_t i = 0; i < n; ++i) + aNew.push_back(aBucket[i].mnPos1); + + maOrderIndices.swap(aNew); +} + +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index 72a066cf9e03..64f0ef5f2874 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -59,6 +59,7 @@ #include #include #include +#include #include @@ -256,39 +257,46 @@ private: SCCOLROW mnLastIndex; /// index of last non-empty cell position. sal_uInt16 nUsedSorts; - std::vector maOldIndices; + std::vector maOrderIndices; bool mbKeepQuery; public: ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) : - pppInfo( new ScSortInfo**[nSorts]), + pppInfo(NULL), nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ), mnLastIndex(nInd2), nUsedSorts(nSorts), mbKeepQuery(false) { - for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) + if (nUsedSorts) { - ScSortInfo** ppInfo = new ScSortInfo* [nCount]; - for ( SCSIZE j = 0; j < nCount; j++ ) - ppInfo[j] = new ScSortInfo; - pppInfo[nSort] = ppInfo; + pppInfo = new ScSortInfo**[nUsedSorts]; + for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) + { + ScSortInfo** ppInfo = new ScSortInfo* [nCount]; + for ( SCSIZE j = 0; j < nCount; j++ ) + ppInfo[j] = new ScSortInfo; + pppInfo[nSort] = ppInfo; + } } for (size_t i = 0; i < nCount; ++i) - maOldIndices.push_back(i+nStart); + maOrderIndices.push_back(i+nStart); } ~ScSortInfoArray() { - for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) + if (pppInfo) { - ScSortInfo** ppInfo = pppInfo[nSort]; - for ( SCSIZE j = 0; j < nCount; j++ ) - delete ppInfo[j]; - delete [] ppInfo; + for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) + { + ScSortInfo** ppInfo = pppInfo[nSort]; + for ( SCSIZE j = 0; j < nCount; j++ ) + delete ppInfo[j]; + delete [] ppInfo; + } + delete[] pppInfo; } - delete[] pppInfo; if (mpRows) std::for_each(mpRows->begin(), mpRows->end(), boost::checked_deleter()); @@ -298,11 +306,30 @@ public: bool IsKeepQuery() const { return mbKeepQuery; } + /** + * Call this only during normal sorting, not from reordering. + */ + ScSortInfo** GetFirstArray() const + { + OSL_ASSERT(pppInfo); + return pppInfo[0]; + } + + /** + * Call this only during normal sorting, not from reordering. + */ ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd ) - { return (pppInfo[nSort])[ nInd - nStart ]; } + { + OSL_ASSERT(pppInfo); + return (pppInfo[nSort])[ nInd - nStart ]; + } + /** + * Call this only during normal sorting, not from reordering. + */ void Swap( SCCOLROW nInd1, SCCOLROW nInd2 ) { + OSL_ASSERT(pppInfo); SCSIZE n1 = static_cast(nInd1 - nStart); SCSIZE n2 = static_cast(nInd2 - nStart); for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) @@ -313,7 +340,7 @@ public: ppInfo[n2] = pTmp; } - std::swap(maOldIndices[n1], maOldIndices[n2]); + std::swap(maOrderIndices[n1], maOrderIndices[n2]); if (mpRows) { @@ -323,13 +350,47 @@ public: } } + void SetOrderIndices( const std::vector& rIndices ) + { + maOrderIndices = rIndices; + } + + /** + * @param rIndices indices are actual row positions on the sheet, not an + * offset from the top row. + */ + void ReorderByRow( const std::vector& rIndices ) + { + if (!mpRows) + return; + + RowsType& rRows = *mpRows; + + std::vector aOrderIndices2; + aOrderIndices2.reserve(rIndices.size()); + + RowsType aRows2; + aRows2.reserve(rRows.size()); + + std::vector::const_iterator it = rIndices.begin(), itEnd = rIndices.end(); + for (; it != itEnd; ++it) + { + size_t nPos = *it - nStart; // switch to an offset to top row. + aRows2.push_back(rRows[nPos]); + aOrderIndices2.push_back(maOrderIndices[nPos]); + } + + rRows.swap(aRows2); + maOrderIndices.swap(aOrderIndices2); + } + sal_uInt16 GetUsedSorts() const { return nUsedSorts; } - ScSortInfo** GetFirstArray() const { return pppInfo[0]; } + SCCOLROW GetStart() const { return nStart; } SCCOLROW GetLast() const { return mnLastIndex; } SCSIZE GetCount() const { return nCount; } - const std::vector& GetOldIndices() const { return maOldIndices; } + const std::vector& GetOrderIndices() const { return maOrderIndices; } RowsType& InitDataRows( size_t nRowSize, size_t nColSize ) { @@ -347,19 +408,98 @@ public: } }; -ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery ) +namespace { + +void initDataRows( + ScSortInfoArray& rArray, ScTable& rTab, ScColumn* pCols, + SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + bool bPattern, bool bHiddenFiltered ) +{ + // Fill row-wise data table. + ScSortInfoArray::RowsType& rRows = rArray.InitDataRows(nRow2-nRow1+1, nCol2-nCol1+1); + + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + ScColumn& rCol = pCols[nCol]; + + // Skip reordering of cell formats if the whole span is on the same pattern entry. + bool bUniformPattern = rCol.GetPatternCount(nRow1, nRow2) < 2u; + + sc::ColumnBlockConstPosition aBlockPos; + rCol.InitBlockPosition(aBlockPos); + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + ScSortInfoArray::Row& rRow = *rRows[nRow-nRow1]; + ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-nCol1]; + + rCell.maCell = rCol.GetCellValue(aBlockPos, nRow); + rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow); + rCell.mpBroadcaster = rCol.GetBroadcaster(aBlockPos, nRow); + rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow); + + if (!bUniformPattern && bPattern) + rCell.mpPattern = rCol.GetPattern(nRow); + } + } + + if (bHiddenFiltered) + { + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + ScSortInfoArray::Row& rRow = *rRows[nRow-nRow1]; + rRow.mbHidden = rTab.RowHidden(nRow); + rRow.mbFiltered = rTab.RowFiltered(nRow); + } + } +} + +} + +ScSortInfoArray* ScTable::CreateSortInfoArray( const sc::ReorderParam& rParam ) +{ + ScSortInfoArray* pArray = NULL; + + if (rParam.mbByRow) + { + // Create a sort info array with just the data table. + SCROW nRow1 = rParam.maSortRange.aStart.Row(); + SCROW nRow2 = rParam.maSortRange.aEnd.Row(); + SCCOL nCol1 = rParam.maSortRange.aStart.Col(); + SCCOL nCol2 = rParam.maSortRange.aEnd.Col(); + + pArray = new ScSortInfoArray(0, nRow1, nRow2); + pArray->SetKeepQuery(rParam.mbHiddenFiltered); + + initDataRows( + *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2, + rParam.mbPattern, rParam.mbHiddenFiltered); + } + else + { + SCCOLROW nCol1 = rParam.maSortRange.aStart.Col(); + SCCOLROW nCol2 = rParam.maSortRange.aEnd.Col(); + + pArray = new ScSortInfoArray(0, nCol1, nCol2); + pArray->SetKeepQuery(rParam.mbHiddenFiltered); + } + + return pArray; +} + +ScSortInfoArray* ScTable::CreateSortInfoArray( + const ScSortParam& rSortParam, SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery ) { sal_uInt16 nUsedSorts = 1; - while ( nUsedSorts < aSortParam.GetSortKeyCount() && aSortParam.maKeyState[nUsedSorts].bDoSort ) + while ( nUsedSorts < rSortParam.GetSortKeyCount() && rSortParam.maKeyState[nUsedSorts].bDoSort ) nUsedSorts++; ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 ); pArray->SetKeepQuery(bKeepQuery); - if ( aSortParam.bByRow ) + if ( rSortParam.bByRow ) { for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) { - SCCOL nCol = static_cast(aSortParam.maKeyState[nSort].nField); + SCCOL nCol = static_cast(rSortParam.maKeyState[nSort].nField); ScColumn* pCol = &aCol[nCol]; sc::ColumnBlockConstPosition aBlockPos; pCol->InitBlockPosition(aBlockPos); @@ -371,49 +511,15 @@ ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, b } } - // Fill row-wise data table. - ScSortInfoArray::RowsType& rRows = pArray->InitDataRows( - nInd2 - nInd1 + 1, aSortParam.nCol2 - aSortParam.nCol1 + 1); - - for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; ++nCol) - { - ScColumn& rCol = aCol[nCol]; - - // Skip reordering of cell formats if the whole span is on the same pattern entry. - bool bUniformPattern = rCol.GetPatternCount(nInd1, nInd2) < 2u; - - sc::ColumnBlockConstPosition aBlockPos; - rCol.InitBlockPosition(aBlockPos); - for (SCROW nRow = nInd1; nRow <= nInd2; ++nRow) - { - ScSortInfoArray::Row& rRow = *rRows[nRow-nInd1]; - ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-aSortParam.nCol1]; - - rCell.maCell = rCol.GetCellValue(aBlockPos, nRow); - rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow); - rCell.mpBroadcaster = rCol.GetBroadcaster(aBlockPos, nRow); - rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow); - - if (!bUniformPattern && aSortParam.bIncludePattern) - rCell.mpPattern = rCol.GetPattern(nRow); - } - } - - if (bKeepQuery) - { - for (SCROW nRow = nInd1; nRow <= nInd2; ++nRow) - { - ScSortInfoArray::Row& rRow = *rRows[nRow-nInd1]; - rRow.mbHidden = RowHidden(nRow); - rRow.mbFiltered = RowFiltered(nRow); - } - } + initDataRows( + *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2, + rSortParam.bIncludePattern, bKeepQuery); } else { for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) { - SCROW nRow = aSortParam.maKeyState[nSort].nField; + SCROW nRow = rSortParam.maKeyState[nSort].nField; for ( SCCOL nCol = static_cast(nInd1); nCol <= static_cast(nInd2); nCol++ ) { @@ -527,12 +633,13 @@ void ScTable::DestroySortCollator() namespace { -class ColReorderNotifier : std::unary_function +template +class ReorderNotifier : std::unary_function { - sc::RefColReorderHint maHint; + _Hint maHint; public: - ColReorderNotifier( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) : - maHint(rColMap, nTab, nRow1, nRow2) {} + ReorderNotifier( const _ReorderMap& rMap, SCTAB nTab, _Index nPos1, _Index nPos2 ) : + maHint(rMap, nTab, nPos1, nPos2) {} void operator() ( SvtListener* p ) { @@ -540,77 +647,86 @@ public: } }; -} +typedef ReorderNotifier ColReorderNotifier; +typedef ReorderNotifier RowReorderNotifier; -void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress ) +class FormulaGroupPosCollector : std::unary_function { - if (aSortParam.bByRow) + sc::RefQueryFormulaGroup& mrQuery; + +public: + FormulaGroupPosCollector( sc::RefQueryFormulaGroup& rQuery ) : mrQuery(rQuery) {} + + void operator() ( SvtListener* p ) { - SortReorderByRow(pArray, pProgress); - return; + p->Query(mrQuery); } +}; - size_t nCount = pArray->GetCount(); +} + +void ScTable::SortReorderByColumn( + ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress ) +{ SCCOLROW nStart = pArray->GetStart(); SCCOLROW nLast = pArray->GetLast(); - ScSortInfo** ppInfo = pArray->GetFirstArray(); - - std::vector aTable(nCount); - SCSIZE nPos; - for ( nPos = 0; nPos < nCount; nPos++ ) - aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos]; + std::vector aIndices = pArray->GetOrderIndices(); + size_t nCount = aIndices.size(); // Cut formula grouping at row and reference boundaries before the reordering. - ScRange aSortRange(nStart, aSortParam.nRow1, nTab, nLast, aSortParam.nRow2, nTab); + ScRange aSortRange(nStart, nRow1, nTab, nLast, nRow2, nTab); for (SCCOL nCol = nStart; nCol <= nLast; ++nCol) aCol[nCol].SplitFormulaGroupByRelativeRef(aSortRange); + // table to keep track of column index to position in the index table. + std::vector aPosTable(nCount); + for (size_t i = 0; i < nCount; ++i) + aPosTable[aIndices[i]-nStart] = i; + SCCOLROW nDest = nStart; - for ( nPos = 0; nPos < nCount; nPos++, nDest++ ) + for (size_t i = 0; i < nCount; ++i, ++nDest) { - SCCOLROW nOrg = ppInfo[nPos]->nOrg; - if ( nDest != nOrg ) + SCCOLROW nSrc = aIndices[i]; + if (nDest != nSrc) { - aCol[nDest].Swap(aCol[nOrg], aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern); + aCol[nDest].Swap(aCol[nSrc], nRow1, nRow2, bPattern); - // neue Position des weggeswapten eintragen - ScSortInfo* p = ppInfo[nPos]; - p->nOrg = nDest; - ::std::swap(p, aTable[nDest-nStart]); - p->nOrg = nOrg; - ::std::swap(p, aTable[nOrg-nStart]); - OSL_ENSURE( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" ); + // Update the position of the index that was originally equal to nDest. + size_t nPos = aPosTable[nDest-nStart]; + aIndices[nPos] = nSrc; + aPosTable[nSrc-nStart] = nPos; } - if(pProgress) - pProgress->SetStateOnPercent( nPos ); + + if (pProgress) + pProgress->SetStateOnPercent(i); } // Reset formula cell positions which became out-of-sync after column reordering. for (SCCOL nCol = nStart; nCol <= nLast; ++nCol) - aCol[nCol].ResetFormulaCellPositions(aSortParam.nRow1, aSortParam.nRow2); + aCol[nCol].ResetFormulaCellPositions(nRow1, nRow2); // Set up column reorder map (for later broadcasting of reference updates). - sc::ColReorderMapType aColMap; - const std::vector& rOldIndices = pArray->GetOldIndices(); + sc::ColRowReorderMapType aColMap; + const std::vector& rOldIndices = pArray->GetOrderIndices(); for (size_t i = 0, n = rOldIndices.size(); i < n; ++i) { SCCOL nNew = i + nStart; - SCROW nOld = rOldIndices[i]; - aColMap.insert(sc::ColReorderMapType::value_type(nOld, nNew)); + SCCOL nOld = rOldIndices[i]; + aColMap.insert(sc::ColRowReorderMapType::value_type(nOld, nNew)); } // Collect all listeners within sorted range ahead of time. std::vector aListeners; for (SCCOL nCol = nStart; nCol <= nLast; ++nCol) - aCol[nCol].CollectListeners(aListeners, aSortParam.nRow1, aSortParam.nRow2); + aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); // Remove any duplicate listener entries and notify all listeners // afterward. We must ensure that we notify each unique listener only // once. std::sort(aListeners.begin(), aListeners.end()); aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end()); - ColReorderNotifier aFunc(aColMap, nTab, aSortParam.nRow1, aSortParam.nRow2); + ColReorderNotifier aFunc(aColMap, nTab, nRow1, nRow2); std::for_each(aListeners.begin(), aListeners.end(), aFunc); // Re-join formulas at row boundaries now that all the references have @@ -618,28 +734,28 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress ) for (SCCOL nCol = nStart; nCol <= nLast; ++nCol) { sc::CellStoreType& rCells = aCol[nCol].maCells; - sc::CellStoreType::position_type aPos = rCells.position(aSortParam.nRow1); + sc::CellStoreType::position_type aPos = rCells.position(nRow1); sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); - aPos = rCells.position(aPos.first, aSortParam.nRow2+1); + aPos = rCells.position(aPos.first, nRow2+1); sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); } } -void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ) +void ScTable::SortReorderByRow( + ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress ) { + if (nCol2 < nCol1) + return; + SCROW nRow1 = pArray->GetStart(); SCROW nRow2 = pArray->GetLast(); ScSortInfoArray::RowsType* pRows = pArray->GetDataRows(); assert(pRows); // In sort-by-row mode we must have data rows already populated. - // Detach all formula cells within the sorted range first. - sc::EndListeningContext aCxt(*pDocument); - DetachFormulaCells(aCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2); - // Cells in the data rows only reference values in the document. Make // a copy before updating the document. - size_t nColCount = aSortParam.nCol2 - aSortParam.nCol1 + 1; + size_t nColCount = nCol2 - nCol1 + 1; boost::ptr_vector aSortedCols; // storage for copied cells. SortedRowFlags aRowFlags; aSortedCols.reserve(nColCount); @@ -656,7 +772,7 @@ void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ) ScSortInfoArray::Row* pRow = (*pRows)[i]; for (size_t j = 0; j < pRow->maCells.size(); ++j) { - ScAddress aCellPos(aSortParam.nCol1 + j, nRow1 + i, nTab); + ScAddress aCellPos(nCol1 + j, nRow1 + i, nTab); ScSortInfoArray::Cell& rCell = pRow->maCells[j]; @@ -678,14 +794,14 @@ void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ) case CELLTYPE_FORMULA: { assert(rCell.mpAttr); - size_t n = rCellStore.size(); - sc::CellStoreType::iterator itBlk = rCellStore.push_back( rCell.maCell.mpFormula->Clone( - aCellPos, SC_CLONECELL_DEFAULT | SC_CLONECELL_ADJUST3DREL)); - - // Join the formula cells as we fill the container. - size_t nOffset = n - itBlk->position; - sc::CellStoreType::position_type aPos(itBlk, nOffset); - sc::SharedFormulaUtil::joinFormulaCellAbove(aPos); + ScAddress aOldPos = rCell.maCell.mpFormula->aPos; + + ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( + aCellPos, SC_CLONECELL_DEFAULT | SC_CLONECELL_ADJUST3DREL); + pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula); + pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos); + + sc::CellStoreType::iterator itBlk = rCellStore.push_back(pNew); } break; default: @@ -734,7 +850,7 @@ void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ) for (size_t i = 0, n = aSortedCols.size(); i < n; ++i) { - SCCOL nThisCol = i + aSortParam.nCol1; + SCCOL nThisCol = i + nCol1; { sc::CellStoreType& rDest = aCol[nThisCol].maCells; @@ -809,10 +925,62 @@ void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ) SetRowFiltered(it->mnRow1, it->mnRow2, true); } - // Attach all formula cells within sorted range, to have them start listening again. - sc::StartListeningContext aStartListenCxt(*pDocument); - AttachFormulaCells( - aStartListenCxt, aSortParam.nCol1, nRow1, aSortParam.nCol2, nRow2); + // Set up row reorder map (for later broadcasting of reference updates). + sc::ColRowReorderMapType aRowMap; + const std::vector& rOldIndices = pArray->GetOrderIndices(); + for (size_t i = 0, n = rOldIndices.size(); i < n; ++i) + { + SCROW nNew = i + nRow1; + SCROW nOld = rOldIndices[i]; + aRowMap.insert(sc::ColRowReorderMapType::value_type(nOld, nNew)); + } + + // Collect all listeners within sorted range ahead of time. + std::vector aListeners; + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); + + // Remove any duplicate listener entries. We must ensure that we notify + // each unique listener only once. + std::sort(aListeners.begin(), aListeners.end()); + aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end()); + + // Collect positions of all shared formula cells outside the sorted range, + // and make them unshared before notifying them. + sc::RefQueryFormulaGroup aFormulaGroupPos; + aFormulaGroupPos.setSkipRange(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab)); + + std::for_each(aListeners.begin(), aListeners.end(), FormulaGroupPosCollector(aFormulaGroupPos)); + const sc::RefQueryFormulaGroup::TabsType& rGroupTabs = aFormulaGroupPos.getAllPositions(); + sc::RefQueryFormulaGroup::TabsType::const_iterator itGroupTab = rGroupTabs.begin(), itGroupTabEnd = rGroupTabs.end(); + for (; itGroupTab != itGroupTabEnd; ++itGroupTab) + { + const sc::RefQueryFormulaGroup::ColsType& rCols = itGroupTab->second; + sc::RefQueryFormulaGroup::ColsType::const_iterator itCol = rCols.begin(), itColEnd = rCols.end(); + for (; itCol != itColEnd; ++itCol) + { + const sc::RefQueryFormulaGroup::ColType& rCol = itCol->second; + std::vector aBounds(rCol); + pDocument->UnshareFormulaCells(itGroupTab->first, itCol->first, aBounds); + } + } + + // Notify the listeners. + RowReorderNotifier aFunc(aRowMap, nTab, nCol1, nCol2); + std::for_each(aListeners.begin(), aListeners.end(), aFunc); + + // Re-group formulas in affected columns. + for (itGroupTab = rGroupTabs.begin(); itGroupTab != itGroupTabEnd; ++itGroupTab) + { + const sc::RefQueryFormulaGroup::ColsType& rCols = itGroupTab->second; + sc::RefQueryFormulaGroup::ColsType::const_iterator itCol = rCols.begin(), itColEnd = rCols.end(); + for (; itCol != itColEnd; ++itCol) + pDocument->RegroupFormulaCells(itGroupTab->first, itCol->first); + } + + // Re-group columns in the sorted range too. + for (SCCOL i = nCol1; i <= nCol2; ++i) + aCol[i].RegroupFormulaCells(); } short ScTable::CompareCell( @@ -1031,11 +1199,21 @@ void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 ) } } -void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress) +void ScTable::Sort( + const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress, sc::ReorderParam* pUndo ) { aSortParam = rSortParam; InitSortCollator( rSortParam ); bGlobalKeepQuery = bKeepQuery; + + if (pUndo) + { + // Copy over the basic sort parameters. + pUndo->mbByRow = rSortParam.bByRow; + pUndo->mbPattern = rSortParam.bIncludePattern; + pUndo->mbHiddenFiltered = bKeepQuery; + } + if (rSortParam.bByRow) { SCROW nLastRow = 0; @@ -1049,15 +1227,19 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p if(pProgress) pProgress->SetState( 0, nLastRow-nRow1 ); - boost::scoped_ptr pArray(CreateSortInfoArray(nRow1, nLastRow, bKeepQuery)); + boost::scoped_ptr pArray(CreateSortInfoArray(aSortParam, nRow1, nLastRow, bKeepQuery)); if ( nLastRow - nRow1 > 255 ) DecoladeRow(pArray.get(), nRow1, nLastRow); QuickSort(pArray.get(), nRow1, nLastRow); - SortReorder(pArray.get(), pProgress); + SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress); - // #i59745# update position of caption objects of cell notes --> reported at (SortReorder) ScColumn::SwapCellNotes level + if (pUndo) + { + pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab); + pUndo->maOrderIndices = pArray->GetOrderIndices(); + } } } else @@ -1074,17 +1256,48 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p if(pProgress) pProgress->SetState( 0, nLastCol-nCol1 ); - boost::scoped_ptr pArray(CreateSortInfoArray(nCol1, nLastCol, bKeepQuery)); + boost::scoped_ptr pArray(CreateSortInfoArray(aSortParam, nCol1, nLastCol, bKeepQuery)); QuickSort(pArray.get(), nCol1, nLastCol); - SortReorder(pArray.get(), pProgress); + SortReorderByColumn(pArray.get(), aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern, pProgress); - // #i59745# update position of caption objects of cell notes --> reported at (SortReorder) ScColumn::SwapCellNotes level + if (pUndo) + { + pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab); + pUndo->maOrderIndices = pArray->GetOrderIndices(); + } } } DestroySortCollator(); } +void ScTable::Reorder( const sc::ReorderParam& rParam, ScProgress* pProgress ) +{ + if (rParam.maOrderIndices.empty()) + return; + + boost::scoped_ptr pArray(CreateSortInfoArray(rParam)); + if (!pArray) + return; + + if (rParam.mbByRow) + { + // Re-play sorting from the known sort indices. + pArray->ReorderByRow(rParam.maOrderIndices); + + SortReorderByRow( + pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), pProgress); + } + else + { + // Ordering by column is much simpler. Just set the order indices and we are done. + pArray->SetOrderIndices(rParam.maOrderIndices); + SortReorderByColumn( + pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(), + rParam.mbPattern, pProgress); + } +} + namespace { class SubTotalRowFinder @@ -2074,7 +2287,7 @@ void ScTable::TopTenQuery( ScQueryParam& rParam ) bSortCollatorInitialized = true; InitSortCollator( aLocalSortParam ); } - boost::scoped_ptr pArray(CreateSortInfoArray(nRow1, rParam.nRow2, bGlobalKeepQuery)); + boost::scoped_ptr pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery)); DecoladeRow( pArray.get(), nRow1, rParam.nRow2 ); QuickSort( pArray.get(), nRow1, rParam.nRow2 ); ScSortInfo** ppInfo = pArray->GetFirstArray(); diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index 845c720b2147..f39e529c164d 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -13,6 +13,7 @@ #include #include #include +#include bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const { @@ -117,4 +118,20 @@ bool ScTable::HasUniformRowHeight( SCROW nRow1, SCROW nRow2 ) const return nRow2 <= aData.mnRow2; } +void ScTable::UnshareFormulaCells( SCCOL nCol, std::vector& rRows ) +{ + if (!ValidCol(nCol)) + return; + + sc::SharedFormulaUtil::unshareFormulaCells(aCol[nCol].maCells, rRows); +} + +void ScTable::RegroupFormulaCells( SCCOL nCol ) +{ + if (!ValidCol(nCol)) + return; + + aCol[nCol].RegroupFormulaCells(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/listenerquery.cxx b/sc/source/core/tool/listenerquery.cxx new file mode 100644 index 000000000000..bf9d38fe2070 --- /dev/null +++ b/sc/source/core/tool/listenerquery.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +namespace sc { + +RefQueryFormulaGroup::RefQueryFormulaGroup() : + SvtListener::QueryBase(SC_LISTENER_QUERY_FORMULA_GROUP_POS), + maSkipRange(ScAddress::INITIALIZE_INVALID) {} + +RefQueryFormulaGroup::~RefQueryFormulaGroup() {} + +void RefQueryFormulaGroup::setSkipRange( const ScRange& rRange ) +{ + maSkipRange = rRange; +} + +void RefQueryFormulaGroup::add( const ScAddress& rPos ) +{ + if (!rPos.IsValid()) + return; + + if (maSkipRange.IsValid() && maSkipRange.In(rPos)) + // This is within the skip range. Skip it. + return; + + TabsType::iterator itTab = maTabs.find(rPos.Tab()); + if (itTab == maTabs.end()) + { + std::pair r = + maTabs.insert(TabsType::value_type(rPos.Tab(), ColsType())); + if (!r.second) + // Insertion failed. + return; + + itTab = r.first; + } + + ColsType& rCols = itTab->second; + ColsType::iterator itCol = rCols.find(rPos.Col()); + if (itCol == rCols.end()) + { + std::pair r = + rCols.insert(ColsType::value_type(rPos.Col(), ColType())); + if (!r.second) + // Insertion failed. + return; + + itCol = r.first; + } + + ColType& rCol = itCol->second; + rCol.push_back(rPos.Row()); +} + +const RefQueryFormulaGroup::TabsType& RefQueryFormulaGroup::getAllPositions() const +{ + return maTabs; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/refhint.cxx b/sc/source/core/tool/refhint.cxx index 80aef9307cf1..533a41b54d8a 100644 --- a/sc/source/core/tool/refhint.cxx +++ b/sc/source/core/tool/refhint.cxx @@ -34,12 +34,12 @@ const ScAddress& RefMovedHint::getDelta() const return maMoveDelta; } -RefColReorderHint::RefColReorderHint( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) : +RefColReorderHint::RefColReorderHint( const sc::ColRowReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) : RefHint(ColumnReordered), mrColMap(rColMap), mnTab(nTab), mnRow1(nRow1), mnRow2(nRow2) {} RefColReorderHint::~RefColReorderHint() {} -const sc::ColReorderMapType& RefColReorderHint::getColMap() const +const sc::ColRowReorderMapType& RefColReorderHint::getColMap() const { return mrColMap; } @@ -59,6 +59,31 @@ SCROW RefColReorderHint::getEndRow() const return mnRow2; } +RefRowReorderHint::RefRowReorderHint( const sc::ColRowReorderMapType& rRowMap, SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ) : + RefHint(RowReordered), mrRowMap(rRowMap), mnTab(nTab), mnCol1(nCol1), mnCol2(nCol2) {} + +RefRowReorderHint::~RefRowReorderHint() {} + +const sc::ColRowReorderMapType& RefRowReorderHint::getRowMap() const +{ + return mrRowMap; +} + +SCTAB RefRowReorderHint::getTab() const +{ + return mnTab; +} + +SCCOL RefRowReorderHint::getStartColumn() const +{ + return mnCol1; +} + +SCCOL RefRowReorderHint::getEndColumn() const +{ + return mnCol2; +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx index ed35690a63a7..6f6636557915 100644 --- a/sc/source/core/tool/sharedformula.cxx +++ b/sc/source/core/tool/sharedformula.cxx @@ -297,6 +297,35 @@ void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type& a rCell.SetCellGroup(xNone); } +void SharedFormulaUtil::unshareFormulaCells(CellStoreType& rCells, std::vector& rRows) +{ + if (rRows.empty()) + return; + + // Sort and remove duplicates. + std::sort(rRows.begin(), rRows.end()); + rRows.erase(std::unique(rRows.begin(), rRows.end()), rRows.end()); + + // Add next cell positions to the list (to ensure that each position becomes a single cell). + std::vector aRows2; + std::vector::const_iterator it = rRows.begin(), itEnd = rRows.end(); + for (; it != itEnd; ++it) + { + if (*it > MAXROW) + break; + + aRows2.push_back(*it); + + if (*it < MAXROW) + aRows2.push_back(*it+1); + } + + // Remove duplicates again (the vector should still be sorted). + aRows2.erase(std::unique(aRows2.begin(), aRows2.end()), aRows2.end()); + + splitFormulaCellGroups(rCells, aRows2); +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 73947996ee0a..99a26a85bcf6 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2899,8 +2899,8 @@ void ScTokenArray::MoveReference( } } -void ScTokenArray::MoveReference( - const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColReorderMapType& rColMap ) +void ScTokenArray::MoveReferenceColReorder( + const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColRowReorderMapType& rColMap ) { FormulaToken** p = pCode; FormulaToken** pEnd = p + static_cast(nLen); @@ -2917,7 +2917,7 @@ void ScTokenArray::MoveReference( if (aAbs.Tab() == nTab && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2) { // Inside reordered row range. - sc::ColReorderMapType::const_iterator it = rColMap.find(aAbs.Col()); + sc::ColRowReorderMapType::const_iterator it = rColMap.find(aAbs.Col()); if (it != rColMap.end()) { // This column is reordered. @@ -2945,7 +2945,7 @@ void ScTokenArray::MoveReference( if (aAbs.aStart.Tab() == nTab && nRow1 <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= nRow2) { // Inside reordered row range. - sc::ColReorderMapType::const_iterator it = rColMap.find(aAbs.aStart.Col()); + sc::ColRowReorderMapType::const_iterator it = rColMap.find(aAbs.aStart.Col()); if (it != rColMap.end()) { // This column is reordered. @@ -2963,6 +2963,69 @@ void ScTokenArray::MoveReference( } } +void ScTokenArray::MoveReferenceRowReorder( const ScAddress& rPos, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, const sc::ColRowReorderMapType& rRowMap ) +{ + FormulaToken** p = pCode; + FormulaToken** pEnd = p + static_cast(nLen); + for (; p != pEnd; ++p) + { + switch ((*p)->GetType()) + { + case svSingleRef: + { + ScToken* pToken = static_cast(*p); + ScSingleRefData& rRef = pToken->GetSingleRef(); + ScAddress aAbs = rRef.toAbs(rPos); + + if (aAbs.Tab() == nTab && nCol1 <= aAbs.Col() && aAbs.Col() <= nCol2) + { + // Inside reordered column range. + sc::ColRowReorderMapType::const_iterator it = rRowMap.find(aAbs.Row()); + if (it != rRowMap.end()) + { + // This column is reordered. + SCROW nNewRow = it->second; + aAbs.SetRow(nNewRow); + rRef.SetAddress(aAbs, rPos); + } + } + } + break; + case svDoubleRef: + { + ScToken* pToken = static_cast(*p); + ScComplexRefData& rRef = pToken->GetDoubleRef(); + ScRange aAbs = rRef.toAbs(rPos); + + if (aAbs.aStart.Tab() != aAbs.aEnd.Tab()) + // Must be a single-sheet reference. + break; + + if (aAbs.aStart.Row() != aAbs.aEnd.Row()) + // Whole range must fit in a single row. + break; + + if (aAbs.aStart.Tab() == nTab && nCol1 <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= nCol2) + { + // Inside reordered column range. + sc::ColRowReorderMapType::const_iterator it = rRowMap.find(aAbs.aStart.Row()); + if (it != rRowMap.end()) + { + // This row is reordered. + SCCOL nNewRow = it->second; + aAbs.aStart.SetRow(nNewRow); + aAbs.aEnd.SetRow(nNewRow); + rRef.SetRange(aAbs, rPos); + } + } + } + break; + default: + ; + } + } +} + namespace { bool adjustSingleRefInName( diff --git a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx index a50742778de7..758a1f91f0ca 100644 --- a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx +++ b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx @@ -35,6 +35,7 @@ #include "subtotalparam.hxx" #include "queryparam.hxx" #include "queryentry.hxx" +#include #include diff --git a/sc/source/filter/xml/xmldrani.cxx b/sc/source/filter/xml/xmldrani.cxx index 9088e00d4c32..38db1b30e1e6 100644 --- a/sc/source/filter/xml/xmldrani.cxx +++ b/sc/source/filter/xml/xmldrani.cxx @@ -34,6 +34,7 @@ #include "rangeutl.hxx" #include "queryentry.hxx" #include "dputil.hxx" +#include #include #include diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx index 94578f2e957f..187621dc2b26 100644 --- a/sc/source/ui/docshell/dbdocfun.cxx +++ b/sc/source/ui/docshell/dbdocfun.cxx @@ -47,6 +47,7 @@ #include "queryentry.hxx" #include "markdata.hxx" #include "progress.hxx" +#include #include #include @@ -430,8 +431,6 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, ScDocument& rDoc = rDocShell.GetDocument(); if (bRecord && !rDoc.IsUndoEnabled()) bRecord = false; - SCTAB nSrcTab = nTab; - ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1, rSortParam.nCol2, rSortParam.nRow2 ); @@ -441,28 +440,25 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, return false; } - ScDBData* pDestData = NULL; - ScRange aOldDest; bool bCopy = !rSortParam.bInplace; if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 && rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab ) bCopy = false; + ScSortParam aLocalParam( rSortParam ); if ( bCopy ) { - aLocalParam.MoveToDest(); - if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) ) - { - if (!bApi) - rDocShell.ErrorMessage(STR_PASTE_FULL); + // Copy the data range to the destination then move the sort range to it. + ScRange aSrcRange(rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab); + ScAddress aDestPos(rSortParam.nDestCol,rSortParam.nDestRow,rSortParam.nDestTab); + + ScDocFunc& rDocFunc = rDocShell.GetDocFunc(); + bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi); + + if (!bRet) return false; - } - nTab = rSortParam.nDestTab; - pDestData = rDoc.GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow, - rSortParam.nDestTab, true ); - if (pDestData) - pDestData->GetArea(aOldDest); + aLocalParam.MoveToDest(); } ScEditableTester aTester( &rDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1, @@ -511,133 +507,23 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, if ( aQueryParam.GetEntry(0).bDoQuery ) bRepeatQuery = true; - if (bRepeatQuery && bCopy) - { - if ( aQueryParam.bInplace || - aQueryParam.nDestCol != rSortParam.nDestCol || - aQueryParam.nDestRow != rSortParam.nDestRow || - aQueryParam.nDestTab != rSortParam.nDestTab ) // Query auf selben Zielbereich? - bRepeatQuery = false; - } - - ScUndoSort* pUndoAction = 0; - if ( bRecord ) - { - // Referenzen ausserhalb des Bereichs werden nicht veraendert ! - - ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); - // Zeilenhoehen immer (wegen automatischer Anpassung) - //! auf ScBlockUndo umstellen - pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true ); - - /* #i59745# Do not copy note captions to undo document. All existing - caption objects will be repositioned while sorting which is tracked - in drawing undo. When undo is executed, the old positions will be - restored, and the cells with the old notes (which still refer to the - existing captions) will be copied back into the source document. */ - rDoc.CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nTab, - aLocalParam.nCol2, aLocalParam.nRow2, nTab, - IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); - - const ScRange* pR = 0; - if (pDestData) - { - /* #i59745# Do not copy note captions from destination range to - undo document. All existing caption objects will be removed - which is tracked in drawing undo. When undo is executed, the - caption objects are reinserted with drawing undo, and the cells - with the old notes (which still refer to the existing captions) - will be copied back into the source document. */ - rDoc.CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); - pR = &aOldDest; - } - - // Zeilenhoehen immer (wegen automatischer Anpassung) - //! auf ScBlockUndo umstellen -// if (bRepeatQuery) - rDoc.CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab, - IDF_NONE, false, pUndoDoc ); - - ScDBCollection* pUndoDB = NULL; - ScDBCollection* pDocDB = rDoc.GetDBCollection(); - if (!pDocDB->empty()) - pUndoDB = new ScDBCollection( *pDocDB ); - - pUndoAction = new ScUndoSort( &rDocShell, nTab, rSortParam, pUndoDoc, pUndoDB, pR ); - rDocShell.GetUndoManager()->AddUndoAction( pUndoAction ); - - // #i59745# collect all drawing undo actions affecting cell note captions - if( pDrawLayer ) - pDrawLayer->BeginCalcUndo(false); - } - - if ( bCopy ) - { - if (pDestData) - rDoc.DeleteAreaTab(aOldDest, IDF_CONTENTS); // Zielbereich vorher loeschen - - ScRange aSource( rSortParam.nCol1,rSortParam.nRow1,nSrcTab, - rSortParam.nCol2,rSortParam.nRow2,nSrcTab ); - ScAddress aDest( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab ); - - rDocShell.GetDocFunc().MoveBlock( aSource, aDest, false, false, false, true ); - } + sc::ReorderParam aUndoParam; // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set) if (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort) { ScProgress aProgress(&rDocShell, ScGlobal::GetRscString(STR_PROGRESS_SORTING), 0); - rDoc.Sort( nTab, aLocalParam, bRepeatQuery, &aProgress ); + rDoc.Sort(nTab, aLocalParam, bRepeatQuery, &aProgress, &aUndoParam); } - bool bSave = true; - if (bCopy) - { - ScSortParam aOldSortParam; - pDBData->GetSortParam( aOldSortParam ); - if (aOldSortParam.GetSortKeyCount() && - aOldSortParam.maKeyState[0].bDoSort && aOldSortParam.bInplace) - { - bSave = false; - aOldSortParam.nDestCol = rSortParam.nDestCol; - aOldSortParam.nDestRow = rSortParam.nDestRow; - aOldSortParam.nDestTab = rSortParam.nDestTab; - pDBData->SetSortParam( aOldSortParam ); // dann nur DestPos merken - } - } - if (bSave) // Parameter merken + if (bRecord) { - pDBData->SetSortParam( rSortParam ); - pDBData->SetHeader( rSortParam.bHasHeader ); //! ??? - pDBData->SetByRow( rSortParam.bByRow ); //! ??? + // Set up an undo object. + sc::UndoSort* pUndoAction = new sc::UndoSort(&rDocShell, aUndoParam); + rDocShell.GetUndoManager()->AddUndoAction(pUndoAction); } - if (bCopy) // neuen DB-Bereich merken - { - // Tabelle umschalten von aussen (View) - //! SetCursor ??!?! - - ScRange aDestPos( aLocalParam.nCol1, aLocalParam.nRow1, nTab, - aLocalParam.nCol2, aLocalParam.nRow2, nTab ); - ScDBData* pNewData; - if (pDestData) - pNewData = pDestData; // Bereich vorhanden -> anpassen - else // Bereich ab Cursor/Markierung wird angelegt - pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, SC_DBSEL_FORCE_MARK ); - if (pNewData) - { - pNewData->SetArea( nTab, - aLocalParam.nCol1,aLocalParam.nRow1, - aLocalParam.nCol2,aLocalParam.nRow2 ); - pNewData->SetSortParam( aLocalParam ); - pNewData->SetHeader( aLocalParam.bHasHeader ); //! ??? - pNewData->SetByRow( aLocalParam.bByRow ); - } - else - { - OSL_FAIL("Zielbereich nicht da"); - } - } + pDBData->SetSortParam(rSortParam); ScRange aDirtyRange( aLocalParam.nCol1, nStartRow, nTab, @@ -657,23 +543,12 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, nStartX = 0; nEndX = MAXCOL; } - if (pDestData) - { - if ( nEndX < aOldDest.aEnd.Col() ) - nEndX = aOldDest.aEnd.Col(); - if ( nEndY < aOldDest.aEnd.Row() ) - nEndY = aOldDest.aEnd.Row(); - } rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint); } if (!bUniformRowHeight) rDocShell.AdjustRowHeight(nStartRow, aLocalParam.nRow2, nTab); - // #i59745# set collected drawing undo actions at sorting undo action - if( pUndoAction && pDrawLayer ) - pUndoAction->SetDrawUndoAction( pDrawLayer->GetCalcUndo() ); - aModificator.SetDocumentModified(); return true; diff --git a/sc/source/ui/inc/undodat.hxx b/sc/source/ui/inc/undodat.hxx index 00388d71b6a3..cbe115265b15 100644 --- a/sc/source/ui/inc/undodat.hxx +++ b/sc/source/ui/inc/undodat.hxx @@ -231,7 +231,7 @@ public: ScUndoSort( ScDocShell* pNewDocShell, SCTAB nNewTab, const ScSortParam& rParam, ScDocument* pNewUndoDoc, - ScDBCollection* pNewUndoDB, const ScRange* pDest = NULL ); + ScDBCollection* pNewUndoDB ); virtual ~ScUndoSort(); virtual void Undo() SAL_OVERRIDE; @@ -246,8 +246,6 @@ private: ScSortParam aSortParam; ScDocument* pUndoDoc; ScDBCollection* pUndoDB; // due to source and target range - bool bDestArea; - ScRange aDestRange; }; class ScUndoQuery: public ScDBFuncUndo diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx index 8740c6b31077..dc7efd49756e 100644 --- a/sc/source/ui/undo/undobase.cxx +++ b/sc/source/ui/undo/undobase.cxx @@ -33,6 +33,7 @@ #include "globstr.hrc" #include #include +#include TYPEINIT1(ScSimpleUndo, SfxUndoAction); TYPEINIT1(ScBlockUndo, ScSimpleUndo); diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx index b6bc5d614a33..d0a7c809faa8 100644 --- a/sc/source/ui/undo/undodat.cxx +++ b/sc/source/ui/undo/undodat.cxx @@ -739,21 +739,14 @@ bool ScUndoSubTotals::CanRepeat(SfxRepeatTarget& /* rTarget */) const ScUndoSort::ScUndoSort( ScDocShell* pNewDocShell, SCTAB nNewTab, const ScSortParam& rParam, - ScDocument* pNewUndoDoc, ScDBCollection* pNewUndoDB, - const ScRange* pDest ) : + ScDocument* pNewUndoDoc, ScDBCollection* pNewUndoDB ) : ScDBFuncUndo( pNewDocShell, ScRange( rParam.nCol1, rParam.nRow1, nNewTab, rParam.nCol2, rParam.nRow2, nNewTab ) ), nTab( nNewTab ), aSortParam( rParam ), pUndoDoc( pNewUndoDoc ), - pUndoDB( pNewUndoDB ), - bDestArea( false ) + pUndoDB( pNewUndoDB ) { - if ( pDest ) - { - bDestArea = true; - aDestRange = *pDest; - } } ScUndoSort::~ScUndoSort() @@ -796,13 +789,6 @@ void ScUndoSort::Undo() pUndoDoc->CopyToDocument( nStartCol, nStartRow, nSortTab, nEndCol, nEndRow, nSortTab, IDF_ALL|IDF_NOCAPTIONS, false, &rDoc ); - if (bDestArea) - { - // do not delete/copy note captions, they are handled in drawing undo (ScDBFuncUndo::mpDrawUndo) - rDoc.DeleteAreaTab( aDestRange, IDF_ALL|IDF_NOCAPTIONS ); - pUndoDoc->CopyToDocument( aDestRange, IDF_ALL|IDF_NOCAPTIONS, false, &rDoc ); - } - // Row heights always (due to automatic adjustment) // TODO change to use ScBlockUndo pUndoDoc->CopyToDocument( 0, nStartRow, nSortTab, MAXCOL, nEndRow, nSortTab, diff --git a/sc/source/ui/undo/undosort.cxx b/sc/source/ui/undo/undosort.cxx new file mode 100644 index 000000000000..d138491c3abb --- /dev/null +++ b/sc/source/ui/undo/undosort.cxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +namespace sc { + +UndoSort::UndoSort( ScDocShell* pDocSh, const ReorderParam& rParam ) : + ScSimpleUndo(pDocSh), maParam(rParam) {} + +OUString UndoSort::GetComment() const +{ + return ScGlobal::GetRscString(STR_UNDO_SORT); +} + +void UndoSort::Undo() +{ + BeginUndo(); + Execute(true); + EndUndo(); +} + +void UndoSort::Redo() +{ + BeginRedo(); + Execute(false); + EndRedo(); +} + +void UndoSort::Execute( bool bUndo ) +{ + ScDocument& rDoc = pDocShell->GetDocument(); + sc::ReorderParam aParam = maParam; + if (bUndo) + aParam.reverse(); + rDoc.Reorder(aParam, NULL); + + ScUndoUtil::MarkSimpleBlock(pDocShell, maParam.maSortRange); + + pDocShell->PostPaint(maParam.maSortRange, PAINT_GRID); + pDocShell->PostDataChanged(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 3a94df0175ab..7ad020265790 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -125,6 +125,7 @@ #include "tokenarray.hxx" #include "stylehelper.hxx" #include "dputil.hxx" +#include #include #include diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx index b84879116d3f..0dc0bcf639ba 100644 --- a/sc/source/ui/unoobj/datauno.cxx +++ b/sc/source/ui/unoobj/datauno.cxx @@ -51,6 +51,7 @@ #include "dpshttab.hxx" #include "queryentry.hxx" #include "dputil.hxx" +#include #include #include -- cgit v1.2.3