fdo#81309: Adjust references during sort.
Change-Id: I2b98610f6b774400ecfaffe2905201c27fcab33f
diff --git a/include/svl/listener.hxx b/include/svl/listener.hxx
index 1c98458..8b47fda 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 9b55aa4..639946a 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 d7f8752..44e88c0 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 {
@@ -1676,7 +1679,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 );
@@ -2033,8 +2038,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; }
@@ -2063,6 +2068,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 );
@@ -2148,15 +2166,6 @@ private:
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 e13e2bb..cc234c9 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 { return pDocument;}
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 0000000..2cbc957
--- /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 0000000..48f240b
--- /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 1f92731..1eff906 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 840b63b..b29843f 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 55b09a6..ab26d10 100644
--- a/sc/inc/sortparam.hxx
+++ b/sc/inc/sortparam.hxx
@@ -78,6 +78,34 @@ 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
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 412c6ca..44c4951 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 a83e115..8ae6145 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -168,7 +168,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 8d37ad4..37784dc 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 0000000..388fcfa
--- /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 bb60b7b..da9ec56 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 7708427..8e88ee4 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 <editable.hxx>
@@ -4810,7 +4811,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)
{
@@ -4845,7 +4846,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)));
@@ -4853,7 +4854,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)));
@@ -4896,7 +4897,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);
@@ -4929,7 +4930,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
@@ -5127,7 +5128,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 e8719fc..34badd8 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<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] )
@@ -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 a173362..d44bc33 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<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 44d0807..8d9dee1 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>
@@ -1938,8 +1940,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:
@@ -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<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 56448cf..1e265b3 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<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 72a066c..64f0ef5 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -59,6 +59,7 @@
#include <listenercontext.hxx>
#include <sharedformula.hxx>
#include <refhint.hxx>
#include <listenerquery.hxx>
#include <svl/sharedstringpool.hxx>
@@ -256,39 +257,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>());
@@ -298,11 +306,30 @@ public:
bool IsKeepQuery() const { return mbKeepQuery; }
ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd )
{ return (pppInfo[nSort])[ nInd - nStart ]; }
/**
* 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 )
{
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++ )
@@ -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<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 )
{
@@ -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<SCCOL>(aSortParam.maKeyState[nSort].nField);
SCCOL nCol = static_cast<SCCOL>(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<SCCOL>(nInd1);
nCol <= static_cast<SCCOL>(nInd2); nCol++ )
{
@@ -527,12 +633,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 )
{
@@ -540,77 +647,86 @@ public:
}
};
typedef ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> ColReorderNotifier;
typedef ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> RowReorderNotifier;
class FormulaGroupPosCollector : std::unary_function<SvtListener*, void>
{
sc::RefQueryFormulaGroup& mrQuery;
public:
FormulaGroupPosCollector( sc::RefQueryFormulaGroup& rQuery ) : mrQuery(rQuery) {}
void operator() ( SvtListener* p )
{
p->Query(mrQuery);
}
};
}
void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
void ScTable::SortReorderByColumn(
ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress )
{
if (aSortParam.bByRow)
{
SortReorderByRow(pArray, pProgress);
return;
}
size_t nCount = pArray->GetCount();
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);
SCCOLROW nDest = nStart;
for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
{
SCCOLROW nOrg = ppInfo[nPos]->nOrg;
if ( nDest != nOrg )
{
aCol[nDest].Swap(aCol[nOrg], aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern);
// 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;
// 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" );
SCCOLROW nDest = nStart;
for (size_t i = 0; i < nCount; ++i, ++nDest)
{
SCCOLROW nSrc = aIndices[i];
if (nDest != nSrc)
{
aCol[nDest].Swap(aCol[nSrc], nRow1, nRow2, bPattern);
// 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
@@ -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<SortedColumn> 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));
ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
// 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);
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<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(
@@ -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<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
@@ -1074,17 +1256,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
@@ -2074,7 +2287,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 845c720b..f39e529 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 0000000..bf9d38f
--- /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 80aef93..533a41b 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 ed35690..6f66365 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 7394799..99a26a8 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<size_t>(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<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 a507427..758a1f91 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 9088e00..38db1b30 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 94578f2..187621d 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& 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);
return false;
}
// 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);
nTab = rSortParam.nDestTab;
pDestData = rDoc.GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow,
rSortParam.nDestTab, true );
if (pDestData)
pDestData->GetArea(aOldDest);
ScDocFunc& rDocFunc = rDocShell.GetDocFunc();
bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi);
if (!bRet)
return false;
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)
if (bRecord)
{
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
{
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 00388d7..cbe1152 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 8740c6b..dc7efd4 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);
TYPEINIT1(ScBlockUndo, ScSimpleUndo);
diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx
index b6bc5d6..d0a7c80 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 0000000..d138491
--- /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 3a94df0..7ad0202 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 b848791..0dc0bcf 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 66207bf..f905090 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: */