[Libreoffice-commits] core.git: Branch 'libreoffice-4-2' - sc/inc sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Thu May 1 13:46:07 PDT 2014


 sc/inc/address.hxx                  |   13 --
 sc/inc/column.hxx                   |   20 ++++
 sc/inc/refhint.hxx                  |   20 ++++
 sc/inc/table.hxx                    |    1 
 sc/inc/tokenarray.hxx               |   20 ++++
 sc/inc/types.hxx                    |   15 +++
 sc/source/core/data/column.cxx      |   60 -------------
 sc/source/core/data/column4.cxx     |  129 +++++++++++++++++++++++++++++
 sc/source/core/data/formulacell.cxx |   24 ++++-
 sc/source/core/data/table3.cxx      |   95 ++++++++++++++++-----
 sc/source/core/tool/refhint.cxx     |   25 +++++
 sc/source/core/tool/token.cxx       |  160 +++++++++++++++++++++++++++++++++---
 12 files changed, 467 insertions(+), 115 deletions(-)

New commits:
commit 5797fd7662d09a9f0f1ee3bf06204b5c4a6397ac
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu May 1 01:15:02 2014 -0400

    fdo#78079: Re-work sort by column to get it to do the right thing.
    
    Also fixed reference update problem.
    
    (cherry picked from commit 3c4fb52d8fc89fe43983991ed2339295b2e0ef8c)
    
    Conflicts:
    	sc/inc/column.hxx
    
    Change-Id: I06e6115ef969a011fdd5c92d5eb1927fb7ae789b
    Reviewed-on: https://gerrit.libreoffice.org/9220
    Tested-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>

diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx
index 608a505..b4ab629 100644
--- a/sc/inc/address.hxx
+++ b/sc/inc/address.hxx
@@ -27,6 +27,7 @@
 
 #include <limits>
 #include "scdllapi.h"
+#include <types.hxx>
 #include <formula/grammar.hxx>
 
 #include <com/sun/star/uno/Sequence.hxx>
@@ -39,18 +40,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 53ca5cc..bfc7a54 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -182,7 +182,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;
@@ -473,6 +473,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 );
@@ -567,6 +568,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 );
+
 #if DEBUG_COLUMN_STORAGE
     void DumpFormulaGroups() const;
 #endif
diff --git a/sc/inc/refhint.hxx b/sc/inc/refhint.hxx
index ec56735..3ffe861 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 108637b..ba7745d 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -988,7 +988,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 3c7d7e8..8715e9c 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -158,6 +158,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.
      *
@@ -185,6 +197,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
@@ -199,6 +216,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 b6c4fa6..e0163aa 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 6c3e2a9..9835a6d 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -838,66 +838,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 baa00e0..7996cd8 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -27,6 +27,7 @@
 #include <globalnames.hxx>
 #include <scitems.hxx>
 #include <cellform.hxx>
+#include <sharedformula.hxx>
 
 #include <svl/sharedstringpool.hxx>
 
@@ -387,4 +388,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 7250746..8302730 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1888,12 +1888,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 1765f25..5fceab2 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"
 
@@ -256,6 +257,7 @@ private:
     SCCOLROW        mnLastIndex; /// index of last non-empty cell position.
     sal_uInt16      nUsedSorts;
 
+    std::vector<SCCOLROW> maOldIndices;
     bool mbKeepQuery;
 
 public:
@@ -273,6 +275,9 @@ public:
                 ppInfo[j] = new ScSortInfo;
             pppInfo[nSort] = ppInfo;
         }
+
+        for (size_t i = 0; i < nCount; ++i)
+            maOldIndices.push_back(i+nStart);
     }
 
     ~ScSortInfoArray()
@@ -309,6 +314,8 @@ public:
             ppInfo[n2] = pTmp;
         }
 
+        std::swap(maOldIndices[n1], maOldIndices[n2]);
+
         if (mpRows)
         {
             // Swap rows in data table.
@@ -323,6 +330,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);
@@ -519,6 +528,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 )
 {
@@ -530,20 +555,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;
@@ -555,6 +588,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 )
@@ -912,28 +983,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 eb07b4fe..0e70b4f 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 65ed7ad..f4064f9 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2897,6 +2897,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(
@@ -3311,6 +3375,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 )
@@ -3360,28 +3454,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
         //    | |
@@ -3391,11 +3480,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
 
@@ -3407,11 +3496,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(
@@ -3443,6 +3547,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 )


More information about the Libreoffice-commits mailing list