summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-05-01 01:15:02 -0400
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-05-01 01:18:50 -0400
commit3c4fb52d8fc89fe43983991ed2339295b2e0ef8c (patch)
treee1f5f8f6f047edad2d610394c737ff2f1ceca44c
parent0e443b773454fa153827753812757d88eea932c5 (diff)
fdo#78079: Re-work sort by column to get it to do the right thing.
Also fixed reference update problem. Change-Id: I06e6115ef969a011fdd5c92d5eb1927fb7ae789b
-rw-r--r--sc/inc/address.hxx13
-rw-r--r--sc/inc/column.hxx20
-rw-r--r--sc/inc/refhint.hxx20
-rw-r--r--sc/inc/table.hxx1
-rw-r--r--sc/inc/tokenarray.hxx20
-rw-r--r--sc/inc/types.hxx15
-rw-r--r--sc/source/core/data/column.cxx60
-rw-r--r--sc/source/core/data/column4.cxx129
-rw-r--r--sc/source/core/data/formulacell.cxx24
-rw-r--r--sc/source/core/data/table3.cxx95
-rw-r--r--sc/source/core/tool/refhint.cxx25
-rw-r--r--sc/source/core/tool/token.cxx160
12 files changed, 467 insertions, 115 deletions
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index e8f4c93f830b..f856f3d578d5 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -26,6 +26,7 @@
#include <limits>
#include "scdllapi.h"
+#include <types.hxx>
#include <formula/grammar.hxx>
#include <com/sun/star/uno/Sequence.hxx>
@@ -38,18 +39,6 @@ namespace com { namespace sun { namespace star {
class ScDocument;
-// The typedefs
-typedef sal_Int32 SCROW;
-typedef sal_Int16 SCCOL;
-typedef sal_Int16 SCTAB;
-typedef sal_Int32 SCCOLROW; ///< a type capable of holding either SCCOL or SCROW
-
-// temporarily signed typedefs
-typedef sal_Int32 SCsROW;
-typedef sal_Int16 SCsCOL;
-typedef sal_Int16 SCsTAB;
-typedef sal_Int32 SCsCOLROW;
-
/** size_t typedef to be able to find places where code was changed from USHORT
to size_t and is used to read/write from/to streams. */
typedef size_t SCSIZE;
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 0e13ec940d49..526c8e3af598 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -186,7 +186,7 @@ public:
void Delete( SCROW nRow );
void FreeAll();
- void SwapCell( SCROW nRow, ScColumn& rCol);
+ void Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern );
bool HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const;
bool HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const;
@@ -480,6 +480,7 @@ public:
void BroadcastRecalcOnRefMove();
void BroadcastRefMoved( const sc::RefMovedHint& rHint );
void TransferListeners( ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta );
+ void CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 );
void CompileDBFormula( sc::CompileFormulaContext& rCxt );
void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
@@ -576,6 +577,23 @@ public:
*/
void RegroupFormulaCells();
+ /**
+ * Reset column position of formula cells within specified row range.
+ * Reference positions are also adjusted to reflect the new position so
+ * that the formula cells still reference the same cells or ranges after
+ * the the position change. The position of a formula cell before the
+ * call is interpreted as the old position of that cell.
+ *
+ * Caller needs to ensure that no formula groups cross the top and bottom
+ * row boundaries.
+ *
+ * @param nRow1 top row boundary
+ * @param nRow2 bottom row boundary
+ */
+ void ResetFormulaCellPositions( SCROW nRow1, SCROW nRow2 );
+
+ void SplitFormulaGroupByRelativeRef( const ScRange& rBoundRange );
+
void TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest );
void TransferCellValuesFrom( SCROW nRow, sc::CellValues& rSrc );
void CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc );
diff --git a/sc/inc/refhint.hxx b/sc/inc/refhint.hxx
index b9ddf046fb8a..9ded863d5f98 100644
--- a/sc/inc/refhint.hxx
+++ b/sc/inc/refhint.hxx
@@ -18,7 +18,7 @@ namespace sc {
class RefHint : public SfxSimpleHint
{
public:
- enum Type { Moved };
+ enum Type { Moved, ColumnReordered };
private:
Type meType;
@@ -55,6 +55,24 @@ public:
const ScAddress& getDelta() const;
};
+class RefColReorderHint : public RefHint
+{
+ const sc::ColReorderMapType& mrColMap;
+ SCTAB mnTab;
+ SCROW mnRow1;
+ SCROW mnRow2;
+
+public:
+ RefColReorderHint( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 );
+ virtual ~RefColReorderHint();
+
+ const sc::ColReorderMapType& getColMap() const;
+
+ SCTAB getTab() const;
+ SCROW getStartRow() const;
+ SCROW getEndRow() const;
+};
+
}
#endif
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index a8bef6ec7abf..16680dca0413 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1007,7 +1007,6 @@ private:
// use the global sort parameter:
bool IsSorted(SCCOLROW nStart, SCCOLROW nEnd) const;
void DecoladeRow( ScSortInfoArray*, SCROW nRow1, SCROW nRow2 );
- void SwapCol(SCCOL nCol1, SCCOL nCol2);
short CompareCell(
sal_uInt16 nSort,
ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row,
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 72447904cf89..c7ff3dcb1b93 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -157,6 +157,18 @@ public:
const ScAddress& rPos, const ScRange& rMovedRange, const ScAddress& rDelta );
/**
+ * Move reference positions in response to column reordering. A range
+ * reference gets moved only when the whole range fits in a single column.
+ *
+ * @param rPos position of this formula cell
+ * @param nTab sheet where columns are reordered.
+ * @param nRow1 top row of reordered range.
+ * @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 );
+
+ /**
* Adjust all references in named expression. In named expression, we only
* update absolute positions, and leave relative positions intact.
*
@@ -184,6 +196,11 @@ public:
sc::RefUpdateResult AdjustReferenceOnMovedTab( sc::RefUpdateMoveTabContext& rCxt, const ScAddress& rOldPos );
/**
+ * Adjust all internal references on base position change.
+ */
+ void AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos );
+
+ /**
* Clear sheet deleted flag from internal reference tokens if the sheet
* index falls within specified range. Note that when a reference is on a
* sheet that's been deleted, its referenced sheet index retains the
@@ -198,6 +215,9 @@ public:
void CheckRelativeReferenceBounds(
const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const;
+ void CheckRelativeReferenceBounds(
+ const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector<SCROW>& rBounds ) const;
+
/**
* Create a string representation of formula token array without modifying
* the internal state of the token array.
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 045f5504cd40..216a58d2fdf5 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -13,9 +13,22 @@
#include "sal/types.h"
#include <boost/intrusive_ptr.hpp>
+#include <boost/unordered_map.hpp>
class ScMatrix;
+// The typedefs
+typedef sal_Int32 SCROW;
+typedef sal_Int16 SCCOL;
+typedef sal_Int16 SCTAB;
+typedef sal_Int32 SCCOLROW; ///< a type capable of holding either SCCOL or SCROW
+
+// temporarily signed typedefs
+typedef sal_Int32 SCsROW;
+typedef sal_Int16 SCsCOL;
+typedef sal_Int16 SCsTAB;
+typedef sal_Int32 SCsCOLROW;
+
typedef ::boost::intrusive_ptr<ScMatrix> ScMatrixRef;
typedef ::boost::intrusive_ptr<const ScMatrix> ScConstMatrixRef;
@@ -85,6 +98,8 @@ struct RangeMatrix
bool isRangeValid() const;
};
+typedef boost::unordered_map<SCCOL,SCCOL> ColReorderMapType;
+
}
#endif
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index a2435989dd3a..208c04688e53 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -836,66 +836,6 @@ const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition&
return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
}
-namespace {
-
-/**
- * Adjust references in formula cell with respect to column-wise relocation.
- */
-void updateRefInFormulaCell( ScDocument* pDoc, ScFormulaCell& rCell, SCCOL nCol, SCTAB nTab, SCCOL nColDiff )
-{
- rCell.aPos.SetCol(nCol);
- sc::RefUpdateContext aCxt(*pDoc);
- aCxt.meMode = URM_MOVE;
- aCxt.maRange = ScRange(ScAddress(nCol, 0, nTab), ScAddress(nCol, MAXROW, nTab));
- aCxt.mnColDelta = nColDiff;
- rCell.UpdateReference(aCxt);
-}
-
-}
-
-void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
-{
- sc::CellStoreType::position_type aPos1 = maCells.position(nRow);
- sc::CellStoreType::position_type aPos2 = rCol.maCells.position(nRow);
-
- if (aPos1.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
- updateRefInFormulaCell(pDocument, rCell, rCol.nCol, nTab, rCol.nCol - nCol);
- sc::SharedFormulaUtil::unshareFormulaCell(aPos1, rCell);
- }
-
- if (aPos2.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
- updateRefInFormulaCell(pDocument, rCell, nCol, nTab, nCol - rCol.nCol);
- sc::SharedFormulaUtil::unshareFormulaCell(aPos2, rCell);
- }
-
- maCells.swap(nRow, nRow, rCol.maCells, nRow);
- maCellTextAttrs.swap(nRow, nRow, rCol.maCellTextAttrs, nRow);
- maCellNotes.swap(nRow, nRow, rCol.maCellNotes, nRow);
-
- aPos1 = maCells.position(nRow);
- aPos2 = rCol.maCells.position(nRow);
-
- if (aPos1.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos1.first->data, aPos1.second);
- JoinNewFormulaCell(aPos1, rCell);
- }
-
- if (aPos2.first->type == sc::element_type_formula)
- {
- ScFormulaCell& rCell = *sc::formula_block::at(*aPos2.first->data, aPos2.second);
- rCol.JoinNewFormulaCell(aPos2, rCell);
- }
-
- CellStorageModified();
- rCol.CellStorageModified();
-}
-
-
bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
{
if (IsEmpty())
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index b9553448e669..cf9cd1e2f00a 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -28,6 +28,7 @@
#include <globalnames.hxx>
#include <scitems.hxx>
#include <cellform.hxx>
+#include <sharedformula.hxx>
#include <svl/sharedstringpool.hxx>
@@ -830,4 +831,132 @@ void ScColumn::UpdateScriptTypes( SCROW nRow1, SCROW nRow2 )
CellStorageModified();
}
+void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
+{
+ maCells.swap(nRow1, nRow2, rOther.maCells, nRow1);
+ maCellTextAttrs.swap(nRow1, nRow2, rOther.maCellTextAttrs, nRow1);
+ maCellNotes.swap(nRow1, nRow2, rOther.maCellNotes, nRow1);
+ maBroadcasters.swap(nRow1, nRow2, rOther.maBroadcasters, nRow1);
+
+ if (bPattern)
+ {
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ const ScPatternAttr* pPat1 = GetPattern(nRow);
+ const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
+ if (pPat1 != pPat2)
+ {
+ SetPattern(nRow, *pPat2, true);
+ rOther.SetPattern(nRow, *pPat1, true);
+ }
+ }
+ }
+
+ CellStorageModified();
+ rOther.CellStorageModified();
+}
+
+namespace {
+
+class FormulaColPosSetter
+{
+ SCCOL mnCol;
+public:
+ FormulaColPosSetter( SCCOL nCol ) : mnCol(nCol) {}
+
+ void operator() ( size_t nRow, ScFormulaCell* pCell )
+ {
+ if (!pCell->IsShared() || pCell->IsSharedTop())
+ {
+ // Ensure that the references still point to the same locations
+ // after the position change.
+ ScAddress aOldPos = pCell->aPos;
+ pCell->aPos.SetCol(mnCol);
+ pCell->aPos.SetRow(nRow);
+ pCell->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, pCell->aPos);
+ }
+ else
+ {
+ pCell->aPos.SetCol(mnCol);
+ pCell->aPos.SetRow(nRow);
+ }
+ }
+};
+
+}
+
+void ScColumn::ResetFormulaCellPositions( SCROW nRow1, SCROW nRow2 )
+{
+ FormulaColPosSetter aFunc(nCol);
+ sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
+}
+
+namespace {
+
+class RelativeRefBoundChecker
+{
+ std::vector<SCROW> maBounds;
+ ScRange maBoundRange;
+
+public:
+ RelativeRefBoundChecker( const ScRange& rBoundRange ) :
+ maBoundRange(rBoundRange) {}
+
+ void operator() ( size_t /*nRow*/, ScFormulaCell* pCell )
+ {
+ if (!pCell->IsSharedTop())
+ return;
+
+ pCell->GetCode()->CheckRelativeReferenceBounds(
+ pCell->aPos, pCell->GetSharedLength(), maBoundRange, maBounds);
+ }
+
+ void swapBounds( std::vector<SCROW>& rBounds )
+ {
+ rBounds.swap(maBounds);
+ }
+};
+
+}
+
+void ScColumn::SplitFormulaGroupByRelativeRef( const ScRange& rBoundRange )
+{
+ std::vector<SCROW> aBounds;
+
+ // Cut at row boundaries first.
+ aBounds.push_back(rBoundRange.aStart.Row());
+ aBounds.push_back(rBoundRange.aEnd.Row()+1);
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+
+ RelativeRefBoundChecker aFunc(rBoundRange);
+ sc::ProcessFormula(
+ maCells.begin(), maCells, rBoundRange.aStart.Row(), rBoundRange.aEnd.Row(), aFunc);
+ aFunc.swapBounds(aBounds);
+ sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+}
+
+namespace {
+
+class ListenerCollector
+{
+ std::vector<SvtListener*>& mrListeners;
+public:
+ ListenerCollector( std::vector<SvtListener*>& rListener ) :
+ mrListeners(rListener) {}
+
+ void operator() ( size_t /*nRow*/, SvtBroadcaster* p )
+ {
+ SvtBroadcaster::ListenersType& rLis = p->GetAllListeners();
+ std::copy(rLis.begin(), rLis.end(), std::back_inserter(mrListeners));
+ }
+};
+
+}
+
+void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 )
+{
+ ListenerCollector aFunc(rListeners);
+ sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index aa52450b576d..d7cef22772b6 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1898,12 +1898,28 @@ void ScFormulaCell::Notify( const SfxHint& rHint )
{
const sc::RefHint& rRefHint = static_cast<const sc::RefHint&>(rHint);
- if (rRefHint.getType() == sc::RefHint::Moved)
+ switch (rRefHint.getType())
{
- // One of the references has moved.
+ case sc::RefHint::Moved:
+ {
+ // One of the references has moved.
- const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
- pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+ const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
+ if (!IsShared() || IsSharedTop())
+ pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+ }
+ break;
+ case sc::RefHint::ColumnReordered:
+ {
+ const sc::RefColReorderHint& rRefColReorder =
+ static_cast<const sc::RefColReorderHint&>(rRefHint);
+ if (!IsShared() || IsSharedTop())
+ pCode->MoveReference(
+ aPos, rRefColReorder.getTab(), rRefColReorder.getStartRow(), rRefColReorder.getEndRow(), rRefColReorder.getColMap());
+ }
+ break;
+ default:
+ ;
}
return;
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 2cf6c1b26401..f32d5597c2ca 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -60,6 +60,7 @@
#include <fstalgorithm.hxx>
#include <listenercontext.hxx>
#include <sharedformula.hxx>
+#include <refhint.hxx>
#include "svl/sharedstringpool.hxx"
@@ -257,6 +258,7 @@ private:
SCCOLROW mnLastIndex; /// index of last non-empty cell position.
sal_uInt16 nUsedSorts;
+ std::vector<SCCOLROW> maOldIndices;
bool mbKeepQuery;
public:
@@ -274,6 +276,9 @@ public:
ppInfo[j] = new ScSortInfo;
pppInfo[nSort] = ppInfo;
}
+
+ for (size_t i = 0; i < nCount; ++i)
+ maOldIndices.push_back(i+nStart);
}
~ScSortInfoArray()
@@ -310,6 +315,8 @@ public:
ppInfo[n2] = pTmp;
}
+ std::swap(maOldIndices[n1], maOldIndices[n2]);
+
if (mpRows)
{
// Swap rows in data table.
@@ -324,6 +331,8 @@ public:
SCCOLROW GetLast() const { return mnLastIndex; }
SCSIZE GetCount() const { return nCount; }
+ const std::vector<SCCOLROW>& GetOldIndices() const { return maOldIndices; }
+
RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
{
mpRows.reset(new RowsType);
@@ -520,6 +529,22 @@ void ScTable::DestroySortCollator()
}
}
+namespace {
+
+class ColReorderNotifier : std::unary_function<SvtListener*, void>
+{
+ sc::RefColReorderHint maHint;
+public:
+ ColReorderNotifier( const sc::ColReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) :
+ maHint(rColMap, nTab, nRow1, nRow2) {}
+
+ void operator() ( SvtListener* p )
+ {
+ p->Notify(maHint);
+ }
+};
+
+}
void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
{
@@ -531,20 +556,28 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
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];
+ // Cut formula grouping at row and reference boundaries before the reordering.
+ ScRange aSortRange(nStart, aSortParam.nRow1, nTab, nLast, aSortParam.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 )
{
- SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
+ aCol[nDest].Swap(aCol[nOrg], aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern);
+
// neue Position des weggeswapten eintragen
ScSortInfo* p = ppInfo[nPos];
p->nOrg = nDest;
@@ -556,6 +589,44 @@ void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress* pProgress )
if(pProgress)
pProgress->SetStateOnPercent( nPos );
}
+
+ // 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);
+
+ // Set up column reorder map (for later broadcasting of reference updates).
+ sc::ColReorderMapType aColMap;
+ const std::vector<SCCOLROW>& rOldIndices = pArray->GetOldIndices();
+ 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));
+ }
+
+ // 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);
+
+ // 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);
+ std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+
+ // Re-join formulas at row boundaries now that all the references have
+ // been adjusted for column reordering.
+ for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
+ {
+ sc::CellStoreType& rCells = aCol[nCol].maCells;
+ sc::CellStoreType::position_type aPos = rCells.position(aSortParam.nRow1);
+ sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
+ aPos = rCells.position(aPos.first, aSortParam.nRow2+1);
+ sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
+ }
}
void ScTable::SortReorderByRow( ScSortInfoArray* pArray, ScProgress* pProgress )
@@ -913,28 +984,6 @@ void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
}
}
-void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
-{
- SCROW nRowStart = aSortParam.nRow1;
- SCROW nRowEnd = aSortParam.nRow2;
- for (SCROW nRow = nRowStart; nRow <= nRowEnd; nRow++)
- {
- aCol[nCol1].SwapCell(nRow, aCol[nCol2]);
- if (aSortParam.bIncludePattern)
- {
- const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow);
- const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow);
- if (pPat1 != pPat2)
- {
- pDocument->GetPool()->Put(*pPat1);
- SetPattern(nCol1, nRow, *pPat2, true);
- SetPattern(nCol2, nRow, *pPat1, true);
- pDocument->GetPool()->Remove(*pPat1);
- }
- }
- }
-}
-
short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
{
short nRes;
diff --git a/sc/source/core/tool/refhint.cxx b/sc/source/core/tool/refhint.cxx
index eb07b4fe3565..0e70b4f22ac3 100644
--- a/sc/source/core/tool/refhint.cxx
+++ b/sc/source/core/tool/refhint.cxx
@@ -31,6 +31,31 @@ const ScAddress& RefMovedHint::getDelta() const
return maMoveDelta;
}
+RefColReorderHint::RefColReorderHint( const sc::ColReorderMapType& 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
+{
+ return mrColMap;
+}
+
+SCTAB RefColReorderHint::getTab() const
+{
+ return mnTab;
+}
+
+SCROW RefColReorderHint::getStartRow() const
+{
+ return mnRow1;
+}
+
+SCROW RefColReorderHint::getEndRow() const
+{
+ return mnRow2;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 016ff7942d77..bd884eb0246c 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2879,6 +2879,70 @@ void ScTokenArray::MoveReference(
}
}
+void ScTokenArray::MoveReference(
+ const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColReorderMapType& rColMap )
+{
+ 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 && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2)
+ {
+ // Inside reordered row range.
+ sc::ColReorderMapType::const_iterator it = rColMap.find(aAbs.Col());
+ if (it != rColMap.end())
+ {
+ // This column is reordered.
+ SCCOL nNewCol = it->second;
+ aAbs.SetCol(nNewCol);
+ 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.Col() != aAbs.aEnd.Col())
+ // Whole range must fit in a single column.
+ break;
+
+ 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());
+ if (it != rColMap.end())
+ {
+ // This column is reordered.
+ SCCOL nNewCol = it->second;
+ aAbs.aStart.SetCol(nNewCol);
+ aAbs.aEnd.SetCol(nNewCol);
+ rRef.SetRange(aAbs, rPos);
+ }
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
bool adjustSingleRefInName(
@@ -3292,6 +3356,36 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
return aRes;
}
+void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ScAddress& rNewPos )
+{
+ 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(rOldPos);
+ rRef.SetAddress(aAbs, rNewPos);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ ScComplexRefData& rRef = pToken->GetDoubleRef();
+ ScRange aAbs = rRef.toAbs(rOldPos);
+ rRef.SetRange(aAbs, rNewPos);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
void clearTabDeletedFlag( ScSingleRefData& rRef, const ScAddress& rPos, SCTAB nStartTab, SCTAB nEndTab )
@@ -3341,28 +3435,23 @@ void ScTokenArray::ClearTabDeleted( const ScAddress& rPos, SCTAB nStartTab, SCTA
namespace {
void checkBounds(
- const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
- const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+ const ScAddress& rPos, SCROW nGroupLen, const ScRange& rCheckRange,
+ const ScSingleRefData& rRef, std::vector<SCROW>& rBounds )
{
if (!rRef.IsRowRel())
return;
- ScRange aCheckRange = rCxt.maRange;
- if (rCxt.meMode == URM_MOVE)
- // Check bounds against the old range prior to the move.
- aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
-
ScRange aAbs(rRef.toAbs(rPos));
aAbs.aEnd.IncRow(nGroupLen-1);
- if (!aCheckRange.Intersects(aAbs))
+ if (!rCheckRange.Intersects(aAbs))
return;
// Get the boundary row positions.
- if (aAbs.aEnd.Row() < aCheckRange.aStart.Row())
+ if (aAbs.aEnd.Row() < rCheckRange.aStart.Row())
// No intersections.
return;
- if (aAbs.aStart.Row() <= aCheckRange.aStart.Row())
+ if (aAbs.aStart.Row() <= rCheckRange.aStart.Row())
{
// +-+ <---- top
// | |
@@ -3372,11 +3461,11 @@ void checkBounds(
// +-------+
// Add offset from the reference top to the cell position.
- SCROW nOffset = aCheckRange.aStart.Row() - aAbs.aStart.Row();
+ SCROW nOffset = rCheckRange.aStart.Row() - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
- if (aAbs.aEnd.Row() >= aCheckRange.aEnd.Row())
+ if (aAbs.aEnd.Row() >= rCheckRange.aEnd.Row())
{
// only check for end range
@@ -3388,11 +3477,26 @@ void checkBounds(
// +-+
// Ditto.
- SCROW nOffset = aCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
+ SCROW nOffset = rCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
}
+void checkBounds(
+ const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
+ const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+{
+ if (!rRef.IsRowRel())
+ return;
+
+ ScRange aCheckRange = rCxt.maRange;
+ if (rCxt.meMode == URM_MOVE)
+ // Check bounds against the old range prior to the move.
+ aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
+ checkBounds(rPos, nGroupLen, aCheckRange, rRef, rBounds);
+}
+
}
void ScTokenArray::CheckRelativeReferenceBounds(
@@ -3424,6 +3528,36 @@ void ScTokenArray::CheckRelativeReferenceBounds(
}
}
+void ScTokenArray::CheckRelativeReferenceBounds(
+ const ScAddress& rPos, SCROW nGroupLen, const ScRange& rRange, std::vector<SCROW>& rBounds ) const
+{
+ 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);
+ const ScSingleRefData& rRef = pToken->GetSingleRef();
+ checkBounds(rPos, nGroupLen, rRange, rRef, rBounds);
+ }
+ break;
+ case svDoubleRef:
+ {
+ ScToken* pToken = static_cast<ScToken*>(*p);
+ const ScComplexRefData& rRef = pToken->GetDoubleRef();
+ checkBounds(rPos, nGroupLen, rRange, rRef.Ref1, rBounds);
+ checkBounds(rPos, nGroupLen, rRange, rRef.Ref2, rBounds);
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
namespace {
void appendDouble( sc::TokenStringContext& rCxt, OUStringBuffer& rBuf, double fVal )