[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.3' - sc/inc sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Wed May 3 22:55:41 UTC 2017


 sc/inc/colcontainer.hxx            |   11 ++++--
 sc/inc/column.hxx                  |    3 +
 sc/inc/document.hxx                |    8 ++++
 sc/inc/table.hxx                   |    2 +
 sc/inc/types.hxx                   |   14 ++++++++
 sc/source/core/data/column4.cxx    |   48 +++++++++++++++++++++++++++
 sc/source/core/data/document10.cxx |   15 ++++++++
 sc/source/core/data/table7.cxx     |   64 +++++++++++++++++++++++++++++++++++++
 sc/source/core/data/types.cxx      |    7 ++++
 sc/source/ui/view/viewfun2.cxx     |   22 +++++++++---
 10 files changed, 184 insertions(+), 10 deletions(-)

New commits:
commit 21a40e668a610fada3e06ed381d8a4c459d24f69
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon May 1 19:43:16 2017 -0400

    tdf#107255: detect whether the range has only one data cell.
    
    (cherry picked from commit 93f5cb55349e6de5003182462bfee434dc51f6ad)
    
    Conflicts:
            sc/inc/colcontainer.hxx
    
    Change-Id: I4f67f15f95a428ea9068f706abc925ebfc835d39

diff --git a/sc/inc/colcontainer.hxx b/sc/inc/colcontainer.hxx
index 1a2e9d43aa9d..0f4a64589cdd 100644
--- a/sc/inc/colcontainer.hxx
+++ b/sc/inc/colcontainer.hxx
@@ -20,22 +20,20 @@
 #ifndef INCLUDED_SC_INC_COLCONTAINER_HXX
 #define INCLUDED_SC_INC_COLCONTAINER_HXX
 
-
 #include "types.hxx"
 #include "address.hxx"
 
 #include <vector>
 
-
 class ScColumn;
 class ScDocument;
+
 class ScColContainer
 {
-public:
     typedef std::vector<ScColumn*> ScColumnVector;
-private:
     ScColumnVector    aCols;
     ScDocument*       pDocument;
+
 public:
     ScColContainer( ScDocument* pDoc, const size_t nSize );
     ~ScColContainer();
@@ -55,6 +53,11 @@ public:
         return static_cast<SCCOL>( aCols.size() );
     }
 
+    bool empty() const
+    {
+        return aCols.empty();
+    }
+
     void Clear();
 };
 
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 82ef60773628..de28a87ae63d 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -381,6 +381,9 @@ public:
     bool    HasValueData( SCROW nRow ) const;
     bool    HasStringCells( SCROW nStartRow, SCROW nEndRow ) const;
 
+    sc::MultiDataCellState::StateType HasDataCellsInRange(
+        SCROW nRow1, SCROW nRow2, SCROW* pRow1 = nullptr ) const;
+
     bool IsFormulaDirty( SCROW nRow ) const;
 
     void CheckVectorizationState();
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 10ce2e2f750a..5e4336019fb1 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1088,6 +1088,14 @@ public:
     /** Returns true, if there is any data to create a selection list for rPos. */
     bool            HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const;
 
+    /**
+     * Check if the specified range contains either: 1) one non-empty cell, 2)
+     * more than one non-empty cells, or 3) totally empty.  In case the range
+     * contains at least one non-empty cell, specify the position of the first
+     * non-empty cell.
+     */
+    sc::MultiDataCellState HasMultipleDataCells( const ScRange& rRange ) const;
+
     /** Notes **/
     SC_DLLPUBLIC ScPostIt*       GetNote(const ScAddress& rPos);
     SC_DLLPUBLIC ScPostIt*       GetNote(SCCOL nCol, SCROW nRow, SCTAB nTab);
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 34f6e3fd992a..26a729227829 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -529,6 +529,8 @@ public:
     bool        HasStringCells( SCCOL nStartCol, SCROW nStartRow,
                                 SCCOL nEndCol, SCROW nEndRow ) const;
 
+    sc::MultiDataCellState HasMultipleDataCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const;
+
     FormulaError    GetErrCode( const ScAddress& rPos ) const
                     {
                         return ValidColRow(rPos.Col(),rPos.Row()) ?
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 13983939007e..f6746063eaa8 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -97,6 +97,20 @@ struct RangeMatrix
     bool isRangeValid() const;
 };
 
+struct MultiDataCellState
+{
+    enum StateType { Invalid = 0, Empty, HasOneCell, HasMultipleCells };
+
+    StateType meState;
+
+    SCCOL mnCol1; //< first non-empty column
+    SCROW mnRow1; //< first non-empty row
+    SCTAB mnTab1; //< first non-empty sheet
+
+    MultiDataCellState();
+    MultiDataCellState( StateType eState );
+};
+
 enum AreaOverlapType
 {
     AreaInside,
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 234a8528b4e7..69d95f96fa64 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -39,6 +39,54 @@ bool ScColumn::IsMerged( SCROW nRow ) const
     return pAttrArray->IsMerged(nRow);
 }
 
+sc::MultiDataCellState::StateType ScColumn::HasDataCellsInRange(
+    SCROW nRow1, SCROW nRow2, SCROW* pRow1 ) const
+{
+    sc::CellStoreType::const_position_type aPos = maCells.position(nRow1);
+    sc::CellStoreType::const_iterator it = aPos.first;
+    size_t nOffset = aPos.second;
+    SCROW nRow = nRow1;
+    bool bHasOne = false; // whether or not we have found a non-empty block of size one.
+
+    for (; it != maCells.end() && nRow <= nRow2; ++it)
+    {
+        if (it->type != sc::element_type_empty)
+        {
+            // non-empty block found.
+            assert(it->size > 0); // mtv should never contain a block of zero length.
+            size_t nSize = it->size - nOffset;
+
+            SCROW nLastRow = nRow + nSize - 1;
+            if (nLastRow > nRow2)
+                // shrink the size to avoid exceeding the specified last row position.
+                nSize -= nLastRow - nRow2;
+
+            if (nSize == 1)
+            {
+                // this block is of size one.
+                if (bHasOne)
+                    return sc::MultiDataCellState::HasMultipleCells;
+
+                bHasOne = true;
+                if (pRow1)
+                    *pRow1 = nRow;
+            }
+            else
+            {
+                // size of this block is greater than one.
+                if (pRow1)
+                    *pRow1 = nRow;
+                return sc::MultiDataCellState::HasMultipleCells;
+            }
+        }
+
+        nRow += it->size - nOffset;
+        nOffset = 0;
+    }
+
+    return bHasOne ? sc::MultiDataCellState::HasOneCell : sc::MultiDataCellState::Empty;
+}
+
 void ScColumn::DeleteBeforeCopyFromClip(
     sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol, sc::ColumnSpanSet& rBroadcastSpans )
 {
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index c5bc3118a174..7b6ce1cc4a7a 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -39,6 +39,21 @@ bool ScDocument::IsMerged( const ScAddress& rPos ) const
     return pTab->IsMerged(rPos.Col(), rPos.Row());
 }
 
+sc::MultiDataCellState ScDocument::HasMultipleDataCells( const ScRange& rRange ) const
+{
+    if (rRange.aStart.Tab() != rRange.aEnd.Tab())
+        // Currently we only support a single-sheet range.
+        return sc::MultiDataCellState();
+
+    const ScTable* pTab = FetchTable(rRange.aStart.Tab());
+    if (!pTab)
+        return sc::MultiDataCellState(sc::MultiDataCellState::Empty);
+
+    const ScAddress& s = rRange.aStart;
+    const ScAddress& e = rRange.aEnd;
+    return pTab->HasMultipleDataCells(s.Col(), s.Row(), e.Col(), e.Row());
+}
+
 void ScDocument::DeleteBeforeCopyFromClip(
     sc::CopyFromClipContext& rCxt, const ScMarkData& rMark, sc::ColumnSpanSet& rBroadcastSpans )
 {
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index d4cd767ec256..f66be85f75cc 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -25,6 +25,70 @@ bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const
     return aCol[nCol].IsMerged(nRow);
 }
 
+sc::MultiDataCellState ScTable::HasMultipleDataCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
+{
+    if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
+        return sc::MultiDataCellState();
+
+    if (nCol1 > nCol2 || nRow1 > nRow2)
+        // invalid range.
+        return sc::MultiDataCellState();
+
+    if (aCol.empty())
+        return sc::MultiDataCellState(sc::MultiDataCellState::Empty);
+
+    auto setFirstCell = []( sc::MultiDataCellState& rRet, SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
+    {
+        if (rRet.mnCol1 < 0)
+        {
+            // First cell not yet set.  Set it.
+            rRet.mnCol1 = nCurCol;
+            rRet.mnRow1 = nCurRow;
+            rRet.mnTab1 = nCurTab;
+        }
+    };
+
+    SCCOL nMaxCol = aCol.size()-1;
+    bool bHasOne = false;
+    sc::MultiDataCellState aRet(sc::MultiDataCellState::Empty);
+
+    for (SCCOL nCol = nCol1; nCol <= nCol2 && nCol <= nMaxCol; ++nCol)
+    {
+        SCROW nFirstDataRow = -1;
+        switch (aCol[nCol].HasDataCellsInRange(nRow1, nRow2, &nFirstDataRow))
+        {
+            case sc::MultiDataCellState::HasOneCell:
+            {
+                setFirstCell(aRet, nCol, nFirstDataRow, nTab);
+
+                if (bHasOne)
+                {
+                    // We've already found one data cell in another column.
+                    aRet.meState = sc::MultiDataCellState::HasMultipleCells;
+                    return aRet;
+                }
+                bHasOne = true;
+                break;
+            }
+            case sc::MultiDataCellState::HasMultipleCells:
+            {
+                setFirstCell(aRet, nCol, nFirstDataRow, nTab);
+
+                aRet.meState = sc::MultiDataCellState::HasMultipleCells;
+                return aRet;
+            }
+            case sc::MultiDataCellState::Empty:
+            default:
+                ;
+        }
+    }
+
+    if (bHasOne)
+        aRet.meState = sc::MultiDataCellState::HasOneCell;
+
+    return aRet;
+}
+
 void ScTable::DeleteBeforeCopyFromClip(
     sc::CopyFromClipContext& rCxt, const ScTable& rClipTab, sc::ColumnSpanSet& rBroadcastSpans )
 {
diff --git a/sc/source/core/data/types.cxx b/sc/source/core/data/types.cxx
index 199819ea7506..6146f77b28ef 100644
--- a/sc/source/core/data/types.cxx
+++ b/sc/source/core/data/types.cxx
@@ -22,6 +22,13 @@ bool RangeMatrix::isRangeValid() const
         mnCol1 <= mnCol2 && mnRow1 <= mnRow2 && mnTab1 <= mnTab2;
 }
 
+MultiDataCellState::MultiDataCellState() :
+    meState(StateType::Invalid),
+    mnCol1(-1), mnRow1(-1), mnTab1(-1) {}
+MultiDataCellState::MultiDataCellState( StateType eState ) :
+    meState(eState),
+    mnCol1(-1), mnRow1(-1), mnTab1(-1) {}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
index 691ba520dc84..3373a97264ad 100644
--- a/sc/source/ui/view/viewfun2.cxx
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -1075,15 +1075,25 @@ bool ScViewFunc::MergeCells( bool bApi, bool& rDoContents, bool bCenter )
         SCTAB i = *itr;
         aMergeOption.maTabs.insert(i);
 
-        if ( nEndRow == nStartRow )
+        sc::MultiDataCellState aState = rDoc.HasMultipleDataCells(aMergeOption.getSingleRange(i));
+        switch (aState.meState)
         {
-            if (!rDoc.IsBlockEmpty(i, nStartCol+1, nStartRow, nEndCol, nEndRow))
+            case sc::MultiDataCellState::HasMultipleCells:
+            {
+                // this range contains multiple data cells.
                 bAskDialog = true;
+                break;
+            }
+            case sc::MultiDataCellState::HasOneCell:
+            {
+                // this range contains only one data cell.
+                if (nStartCol != aState.mnCol1 || nStartRow != aState.mnRow1)
+                    rDoContents = true; // move the value to the top-left.
+                break;
+            }
+            default:
+                ;
         }
-        else
-            if (!rDoc.IsBlockEmpty(i, nStartCol, nStartRow+1, nStartCol, nEndRow) ||
-                !rDoc.IsBlockEmpty(i, nStartCol+1, nStartRow, nEndCol, nEndRow))
-                bAskDialog = true;
     }
 
     bool bOk = true;


More information about the Libreoffice-commits mailing list