diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2014-06-02 18:29:27 -0400 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@googlemail.com> | 2014-07-15 16:16:01 +0000 |
commit | 5c3bcc6fe3653aed79a11abbead66f11896e7ee8 (patch) | |
tree | cedabc7d8e4c5b990a9514556ba0b881bdb0aef4 | |
parent | cd278ead4d8865bc886f6641012f10d459601e71 (diff) |
fdo#81309: Adjust references during sort.
(cherry picked from commit 5c6ee09126631342939ae8766fe36083d8c011e3)
Conflicts:
sc/inc/sortparam.hxx
sc/source/ui/docshell/dbdocfun.cxx
sc/source/ui/undo/undodat.cxx
Change-Id: I2b98610f6b774400ecfaffe2905201c27fcab33f
Reviewed-on: https://gerrit.libreoffice.org/10305
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
Tested-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
33 files changed, 1015 insertions, 310 deletions
diff --git a/include/svl/listener.hxx b/include/svl/listener.hxx index 1c9845843bd1..8b47fda968b4 100644 --- a/include/svl/listener.hxx +++ b/include/svl/listener.hxx @@ -34,6 +34,16 @@ class SVL_DLLPUBLIC SvtListener const SvtListener& operator=(const SvtListener &); // n.i., ist verboten public: + class SVL_DLLPUBLIC QueryBase + { + sal_uInt16 mnId; + public: + QueryBase( sal_uInt16 nId ); + virtual ~QueryBase(); + + sal_uInt16 getId() const; + }; + SvtListener(); SvtListener( const SvtListener &r ); virtual ~SvtListener(); @@ -43,9 +53,11 @@ public: void EndListeningAll(); bool IsListening( SvtBroadcaster& rBroadcaster ) const; + void CopyAllBroadcasters( const SvtListener& r ); bool HasBroadcaster() const; virtual void Notify( const SfxHint& rHint ); + virtual void Query( QueryBase& rQuery ) const; }; diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 9b55aa4380b3..639946a9b786 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -237,6 +237,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/tool/interpr6 \ sc/source/core/tool/interpr7 \ sc/source/core/tool/jumpmatrix \ + sc/source/core/tool/listenerquery \ sc/source/core/tool/lookupcache \ sc/source/core/tool/navicfg \ sc/source/core/tool/odffmap \ @@ -517,6 +518,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/ui/undo/undodraw \ sc/source/ui/undo/undoolk \ sc/source/ui/undo/undorangename \ + sc/source/ui/undo/undosort \ sc/source/ui/undo/undostyl \ sc/source/ui/undo/undotab \ sc/source/ui/undo/undoutil \ diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 3db9fb9def52..bfeefc399730 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -29,7 +29,6 @@ #include "rangenam.hxx" #include "brdcst.hxx" #include "tabopparams.hxx" -#include "sortparam.hxx" #include "types.hxx" #include <formula/grammar.hxx> #include <formula/types.hxx> @@ -79,6 +78,8 @@ class CellValues; class RowHeightContext; struct SetFormulaDirtyContext; class RefMovedHint; +struct SortUndoParam; +struct ReorderParam; } @@ -181,6 +182,8 @@ class EditTextObject; struct ScRefCellValue; class ScDocumentImport; class ScPostIt; +struct ScSubTotalParam; +struct ScQueryParam; namespace com { namespace sun { namespace star { namespace lang { @@ -1678,7 +1681,9 @@ public: SC_DLLPUBLIC SvNumberFormatter* GetFormatTable() const; SC_DLLPUBLIC SvNumberFormatter* CreateFormatTable() const; - void Sort( SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress ); + void Sort( SCTAB nTab, const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress, sc::ReorderParam* pUndo ); + void Reorder( const sc::ReorderParam& rParam, ScProgress* pProgress ); + SCSIZE Query( SCTAB nTab, const ScQueryParam& rQueryParam, bool bKeepSub ); SC_DLLPUBLIC bool CreateQueryParam( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, ScQueryParam& rQueryParam ); @@ -2036,8 +2041,8 @@ public: void InvalidateStyleSheetUsage() { bStyleSheetUsageInvalid = true; } - void GetSortParam( ScSortParam& rParam, SCTAB nTab ); - void SetSortParam( ScSortParam& rParam, SCTAB nTab ); + void SC_DLLPUBLIC GetSortParam( ScSortParam& rParam, SCTAB nTab ); + void SC_DLLPUBLIC SetSortParam( ScSortParam& rParam, SCTAB nTab ); inline void SetVbaEventProcessor( const com::sun::star::uno::Reference< com::sun::star::script::vba::XVBAEventProcessor >& rxVbaEvents ) { mxVbaEvents = rxVbaEvents; } @@ -2066,6 +2071,19 @@ public: size_t GetFormulaHash( const ScAddress& rPos ) const; + /** + * Make specified formula cells non-grouped. + * + * @param nTab sheet index + * @param nCol column index + * @param rRows list of row indices at which formula cells are to be + * unshared. This call sorts the passed row indices and + * removes duplicates, which is why the caller must pass it + * as reference. + */ + void UnshareFormulaCells( SCTAB nTab, SCCOL nCol, std::vector<SCROW>& rRows ); + void RegroupFormulaCells( SCTAB nTab, SCCOL nCol ); + ScFormulaVectorState GetFormulaVectorState( const ScAddress& rPos ) const; formula::FormulaTokenRef ResolveStaticReference( const ScAddress& rPos ); @@ -2151,15 +2169,6 @@ private: // CLOOK-Impl-methods void SharePooledResources( ScDocument* pSrcDoc ); }; -inline void ScDocument::GetSortParam( ScSortParam& rParam, SCTAB nTab ) -{ - rParam = mSheetSortParams[ nTab ]; -} - -inline void ScDocument::SetSortParam( ScSortParam& rParam, SCTAB nTab ) -{ - mSheetSortParams[ nTab ] = rParam; -} #endif diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index 49b20b120f72..959779a788bb 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -321,6 +321,8 @@ public: void SetNextTrack( ScFormulaCell* pF ); virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE; + virtual void Query( SvtListener::QueryBase& rQuery ) const SAL_OVERRIDE; + void SetCompile( bool bVal ); ScDocument* GetDocument() const; void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true ); diff --git a/sc/inc/listenerquery.hxx b/sc/inc/listenerquery.hxx new file mode 100644 index 000000000000..2cbc95731be1 --- /dev/null +++ b/sc/inc/listenerquery.hxx @@ -0,0 +1,50 @@ +/* -*- 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/. + */ + +#ifndef SC_LISTENERQUERY_HXX +#define SC_LISTENERQUERY_HXX + +#include <address.hxx> +#include <svl/listener.hxx> + +namespace sc { + +/** + * Used to collect positions of formula cells that belong to a formula + * group. + */ +class RefQueryFormulaGroup : public SvtListener::QueryBase +{ +public: + typedef std::vector<SCROW> ColType; + typedef boost::unordered_map<SCCOL,ColType> ColsType; + typedef boost::unordered_map<SCTAB,ColsType> TabsType; + + RefQueryFormulaGroup(); + virtual ~RefQueryFormulaGroup(); + + void setSkipRange( const ScRange& rRange ); + void add( const ScAddress& rPos ); + + /** + * Row positions in each column may contain duplicates. Caller must + * remove duplicates if necessary. + */ + const TabsType& getAllPositions() const; + +private: + ScRange maSkipRange; + TabsType maTabs; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/listenerqueryids.hxx b/sc/inc/listenerqueryids.hxx new file mode 100644 index 000000000000..48f240b13fd8 --- /dev/null +++ b/sc/inc/listenerqueryids.hxx @@ -0,0 +1,17 @@ +/* -*- 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/. + */ + +#ifndef SC_LISTENERQUERYIDS_HXX +#define SC_LISTENERQUERYIDS_HXX + +#define SC_LISTENER_QUERY_FORMULA_GROUP_POS 0 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/refhint.hxx b/sc/inc/refhint.hxx index 1f927312327b..1eff90631de6 100644 --- a/sc/inc/refhint.hxx +++ b/sc/inc/refhint.hxx @@ -18,7 +18,11 @@ namespace sc { class RefHint : public SfxSimpleHint { public: - enum Type { Moved, ColumnReordered }; + enum Type { + Moved, + ColumnReordered, + RowReordered + }; private: Type meType; @@ -57,22 +61,40 @@ public: class RefColReorderHint : public RefHint { - const sc::ColReorderMapType& mrColMap; + const sc::ColRowReorderMapType& mrColMap; SCTAB mnTab; SCROW mnRow1; SCROW mnRow2; public: - RefColReorderHint( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ); + RefColReorderHint( const sc::ColRowReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ); virtual ~RefColReorderHint(); - const sc::ColReorderMapType& getColMap() const; + const sc::ColRowReorderMapType& getColMap() const; SCTAB getTab() const; SCROW getStartRow() const; SCROW getEndRow() const; }; +class RefRowReorderHint : public RefHint +{ + const sc::ColRowReorderMapType& mrRowMap; + SCTAB mnTab; + SCCOL mnCol1; + SCCOL mnCol2; + +public: + RefRowReorderHint( const sc::ColRowReorderMapType& rRowMap, SCTAB nTab, SCCOL nCol1, SCCOL nCol2 ); + virtual ~RefRowReorderHint(); + + const sc::ColRowReorderMapType& getRowMap() const; + + SCTAB getTab() const; + SCCOL getStartColumn() const; + SCCOL getEndColumn() const; +}; + } #endif diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx index 840b63b9bbe4..b29843f8547a 100644 --- a/sc/inc/sharedformula.hxx +++ b/sc/inc/sharedformula.hxx @@ -100,6 +100,15 @@ public: * @param rCell formula cell instance */ static void unshareFormulaCell(const CellStoreType::position_type& aPos, ScFormulaCell& rCell); + + /** + * Make specified formula cells non-shared ones, and split them off from + * their respective adjacent formula cell groups. + * + * @param rCells cell storage container + * @param rRows row positions at which to unshare formula cells. + */ + static void unshareFormulaCells(CellStoreType& rCells, std::vector<SCROW>& rRows); }; } diff --git a/sc/inc/sortparam.hxx b/sc/inc/sortparam.hxx index f566aca799f9..e61528bed0b3 100644 --- a/sc/inc/sortparam.hxx +++ b/sc/inc/sortparam.hxx @@ -79,6 +79,33 @@ struct SC_DLLPUBLIC ScSortParam inline sal_uInt16 GetSortKeyCount() const { return maKeyState.size(); } }; +namespace sc { + +struct SC_DLLPUBLIC ReorderParam +{ + /** + * This sort range already takes into account the presence or absence of + * header row / column i.e. if a header row / column is present, it + * excludes that row / column. + */ + ScRange maSortRange; + + /** + * List of original column / row positions after reordering. + */ + std::vector<SCCOLROW> maOrderIndices; + bool mbByRow; + bool mbPattern; + bool mbHiddenFiltered; + + /** + * Reorder the position indices such that it can be used to undo the + * original reordering. + */ + void reverse(); +}; + +} #endif // INCLUDED_SC_INC_SORTPARAM_HXX diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 6492f817e54c..c4ad09e9b6b3 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -73,6 +73,7 @@ class RowHeightContext; class CompileFormulaContext; struct SetFormulaDirtyContext; class RefMovedHint; +struct ReorderParam; } @@ -824,7 +825,10 @@ public: void StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 ); void ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 ); - void Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress); + void Sort( + const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* pProgress, sc::ReorderParam* pUndo ); + void Reorder( const sc::ReorderParam& rParam, ScProgress* pProgress ); + bool ValidQuery( SCROW nRow, const ScQueryParam& rQueryParam, ScRefCellValue* pCell = NULL, bool* pbTestEqualCondition = NULL); @@ -880,6 +884,9 @@ public: formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); formula::VectorRefArray FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 ); + void UnshareFormulaCells( SCCOL nCol, std::vector<SCROW>& rRows ); + void RegroupFormulaCells( SCCOL nCol ); + ScRefCellValue GetRefCellValue( SCCOL nCol, SCROW nRow ); SvtBroadcaster* GetBroadcaster( SCCOL nCol, SCROW nRow ); @@ -1014,10 +1021,11 @@ private: ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const; short Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const; short Compare( ScSortInfoArray*, SCCOLROW nIndex1, SCCOLROW nIndex2) const; - ScSortInfoArray* CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery ); + ScSortInfoArray* CreateSortInfoArray( const sc::ReorderParam& rParam ); + ScSortInfoArray* CreateSortInfoArray( const ScSortParam& rSortParam, SCCOLROW nInd1, SCCOLROW nInd2, bool bKeepQuery ); void QuickSort( ScSortInfoArray*, SCsCOLROW nLo, SCsCOLROW nHi); - void SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress ); - void SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress ); + void SortReorderByColumn( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress ); + void SortReorderByRow( ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress ); bool CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam); bool CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam); diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 9538819e7733..0ce6f7151669 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -169,7 +169,13 @@ public: * @param nRow2 bottom row of reordered range. * @param rColMap old-to-new column mapping. */ - void MoveReference( const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColReorderMapType& rColMap ); + void MoveReferenceColReorder( + const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, + const sc::ColRowReorderMapType& rColMap ); + + void MoveReferenceRowReorder( + const ScAddress& rPos, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, + const sc::ColRowReorderMapType& rRowMap ); /** * Adjust all references in named expression. In named expression, we only diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx index 8d37ad45e6a3..37784dc2f6ca 100644 --- a/sc/inc/types.hxx +++ b/sc/inc/types.hxx @@ -98,7 +98,7 @@ struct RangeMatrix bool isRangeValid() const; }; -typedef boost::unordered_map<SCCOL,SCCOL> ColReorderMapType; +typedef boost::unordered_map<SCCOLROW,SCCOLROW> ColRowReorderMapType; } diff --git a/sc/inc/undosort.hxx b/sc/inc/undosort.hxx new file mode 100644 index 000000000000..388fcfa48bc9 --- /dev/null +++ b/sc/inc/undosort.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_SC_UNDOSORT_HXX +#define INCLUDED_SC_UNDOSORT_HXX + +#include <undobase.hxx> +#include <sortparam.hxx> + +namespace sc { + +class UndoSort : public ScSimpleUndo +{ + ReorderParam maParam; + +public: + UndoSort( ScDocShell* pDocSh, const ReorderParam& rParam ); + + virtual OUString GetComment() const; + virtual void Undo(); + virtual void Redo(); + +private: + void Execute( bool bUndo ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx index 796a01d20836..0ea9f85cad37 100644 --- a/sc/qa/unit/filters-test.cxx +++ b/sc/qa/unit/filters-test.cxx @@ -35,6 +35,7 @@ #include <dbdocfun.hxx> #include <globalnames.hxx> #include <dbdata.hxx> +#include <sortparam.hxx> #include <svx/svdpage.hxx> diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index d8f143749301..8f22cf44dfd3 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -63,6 +63,7 @@ #include <docpool.hxx> #include <globalnames.hxx> #include <inputopt.hxx> +#include <sortparam.hxx> #include <formula/IFunctionDescription.hxx> @@ -4772,7 +4773,7 @@ void Test::testSortWithFormulaRefs() aSortData.maKeyState[0].bDoSort = true; aSortData.maKeyState[0].nField = 0; - m_pDoc->Sort(0, aSortData, false, NULL); + m_pDoc->Sort(0, aSortData, false, NULL, NULL); for (size_t i = 0; i < SAL_N_ELEMENTS(aResults); ++i) { @@ -4807,7 +4808,7 @@ void Test::testSortWithStrings() aParam.maKeyState[0].bAscending = true; aParam.maKeyState[0].nField = 1; - m_pDoc->Sort(0, aParam, false, NULL); + m_pDoc->Sort(0, aParam, false, NULL, NULL); CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0))); CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,2,0))); @@ -4815,7 +4816,7 @@ void Test::testSortWithStrings() aParam.maKeyState[0].bAscending = false; - m_pDoc->Sort(0, aParam, false, NULL); + m_pDoc->Sort(0, aParam, false, NULL, NULL); CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0))); CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0))); @@ -4858,7 +4859,7 @@ void Test::testSort() aSortData.maKeyState[0].nField = 1; aSortData.maKeyState[0].bAscending = true; - m_pDoc->Sort(0, aSortData, false, NULL); + m_pDoc->Sort(0, aSortData, false, NULL, NULL); double nVal = m_pDoc->GetValue(1,0,0); ASSERT_DOUBLES_EQUAL(nVal, 1.0); @@ -4891,7 +4892,7 @@ void Test::testSort() aSortData.nRow2 = aDataRange.aEnd.Row(); aSortData.bHasHeader = true; aSortData.maKeyState[0].nField = 0; - m_pDoc->Sort(0, aSortData, false, NULL); + m_pDoc->Sort(0, aSortData, false, NULL, NULL); // Title should stay at the top, numbers should be sorted numerically, // numbers always come before strings, and empty cells always occur at the @@ -5021,7 +5022,7 @@ void Test::testSortInFormulaGroup() aSortData.maKeyState[0].nField = 0; aSortData.maKeyState[0].bAscending = true; - m_pDoc->Sort(0, aSortData, false, NULL); + m_pDoc->Sort(0, aSortData, false, NULL, NULL); static struct { SCCOL nCol; diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 051c0d1faef7..73cb7ad24cfe 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -1365,17 +1365,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<SCTAB>(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<SCTAB>(maTabs.size()) && maTabs[nTab] ) @@ -2051,4 +2064,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 4112bb9d0ee3..f633a479a449 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -293,4 +293,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<SCROW>& 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 2ff6079e4e35..1d844b1f1f13 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -56,6 +56,8 @@ #include "refupdatecontext.hxx" #include <tokenstringcontext.hxx> #include <refhint.hxx> +#include <listenerquery.hxx> +#include <listenerqueryids.hxx> #include <boost/scoped_ptr.hpp> @@ -1925,8 +1927,23 @@ void ScFormulaCell::Notify( const SfxHint& rHint ) const sc::RefColReorderHint& rRefColReorder = static_cast<const sc::RefColReorderHint&>(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<const sc::RefRowReorderHint&>(rRefHint); + if (!IsShared() || IsSharedTop()) + pCode->MoveReferenceRowReorder( + aPos, rRefRowReorder.getTab(), + rRefRowReorder.getStartColumn(), + rRefRowReorder.getEndColumn(), + rRefRowReorder.getRowMap()); } break; default: @@ -1971,6 +1988,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<sc::RefQueryFormulaGroup&>(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 34392e06d013..7851a45bf407 100644 --- a/sc/source/core/data/sortparam.cxx +++ b/sc/source/core/data/sortparam.cxx @@ -236,4 +236,55 @@ void ScSortParam::MoveToDest() } } +namespace sc { + +namespace { + +struct ReorderIndex +{ + struct LessByPos2 : std::binary_function<ReorderIndex, ReorderIndex, bool> + { + 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<ReorderIndex> 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<SCCOLROW> 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 1b2f86cc10e1..ecfd8503f455 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -60,6 +60,7 @@ #include <listenercontext.hxx> #include <sharedformula.hxx> #include <refhint.hxx> +#include <listenerquery.hxx> #include <svl/sharedstringpool.hxx> @@ -258,39 +259,46 @@ private: SCCOLROW mnLastIndex; /// index of last non-empty cell position. sal_uInt16 nUsedSorts; - std::vector<SCCOLROW> maOldIndices; + std::vector<SCCOLROW> 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<Row>()); @@ -300,11 +308,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<SCSIZE>(nInd1 - nStart); SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart); for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) @@ -315,7 +342,7 @@ public: ppInfo[n2] = pTmp; } - std::swap(maOldIndices[n1], maOldIndices[n2]); + std::swap(maOrderIndices[n1], maOrderIndices[n2]); if (mpRows) { @@ -325,13 +352,47 @@ public: } } + void SetOrderIndices( const std::vector<SCCOLROW>& 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<SCCOLROW>& rIndices ) + { + if (!mpRows) + return; + + RowsType& rRows = *mpRows; + + std::vector<SCCOLROW> aOrderIndices2; + aOrderIndices2.reserve(rIndices.size()); + + RowsType aRows2; + aRows2.reserve(rRows.size()); + + std::vector<SCCOLROW>::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<SCCOLROW>& GetOldIndices() const { return maOldIndices; } + const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; } RowsType& InitDataRows( size_t nRowSize, size_t nColSize ) { @@ -349,19 +410,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<SCCOL>(aSortParam.maKeyState[nSort].nField); + SCCOL nCol = static_cast<SCCOL>(rSortParam.maKeyState[nSort].nField); ScColumn* pCol = &aCol[nCol]; sc::ColumnBlockConstPosition aBlockPos; pCol->InitBlockPosition(aBlockPos); @@ -373,49 +513,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<SCCOL>(nInd1); nCol <= static_cast<SCCOL>(nInd2); nCol++ ) { @@ -531,12 +637,13 @@ void ScTable::DestroySortCollator() namespace { -class ColReorderNotifier : std::unary_function<SvtListener*, void> +template<typename _Hint, typename _ReorderMap, typename _Index> +class ReorderNotifier : std::unary_function<SvtListener*, void> { - 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 ) { @@ -544,77 +651,86 @@ public: } }; -} +typedef ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> ColReorderNotifier; +typedef ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> RowReorderNotifier; -void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress ) +class FormulaGroupPosCollector : std::unary_function<SvtListener*, void> { - 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<ScSortInfo*> aTable(nCount); - SCSIZE nPos; - for ( nPos = 0; nPos < nCount; nPos++ ) - aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos]; + std::vector<SCCOLROW> 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<SCCOLROW> 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<SCCOLROW>& rOldIndices = pArray->GetOldIndices(); + sc::ColRowReorderMapType aColMap; + const std::vector<SCCOLROW>& 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<SvtListener*> 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 @@ -622,28 +738,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<SortedColumn> aSortedCols; // storage for copied cells. SortedRowFlags aRowFlags; aSortedCols.reserve(nColCount); @@ -660,7 +776,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]; @@ -682,14 +798,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: @@ -738,7 +854,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; @@ -813,10 +929,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<SCCOLROW>& 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<SvtListener*> 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<SCROW> 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( @@ -1035,11 +1203,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; @@ -1053,15 +1231,19 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p if(pProgress) pProgress->SetState( 0, nLastRow-nRow1 ); - boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nRow1, nLastRow, bKeepQuery)); + boost::scoped_ptr<ScSortInfoArray> 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 @@ -1078,17 +1260,48 @@ void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery, ScProgress* p if(pProgress) pProgress->SetState( 0, nLastCol-nCol1 ); - boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nCol1, nLastCol, bKeepQuery)); + boost::scoped_ptr<ScSortInfoArray> 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<ScSortInfoArray> 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 @@ -2079,7 +2292,7 @@ void ScTable::TopTenQuery( ScQueryParam& rParam ) bSortCollatorInitialized = true; InitSortCollator( aLocalSortParam ); } - boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(nRow1, rParam.nRow2, bGlobalKeepQuery)); + boost::scoped_ptr<ScSortInfoArray> 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 <clipparam.hxx> #include <bcaslot.hxx> #include <segmenttree.hxx> +#include <sharedformula.hxx> 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<SCROW>& 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 <listenerquery.hxx> +#include <listenerqueryids.hxx> +#include <address.hxx> + +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<TabsType::iterator,bool> 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<ColsType::iterator,bool> 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 0e70b4f22ac3..29a91665c537 100644 --- a/sc/source/core/tool/refhint.cxx +++ b/sc/source/core/tool/refhint.cxx @@ -31,12 +31,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; } @@ -56,6 +56,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<SCROW>& 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<SCROW> aRows2; + std::vector<SCROW>::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 87388778ee69..f37f558944a1 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2924,8 +2924,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<size_t>(nLen); @@ -2942,7 +2942,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. @@ -2970,7 +2970,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. @@ -2988,6 +2988,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<size_t>(nLen); + for (; p != pEnd; ++p) + { + switch ((*p)->GetType()) + { + case svSingleRef: + { + ScToken* pToken = static_cast<ScToken*>(*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<ScToken*>(*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 <sortparam.hxx> #include <svx/dataaccessdescriptor.hxx> diff --git a/sc/source/filter/xml/xmldrani.cxx b/sc/source/filter/xml/xmldrani.cxx index 60ef6c766b53..c4b053cb499a 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 <sortparam.hxx> #include <xmloff/xmltkmap.hxx> #include <xmloff/nmspmap.hxx> diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx index 8238b9a42457..40b67de44921 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 <undosort.hxx> #include <set> #include <memory> @@ -430,8 +431,6 @@ bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, ScDocument* pDoc = rDocShell.GetDocument(); if (bRecord && !pDoc->IsUndoEnabled()) bRecord = false; - SCTAB nSrcTab = nTab; - ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); ScDBData* pDBData = pDoc->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 = pDoc->GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow, - rSortParam.nDestTab, true ); - if (pDestData) - pDestData->GetArea(aOldDest); + aLocalParam.MoveToDest(); } ScEditableTester aTester( pDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1, @@ -512,133 +508,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( pDoc, 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. */ - pDoc->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. */ - pDoc->CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc ); - pR = &aOldDest; - } - - // Zeilenhoehen immer (wegen automatischer Anpassung) - //! auf ScBlockUndo umstellen -// if (bRepeatQuery) - pDoc->CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab, - IDF_NONE, false, pUndoDoc ); - - ScDBCollection* pUndoDB = NULL; - ScDBCollection* pDocDB = pDoc->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) - pDoc->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); - pDoc->Sort( nTab, aLocalParam, bRepeatQuery, &aProgress ); + pDoc->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, @@ -658,23 +544,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/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx index 6a2510b6c2cc..8a0ea2d9e0cc 100644 --- a/sc/source/ui/undo/undobase.cxx +++ b/sc/source/ui/undo/undobase.cxx @@ -33,6 +33,7 @@ #include "globstr.hrc" #include <rowheightcontext.hxx> #include <column.hxx> +#include <sortparam.hxx> TYPEINIT1(ScSimpleUndo, SfxUndoAction); diff --git a/sc/source/ui/undo/undosort.cxx b/sc/source/ui/undo/undosort.cxx new file mode 100644 index 000000000000..4ff0960b7413 --- /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 <undosort.hxx> +#include <globstr.hrc> +#include <global.hxx> +#include <undoutil.hxx> + +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 dd3a0e25e0e3..ee1d7438dae1 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 <sortparam.hxx> #include <list> #include <boost/scoped_array.hpp> diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx index 09762b1f1402..7a64212cad16 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 <sortparam.hxx> #include <comphelper/extract.hxx> #include <comphelper/servicehelper.hxx> diff --git a/svl/source/notify/listener.cxx b/svl/source/notify/listener.cxx index 66207bf4c0bc..f905090b81c8 100644 --- a/svl/source/notify/listener.cxx +++ b/svl/source/notify/listener.cxx @@ -21,6 +21,14 @@ #include <svl/broadcast.hxx> #include <tools/debug.hxx> +SvtListener::QueryBase::QueryBase( sal_uInt16 nId ) : mnId(nId) {} +SvtListener::QueryBase::~QueryBase() {} + +sal_uInt16 SvtListener::QueryBase::getId() const +{ + return mnId; +} + SvtListener::SvtListener() {} SvtListener::SvtListener( const SvtListener &r ) : @@ -75,12 +83,26 @@ bool SvtListener::IsListening( SvtBroadcaster& rBroadcaster ) const return maBroadcasters.count(&rBroadcaster) > 0; } +void SvtListener::CopyAllBroadcasters( const SvtListener& r ) +{ + BroadcastersType aCopy(r.maBroadcasters); + maBroadcasters.swap(aCopy); + BroadcastersType::iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end(); + for (; it != itEnd; ++it) + { + SvtBroadcaster* p = *it; + p->Add(this); + } +} + bool SvtListener::HasBroadcaster() const { return !maBroadcasters.empty(); } -void SvtListener::Notify( const SfxHint& ) {} +void SvtListener::Notify( const SfxHint& /*rHint*/ ) {} + +void SvtListener::Query( QueryBase& /*rQuery*/ ) const {} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |