Anonymous avatar Anonymous committed bad9bea

ooo33gsl13: #i115906# obtain correct data range for external references
* Apparently ScTable::GetFirstDataPos() never worked as intended and selected
the first non-empty row of the first non-empty column instead of also taking
following columns into account where non-empty rows may be on top of that.
* Caller of ScDocument::ShrinkToDataArea() must check the return value, if
false there is no data in the area passed and the values obtained may be out
of bounds, not in order or unmodified.
* In ScExternalRefMgr a call of ScDocument::ShrinkToUsedDataArea() was
intended instead of ScDocument::ShrinkToDataArea(). For this changed the
return of ShrinkToUsedDataArea() to flag if there is any data and added an
out parameter to flag if the area was shrunk.
* Sanitized arguments and slightly optimized ScTable::ShrinkToUsedDataArea()
to not have to check for >0 and <MAX on each iteration.
(transplanted from 31b53a2ec7e32f9560464f8a3b9f6c3e07b29083)

Comments (0)

Files changed (8)

sc/inc/document.hxx

 	USHORT			GetErrCode( const ScAddress& ) const;
 
                     /** Shrink a range to only include data area.
+
                         This is not the actually used area within the 
                         selection, but the bounds of the sheet's data area 
-                        instead. */
+                        instead.
+
+                        @returns TRUE if the area passed intersected the data 
+                                 area, FALSE if not, in which case the values 
+                                 obtained may be out of bounds, not in order or 
+                                 unmodified. TRUE does not mean that there 
+                                 actually is any data within the selection.
+                     */
     bool            ShrinkToDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) const;
 
-                    /** Shrink a range to only include used data area. */
-    bool            ShrinkToUsedDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
+                    /** Shrink a range to only include used data area.
+                        
+                        @param o_bShrunk
+                               Out parameter, TRUE if area was shrunk, FALSE if not.
+
+                        @returns TRUE if there is any data, FALSE if not.
+                     */
+    bool            ShrinkToUsedDataArea( bool& o_bShrunk,
+                                          SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+                                          SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
     void            GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
                                  SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld, bool bOnlyDown ) const;
     void        GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
                              BOOL bIncludeOld, bool bOnlyDown ) const;
 
-	bool		ShrinkToUsedDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
+    bool        ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
+                                      SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const;
 
 	SCSIZE	    GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
 										SCCOL nEndCol, SCROW nEndRow, ScDirection eDir );

sc/source/core/data/document.cxx

     return true;  // success!
 }
 
-bool ScDocument::ShrinkToUsedDataArea( SCTAB nTab, SCCOL& rStartCol,
+bool ScDocument::ShrinkToUsedDataArea( bool& o_bShrunk, SCTAB nTab, SCCOL& rStartCol,
         SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
 {
     if (!ValidTab(nTab) || !pTab[nTab])
+    {
+        o_bShrunk = false;
         return false;
-    return pTab[nTab]->ShrinkToUsedDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
+    }
+    return pTab[nTab]->ShrinkToUsedDataArea( o_bShrunk, rStartCol, rStartRow, rEndCol, rEndRow, bColumnsOnly);
 }
 
 //	zusammenhaengender Bereich

sc/source/core/data/table1.cxx

 }
 
 
-bool ScTable::ShrinkToUsedDataArea( SCCOL& rStartCol, SCROW& rStartRow,
+bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
         SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const
 {
-    bool bRet = false;
+    o_bShrunk = false;
+
+    PutInOrder( rStartCol, rEndCol);
+    PutInOrder( rStartRow, rEndRow);
+    if (rStartCol < 0)
+        rStartCol = 0, o_bShrunk = true;
+    if (rStartRow < 0)
+        rStartRow = 0, o_bShrunk = true;
+    if (rEndCol > MAXCOL)
+        rEndCol = MAXCOL, o_bShrunk = true;
+    if (rEndRow > MAXROW)
+        rEndRow = MAXROW, o_bShrunk = true;
+
     bool bChanged;
-
     do
     {
         bChanged = false;
 
-        bool bCont = true;
-        while (rEndCol > 0 && bCont && rStartCol < rEndCol)
+        while (rStartCol < rEndCol)
         {
             if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow))
             {
                 bChanged = true;
             }
             else
-                bCont = false;
+                break;  // while
         }
 
-        bCont = true;
-        while (rStartCol < MAXCOL && bCont && rStartCol < rEndCol)
+        while (rStartCol < rEndCol)
         {
             if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow))
             {
                 bChanged = true;
             }
             else
-                bCont = false;
+                break;  // while
         }
 
         if (!bColumnsOnly)
         {
-            if (rStartRow < MAXROW && rStartRow < rEndRow)
+            if (rStartRow < rEndRow)
             {
                 bool bFound = false;
                 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
                 }
             }
 
-            if (rEndRow > 0 && rStartRow < rEndRow)
+            if (rStartRow < rEndRow)
             {
                 bool bFound = false;
                 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
         }
 
         if (bChanged)
-            bRet = true;
+            o_bShrunk = true;
     } while( bChanged );
-    return bRet;
+
+    return rStartCol != rEndCol || (bColumnsOnly ? 
+            !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) :
+            (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow)));
 }
 
 

sc/source/core/data/table2.cxx

 void ScTable::GetFirstDataPos(SCCOL& rCol, SCROW& rRow) const
 {
     rCol = 0;
-    rRow = 0;
+    rRow = MAXROW+1;
     while (aCol[rCol].IsEmptyData() && rCol < MAXCOL)
         ++rCol;
-    rRow = aCol[rCol].GetFirstDataPos();
+    SCCOL nCol = rCol;
+    while (nCol <= MAXCOL && rRow > 0)
+    {
+        if (!aCol[nCol].IsEmptyData())
+            rRow = ::std::min( rRow, aCol[nCol].GetFirstDataPos());
+        ++nCol;
+    }
 }
 
 void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
 {
-	rCol = MAXCOL;
-	rRow = 0;
-	while (aCol[rCol].IsEmptyData() && (rCol > 0))
-		rCol--;
-	SCCOL nCol = rCol;
-	while ((SCsCOL)nCol >= 0)
-	{
-		rRow = Max(rRow, aCol[nCol].GetLastDataPos());
-		nCol--;
-	}
+    rCol = MAXCOL;
+    rRow = 0;
+    while (aCol[rCol].IsEmptyData() && (rCol > 0))
+        rCol--;
+    SCCOL nCol = rCol;
+    while (nCol >= 0 && rRow < MAXROW)
+        rRow = ::std::max( rRow, aCol[nCol--].GetLastDataPos());
 }
 
 

sc/source/ui/docshell/externalrefmgr.cxx

         // Only loop within the data area.
         SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
         SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
-        if (!pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2))
+        bool bShrunk;
+        if (!pSrcDoc->ShrinkToUsedDataArea( bShrunk, nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2, false))
             // no data within specified range.
             continue;
 
 
     SCCOL nDataCol1 = 0, nDataCol2 = MAXCOL;
     SCROW nDataRow1 = 0, nDataRow2 = MAXROW;
-    pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2);
-    if (rCell.Col() < nDataCol1 || nDataCol2 < rCell.Col() || rCell.Row() < nDataRow1 || nDataRow2 < rCell.Row())
+    bool bData = pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2);
+    if (!bData || rCell.Col() < nDataCol1 || nDataCol2 < rCell.Col() || rCell.Row() < nDataRow1 || nDataRow2 < rCell.Row())
     {
         // requested cell is outside the data area.  Don't even bother caching
         // this data, but add it to the cached range to prevent accessing the

sc/source/ui/view/dbfunc.cxx

                     ScDocument* pDoc = pDocSh->GetDocument();
                     SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
                     SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
-                    if (pDoc->ShrinkToUsedDataArea( aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly))
+                    bool bShrunk;
+                    pDoc->ShrinkToUsedDataArea( bShrunk, aRange.aStart.Tab(), 
+                            nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly);
+                    if (bShrunk)
                     {
                         aRange.aStart.SetCol(nCol1);
                         aRange.aEnd.SetCol(nCol2);

sc/source/ui/view/tabvwshe.cxx

                 SCROW nRow1, nRow2;
                 SCTAB nTab1, nTab2;
                 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
-                if (pDoc->ShrinkToUsedDataArea( nTab1, nCol1, nRow1, nCol2, nRow2, false))
+                bool bShrunk;
+                pDoc->ShrinkToUsedDataArea( bShrunk, nTab1, nCol1, nRow1, nCol2, nRow2, false);
+                if (bShrunk)
                 {
                     aRange.aStart.SetCol( nCol1 );
                     aRange.aStart.SetRow( nRow1 );
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.