sc/source/core/data/table4.cxx |  269 +++++++++++++++++++++++++++--------------
 1 file changed, 181 insertions(+), 88 deletions(-)

New commits:
commit 42f44a42b625002c8f0e4e832ec457481d89a54c
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue Jul 30 09:25:46 2024 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Jul 31 06:21:49 2024 +0200

    tdf#124341: special-case applying autoformat to whole rows
    
    The problem of allocating thousands of columns can be usually avoided
    when whole rows are selected (e.g., whole sheet). ApplyPatternArea
    (which does the real format application) has a special processing for
    'nEndCol == GetDoc().MaxCol()' case, when it only changes the default
    beyond the already allocated columns. So we can try to pass a single
    range per row (or per row range) where possible, instead of applying
    the format to body without the right column, which would disallow the
    mentioned optimization.
    
    To make that possible, this change detects if whole rows are selected,
    and then it assumes that the user doesn't need the rightmost column
    format of the autoformat. This change also rearranges application of
    format to be by rows rather than by columns where possible. This is
    expected to not slow down the cases that allow by-column application,
    because these cases would either apply to whole body block, or not
    allow by-row application (alternating columnar pattern).
    
    Indeed, this won't help when the autoformat has checkerboard pattern.
    Also, this won't prevent following slow save of the resulting file,
    which would be a separate problem.
    
    Change-Id: Id18a0edb7d6d09fccc3ebb1de3c12eaa45b34501
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171223
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 157b0f01fac7..a400762d1ca2 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -2701,125 +2701,218 @@ void ScTable::AutoFormat( SCCOL nStartCol, SCROW 
nStartRow, SCCOL nEndCol, SCROW
         pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), rDocument);
     }
 
-    SCCOL nCol = nStartCol;
-    SCROW nRow = nStartRow;
-    sal_uInt16 nIndex = 0;
+    // Important special case: when the whole rows are selected. Then applying 
autoformat to right
+    // column individually would create all columns. In this case, assume that 
right column isn't
+    // needed, to allow "to the end of row" format optimization (which doesn't 
create columns).
+    // Keep left column in this case, because it may be pre-formatted for 
categories. To enable the
+    // optimization, apply uniform format row by row where possible, not 
column by column.
+
+    const bool isWholeRows = nStartCol == 0 && nEndCol == rDocument.MaxCol();
+
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+    // Top row data indexes:
+    // 0 - left corner style
+    // 1 - odd columns style
+    // 2 - even column style
+    // 3 - right corner style
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+
+    SCCOL startOffset = 1;
     // Left top corner
-    AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
-    // Left column
-    if (pData->HasSameData(4, 8))
-        AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, 
*pPatternAttrs[4], nFormatNo);
+    if (pData->HasSameData(0, 1) && pData->HasSameData(0, 2))
+        startOffset = 0; // Left corner is same as the rest of the row
+    else
+        AutoFormatArea(nStartCol, nStartRow, nStartCol, nStartRow, 
*pPatternAttrs[0], nFormatNo);
+
+    SCCOL endOffset = 1;
+    // Right top corner: ignore when whole rows selected
+    if (isWholeRows || (pData->HasSameData(3, 1) && pData->HasSameData(3, 2)))
+        endOffset = 0; // Right corner is same as the rest of the row (most 
important case)
+    else
+        AutoFormatArea(nEndCol, nStartRow, nEndCol, nStartRow, 
*pPatternAttrs[3], nFormatNo);
+
+    // Top row
+    if (pData->HasSameData(1, 2))
+        AutoFormatArea(nStartCol + startOffset, nStartRow, nEndCol - 
endOffset, nStartRow, *pPatternAttrs[1], nFormatNo);
     else
     {
-        nIndex = 4;
-        for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+        sal_uInt16 nIndex = 1;
+        for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - 
endOffset; nCol++)
         {
-            AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], 
nFormatNo);
-            if (nIndex == 4)
-                nIndex = 8;
+            AutoFormatArea(nCol, nStartRow, nCol, nStartRow, 
*pPatternAttrs[nIndex], nFormatNo);
+            if (nIndex == 1)
+                nIndex = 2;
             else
-                nIndex = 4;
+                nIndex = 1;
         }
     }
-    // Left bottom corner
-    nRow = nEndRow;
-    nIndex = 12;
-    AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
-    // Right top corner
-    nCol = nEndCol;
-    nRow = nStartRow;
-    nIndex = 3;
-    AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
-    // Right column
-    if (pData->HasSameData(7, 11))
-        AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, 
*pPatternAttrs[7], nFormatNo);
+
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+    // Body data indexes:
+    // 4 - left column odd row style
+    // 8 - left column even row style
+    // 7 - right column odd row style
+    // 11 - right column even row style
+    // 5 - body odd column odd row style
+    // 6 - body even column odd row style
+    // 9 - body odd column even row style
+    // 10 - body even column even row style
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+
+    startOffset = 1;
+    // Left column
+    if (pData->HasSameData(4, 5) && pData->HasSameData(4, 6) && 
pData->HasSameData(8, 9) && pData->HasSameData(8, 10))
+        startOffset = 0; // Left column is same as the lines of the body
     else
     {
-        nIndex = 7;
-        for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+        if (pData->HasSameData(4, 8)) // even and odd rows are same
+            AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, 
*pPatternAttrs[4], nFormatNo);
+        else
         {
-            AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], 
nFormatNo);
-            if (nIndex == 7)
-                nIndex = 11;
-            else
-                nIndex = 7;
+            sal_uInt16 nIndex = 4;
+            for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+            {
+                AutoFormatArea(nStartCol, nRow, nStartCol, nRow, 
*pPatternAttrs[nIndex], nFormatNo);
+                if (nIndex == 4)
+                    nIndex = 8;
+                else
+                    nIndex = 4;
+            }
         }
     }
-    // Right bottom corner
-    nRow = nEndRow;
-    nIndex = 15;
-    AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
-    nRow = nStartRow;
-    nIndex = 1;
-    for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
-    {
-        AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], 
nFormatNo);
-        if (nIndex == 1)
-            nIndex = 2;
-        else
-            nIndex = 1;
-    }
-    // Bottom row
-    nRow = nEndRow;
-    nIndex = 13;
-    for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+
+    endOffset = 1;
+    // Right column: ignore when whole rows selected
+    if (isWholeRows || (pData->HasSameData(7, 5) && pData->HasSameData(7, 6) 
&& pData->HasSameData(11, 9) && pData->HasSameData(11, 10)))
+        endOffset = 0; // Right column is same as the lines of the body (most 
important case)
+    else
     {
-        AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], 
nFormatNo);
-        if (nIndex == 13)
-            nIndex = 14;
+        if (pData->HasSameData(7, 11)) // even and odd rows are same
+            AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, 
*pPatternAttrs[7], nFormatNo);
         else
-            nIndex = 13;
+        {
+            sal_uInt16 nIndex = 7;
+            for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+            {
+                AutoFormatArea(nEndCol, nRow, nEndCol, nRow, 
*pPatternAttrs[nIndex], nFormatNo);
+                if (nIndex == 7)
+                    nIndex = 11;
+                else
+                    nIndex = 7;
+            }
+        }
     }
+
     // Body
-    if ((pData->HasSameData(5, 6)) && (pData->HasSameData(9, 10)) && 
(pData->HasSameData(5, 9)))
-        AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, 
*pPatternAttrs[5], nFormatNo);
-    else
+    if (pData->HasSameData(5, 6) && pData->HasSameData(9, 10)) // Odd and even 
columns are same (most important case)
     {
-        if ((pData->HasSameData(5, 9)) && (pData->HasSameData(6, 10)))
+        if (pData->HasSameData(5, 9)) // Everything is the same
+            AutoFormatArea(nStartCol + startOffset, nStartRow + 1, nEndCol - 
endOffset, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
+        else // Odd and even rows differ
         {
-            nIndex = 5;
-            for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+            if (pProgress)
+                pProgress->SetState(1, nEndRow - nStartRow + 3); // account 
for elements outside the "Body" block
+            sal_uInt16 nIndex = 5;
+            for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
             {
-                AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, 
*pPatternAttrs[nIndex], nFormatNo);
+                AutoFormatArea(nStartCol + startOffset, nRow, nEndCol - 
endOffset, nRow, *pPatternAttrs[nIndex], nFormatNo);
                 if (nIndex == 5)
-                    nIndex = 6;
+                    nIndex = 9;
                 else
                     nIndex = 5;
+                if (pProgress)
+                    pProgress->SetStateOnPercent(nRow - nStartRow + 1);
             }
         }
-        else
+    }
+    else if (pData->HasSameData(5, 9) && pData->HasSameData(6, 10)) // odd and 
even rows are same
+    {
+        if (pProgress)
+            pProgress->SetState(1, nEndCol - nStartCol + 3); // account for 
elements outside the "Body" block
+        sal_uInt16 nIndex = 5;
+        for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - 
endOffset; nCol++)
         {
-            nIndex = 5;
-            for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+            AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, 
*pPatternAttrs[nIndex], nFormatNo);
+            if (nIndex == 5)
+                nIndex = 6;
+            else
+                nIndex = 5;
+            if (pProgress)
+                pProgress->SetStateOnPercent(nCol - nStartCol + 1);
+        }
+    }
+    else // Everything is different
+    {
+        if (pProgress)
+            pProgress->SetState(1, nEndCol - nStartCol + 3); // account for 
elements outside the "Body" block
+        sal_uInt16 nIndex = 5;
+        for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - 
endOffset; nCol++)
+        {
+            for (SCROW nRow = nStartRow + 1; nRow < nEndRow; nRow++)
             {
-                for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+                AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], 
nFormatNo);
+                if ((nIndex == 5) || (nIndex == 9))
                 {
-                    AutoFormatArea(nCol, nRow, nCol, nRow, 
*pPatternAttrs[nIndex], nFormatNo);
-                    if ((nIndex == 5) || (nIndex == 9))
-                    {
-                        if (nIndex == 5)
-                            nIndex = 9;
-                        else
-                            nIndex = 5;
-                    }
+                    if (nIndex == 5)
+                        nIndex = 9;
                     else
-                    {
-                        if (nIndex == 6)
-                            nIndex = 10;
-                        else
-                            nIndex = 6;
-                    }
-                } // for nRow
-                if ((nIndex == 5) || (nIndex == 9))
-                    nIndex = 6;
+                        nIndex = 5;
+                }
                 else
-                    nIndex = 5;
-                if (pProgress)
-                    pProgress->SetStateOnPercent(nCol);
+                {
+                    if (nIndex == 6)
+                        nIndex = 10;
+                    else
+                        nIndex = 6;
+                }
+            } // for nRow
+            if ((nIndex == 5) || (nIndex == 9))
+                nIndex = 6;
+            else
+                nIndex = 5;
+            if (pProgress)
+                pProgress->SetStateOnPercent(nCol - nStartCol + 1);
 
-            } // for nCol
-        } // if not equal Column
+        } // for nCol
     } // if not all equal
+
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+    // Bottom row data indexes:
+    // 12 - left corner style
+    // 13 - odd columns style
+    // 14 - even column style
+    // 15 - right corner style
+    
////////////////////////////////////////////////////////////////////////////////////////////////
+
+    startOffset = 1;
+    // Left bottom corner
+    if (pData->HasSameData(12, 13) && pData->HasSameData(12, 14))
+        startOffset = 0;
+    else
+        AutoFormatArea(nStartCol, nEndRow, nStartCol, nEndRow, 
*pPatternAttrs[12], nFormatNo);
+
+    endOffset = 1;
+    // Right bottom corner: ignore when whole rows selected
+    if (isWholeRows || (pData->HasSameData(15, 13) && pData->HasSameData(15, 
14)))
+        endOffset = 0;
+    else
+        AutoFormatArea(nEndCol, nEndRow, nEndCol, nEndRow, *pPatternAttrs[15], 
nFormatNo);
+
+    // Bottom row
+    if (pData->HasSameData(13, 14))
+        AutoFormatArea(nStartCol + startOffset, nEndRow, nEndCol - endOffset, 
nEndRow, *pPatternAttrs[13], nFormatNo);
+    else
+    {
+        sal_uInt16 nIndex = 13;
+        for (SCCOL nCol = nStartCol + startOffset; nCol <= nEndCol - 
endOffset; nCol++)
+        {
+            AutoFormatArea(nCol, nEndRow, nCol, nEndRow, 
*pPatternAttrs[nIndex], nFormatNo);
+            if (nIndex == 13)
+                nIndex = 14;
+            else
+                nIndex = 13;
+        }
+    }
 }
 
 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, 
ScAutoFormatData& rData)

Reply via email to