sc/Library_sc.mk                                   |    1 
 sc/source/ui/docshell/docfunc.cxx                  |  184 -----------------
 sc/source/ui/inc/operation/FillSimpleOperation.hxx |   40 +++
 sc/source/ui/operation/FillSimpleOperation.cxx     |  218 +++++++++++++++++++++
 4 files changed, 262 insertions(+), 181 deletions(-)

New commits:
commit 08ec6eb69bedf7a6d68216aca89daedb9a88a928
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Fri Mar 6 00:09:09 2026 +0900
Commit:     Miklos Vajna <[email protected]>
CommitDate: Mon Mar 9 14:28:03 2026 +0100

    sc: Introduce FillSimpleOperation, moving the code from ScDocFunc
    
    Pure refactoring only.
    
    Used for FillDown, FillUp, FillLeft, FillRight located in menu
    (Sheet -> FillCells -> ...).
    
    Change-Id: I9a94ccbb128cd8bb8f7e19c91372482679cc2395
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201088
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 199f4bc6070e..8dc762a83e8b 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -536,6 +536,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/ui/operation/DeleteCellOperation \
     sc/source/ui/operation/DeleteContentOperation \
     sc/source/ui/operation/EnterMatrixOperation \
+    sc/source/ui/operation/FillSimpleOperation \
     sc/source/ui/operation/InsertCellsOperation \
     sc/source/ui/operation/InsertSheetViewOperation \
     sc/source/ui/operation/MultipleOpsOperation \
diff --git a/sc/source/ui/docshell/docfunc.cxx 
b/sc/source/ui/docshell/docfunc.cxx
index ec795d883ed8..e1638a30c484 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -122,6 +122,7 @@
 #include <operation/AutoFormatOperation.hxx>
 #include <operation/ClearItemsOperation.hxx>
 #include <operation/EnterMatrixOperation.hxx>
+#include <operation/FillSimpleOperation.hxx>
 #include <operation/InsertCellsOperation.hxx>
 #include <operation/InsertSheetViewOperation.hxx>
 #include <operation/MultipleOpsOperation.hxx>
@@ -3255,190 +3256,11 @@ static ScDirection DirFromFillDir( FillDir eDir )
         return DIR_LEFT;
 }
 
-namespace {
-
-/**
- * Expand the fill range as necessary, to allow copying of adjacent cell(s)
- * even when those cells are not in the original range.
- */
-void adjustFillRangeForAdjacentCopy(const ScDocument &rDoc, ScRange& rRange, 
FillDir eDir)
-{
-    switch (eDir)
-    {
-        case FILL_TO_BOTTOM:
-        {
-            if (rRange.aStart.Row() == 0)
-                return;
-
-            if (rRange.aStart.Row() != rRange.aEnd.Row())
-                return;
-
-            // Include the above row.
-            ScAddress& s = rRange.aStart;
-            s.SetRow(s.Row()-1);
-        }
-        break;
-        case FILL_TO_TOP:
-        {
-            if (rRange.aStart.Row() == rDoc.MaxRow())
-                return;
-
-            if (rRange.aStart.Row() != rRange.aEnd.Row())
-                return;
-
-            // Include the row below.
-            ScAddress& e = rRange.aEnd;
-            e.SetRow(e.Row()+1);
-        }
-        break;
-        case FILL_TO_LEFT:
-        {
-            if (rRange.aStart.Col() == rDoc.MaxCol())
-                return;
-
-            if (rRange.aStart.Col() != rRange.aEnd.Col())
-                return;
-
-            // Include the column to the right.
-            ScAddress& e = rRange.aEnd;
-            e.SetCol(e.Col()+1);
-        }
-        break;
-        case FILL_TO_RIGHT:
-        {
-            if (rRange.aStart.Col() == 0)
-                return;
-
-            if (rRange.aStart.Col() != rRange.aEnd.Col())
-                return;
-
-            // Include the column to the left.
-            ScAddress& s = rRange.aStart;
-            s.SetCol(s.Col()-1);
-        }
-        break;
-        default:
-            ;
-    }
-}
-
-}
-
 bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
                             FillDir eDir, bool bApi )
 {
-    ScDocShellModificator aModificator( rDocShell );
-    ScDocument& rDoc = rDocShell.GetDocument();
-
-    bool bSuccess = false;
-    ScRange aRange = rRange;
-    adjustFillRangeForAdjacentCopy(rDoc, aRange, eDir);
-
-    SCCOL nStartCol = aRange.aStart.Col();
-    SCROW nStartRow = aRange.aStart.Row();
-    SCTAB nStartTab = aRange.aStart.Tab();
-    SCCOL nEndCol = aRange.aEnd.Col();
-    SCROW nEndRow = aRange.aEnd.Row();
-    SCTAB nEndTab = aRange.aEnd.Tab();
-
-    bool bRecord = true;
-    if (!rDoc.IsUndoEnabled())
-        bRecord = false;
-
-    ScMarkData aMark(rDoc.GetSheetLimits());
-    if (pTabMark)
-        aMark = *pTabMark;
-    else
-    {
-        for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
-            aMark.SelectTable( nTab, true );
-    }
-
-    if (!CheckSheetViewProtection(sc::OperationType::FillSimple))
-        return false;
-
-    ScEditableTester aTester = 
ScEditableTester::CreateAndTestSelectedBlock(rDoc, nStartCol, nStartRow, 
nEndCol, nEndRow, aMark);
-    if ( aTester.IsEditable() )
-    {
-        weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
-
-        ScRange aSourceArea = aRange;
-        ScRange aDestArea   = aRange;
-
-        SCCOLROW nCount = 0;
-        switch (eDir)
-        {
-            case FILL_TO_BOTTOM:
-                nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
-                aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() );
-                break;
-            case FILL_TO_RIGHT:
-                nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
-                aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() );
-                break;
-            case FILL_TO_TOP:
-                nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
-                aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() );
-                break;
-            case FILL_TO_LEFT:
-                nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
-                aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() );
-                break;
-        }
-
-        ScDocumentUniquePtr pUndoDoc;
-        if ( bRecord )
-        {
-            SCTAB nTabCount = rDoc.GetTableCount();
-            SCTAB nDestStartTab = aDestArea.aStart.Tab();
-
-            pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
-            pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab );
-            for (const auto& rTab : aMark)
-            {
-                if (rTab >= nTabCount)
-                    break;
-
-                if (rTab != nDestStartTab)
-                    pUndoDoc->AddUndoTab( rTab, rTab );
-            }
-
-            ScRange aCopyRange = aDestArea;
-            aCopyRange.aStart.SetTab(0);
-            aCopyRange.aEnd.SetTab(nTabCount-1);
-            rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::AUTOFILL, 
false, *pUndoDoc, &aMark );
-        }
-
-        sal_uLong nProgCount;
-        if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
-            nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
-        else
-            nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
-        nProgCount *= nCount;
-        ScProgress aProgress( rDoc.GetDocumentShell(),
-                ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
-
-        rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
-                aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
-                aMark, nCount, eDir, FILL_SIMPLE );
-        AdjustRowHeight(aRange, true, bApi);
-
-        if ( bRecord )      // only now is Draw-Undo available
-        {
-            rDocShell.GetUndoManager()->AddUndoAction(
-                std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, 
aSourceArea, std::move(pUndoDoc), aMark,
-                                    eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 
1.0, 1e307) );
-        }
-
-        rDocShell.PostPaintGridAll();
-        aModificator.SetDocumentModified();
-
-        bSuccess = true;
-    }
-    else if (!bApi)
-        rDocShell.ErrorMessage(aTester.GetMessageId());
-
-    return bSuccess;
+    sc::FillSimpleOperation aOperation(*this, rDocShell, rRange, pTabMark, 
eDir, bApi);
+    return aOperation.run();
 }
 
 bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
diff --git a/sc/source/ui/inc/operation/FillSimpleOperation.hxx 
b/sc/source/ui/inc/operation/FillSimpleOperation.hxx
new file mode 100644
index 000000000000..163ecc8ae135
--- /dev/null
+++ b/sc/source/ui/inc/operation/FillSimpleOperation.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "Operation.hxx"
+#include <address.hxx>
+#include <global.hxx>
+
+class ScDocFunc;
+class ScDocShell;
+class ScMarkData;
+
+namespace sc
+{
+/** Operation which fills cells by copying data from an adjacent source row or 
column. */
+class FillSimpleOperation : public Operation
+{
+private:
+    ScDocFunc& mrDocFunc;
+    ScDocShell& mrDocShell;
+    ScRange maRange;
+    ScMarkData const* mpTabMark;
+    FillDir meDir;
+
+    bool runImplementation() override;
+
+public:
+    FillSimpleOperation(ScDocFunc& rDocFunc, ScDocShell& rDocShell, const 
ScRange& rRange,
+                        const ScMarkData* pTabMark, FillDir eDir, bool bApi);
+};
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/operation/FillSimpleOperation.cxx 
b/sc/source/ui/operation/FillSimpleOperation.cxx
new file mode 100644
index 000000000000..0c39ae5010d8
--- /dev/null
+++ b/sc/source/ui/operation/FillSimpleOperation.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <operation/FillSimpleOperation.hxx>
+
+#include <docfunc.hxx>
+#include <docsh.hxx>
+#include <editable.hxx>
+#include <globstr.hrc>
+#include <markdata.hxx>
+#include <progress.hxx>
+#include <scresid.hxx>
+#include <undoblk.hxx>
+
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace
+{
+void adjustFillRangeForAdjacentCopy(const ScDocument& rDoc, ScRange& rRange, 
FillDir eDir)
+{
+    switch (eDir)
+    {
+        case FILL_TO_BOTTOM:
+        {
+            if (rRange.aStart.Row() == 0)
+                return;
+
+            if (rRange.aStart.Row() != rRange.aEnd.Row())
+                return;
+
+            // Include the above row.
+            ScAddress& s = rRange.aStart;
+            s.SetRow(s.Row() - 1);
+        }
+        break;
+        case FILL_TO_TOP:
+        {
+            if (rRange.aStart.Row() == rDoc.MaxRow())
+                return;
+
+            if (rRange.aStart.Row() != rRange.aEnd.Row())
+                return;
+
+            // Include the row below.
+            ScAddress& e = rRange.aEnd;
+            e.SetRow(e.Row() + 1);
+        }
+        break;
+        case FILL_TO_LEFT:
+        {
+            if (rRange.aStart.Col() == rDoc.MaxCol())
+                return;
+
+            if (rRange.aStart.Col() != rRange.aEnd.Col())
+                return;
+
+            // Include the column to the right.
+            ScAddress& e = rRange.aEnd;
+            e.SetCol(e.Col() + 1);
+        }
+        break;
+        case FILL_TO_RIGHT:
+        {
+            if (rRange.aStart.Col() == 0)
+                return;
+
+            if (rRange.aStart.Col() != rRange.aEnd.Col())
+                return;
+
+            // Include the column to the left.
+            ScAddress& s = rRange.aStart;
+            s.SetCol(s.Col() - 1);
+        }
+        break;
+        default:;
+    }
+}
+}
+
+namespace sc
+{
+FillSimpleOperation::FillSimpleOperation(ScDocFunc& rDocFunc, ScDocShell& 
rDocShell,
+                                         const ScRange& rRange, const 
ScMarkData* pTabMark,
+                                         FillDir eDir, bool bApi)
+    : Operation(OperationType::FillSimple, true, bApi)
+    , mrDocFunc(rDocFunc)
+    , mrDocShell(rDocShell)
+    , maRange(rRange)
+    , mpTabMark(pTabMark)
+    , meDir(eDir)
+{
+}
+
+bool FillSimpleOperation::runImplementation()
+{
+    ScDocShellModificator aModificator(mrDocShell);
+    ScDocument& rDoc = mrDocShell.GetDocument();
+
+    bool bSuccess = false;
+    ScRange aRange = maRange;
+    adjustFillRangeForAdjacentCopy(rDoc, aRange, meDir);
+
+    SCCOL nStartCol = aRange.aStart.Col();
+    SCROW nStartRow = aRange.aStart.Row();
+    SCTAB nStartTab = aRange.aStart.Tab();
+    SCCOL nEndCol = aRange.aEnd.Col();
+    SCROW nEndRow = aRange.aEnd.Row();
+    SCTAB nEndTab = aRange.aEnd.Tab();
+
+    if (mbRecord && !rDoc.IsUndoEnabled())
+        mbRecord = false;
+
+    ScMarkData aMark(rDoc.GetSheetLimits());
+    if (mpTabMark)
+        aMark = *mpTabMark;
+    else
+    {
+        for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++)
+            aMark.SelectTable(nTab, true);
+    }
+
+    if (!checkSheetViewProtection())
+        return false;
+
+    ScEditableTester aTester = ScEditableTester::CreateAndTestSelectedBlock(
+        rDoc, nStartCol, nStartRow, nEndCol, nEndRow, aMark);
+    if (aTester.IsEditable())
+    {
+        weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
+
+        ScRange aSourceArea = aRange;
+        ScRange aDestArea = aRange;
+
+        SCCOLROW nCount = 0;
+        switch (meDir)
+        {
+            case FILL_TO_BOTTOM:
+                nCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row();
+                aSourceArea.aEnd.SetRow(aSourceArea.aStart.Row());
+                break;
+            case FILL_TO_RIGHT:
+                nCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col();
+                aSourceArea.aEnd.SetCol(aSourceArea.aStart.Col());
+                break;
+            case FILL_TO_TOP:
+                nCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row();
+                aSourceArea.aStart.SetRow(aSourceArea.aEnd.Row());
+                break;
+            case FILL_TO_LEFT:
+                nCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col();
+                aSourceArea.aStart.SetCol(aSourceArea.aEnd.Col());
+                break;
+        }
+
+        ScDocumentUniquePtr pUndoDoc;
+        if (mbRecord)
+        {
+            SCTAB nTabCount = rDoc.GetTableCount();
+            SCTAB nDestStartTab = aDestArea.aStart.Tab();
+
+            pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+            pUndoDoc->InitUndo(rDoc, nDestStartTab, nDestStartTab);
+            for (const auto& rTab : aMark)
+            {
+                if (rTab >= nTabCount)
+                    break;
+
+                if (rTab != nDestStartTab)
+                    pUndoDoc->AddUndoTab(rTab, rTab);
+            }
+
+            ScRange aCopyRange = aDestArea;
+            aCopyRange.aStart.SetTab(0);
+            aCopyRange.aEnd.SetTab(nTabCount - 1);
+            rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::AUTOFILL, 
false, *pUndoDoc, &aMark);
+        }
+
+        sal_uLong nProgCount;
+        if (meDir == FILL_TO_BOTTOM || meDir == FILL_TO_TOP)
+            nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
+        else
+            nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
+        nProgCount *= nCount;
+        ScProgress aProgress(rDoc.GetDocumentShell(), 
ScResId(STR_FILL_SERIES_PROGRESS), nProgCount,
+                             true);
+
+        rDoc.Fill(aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), 
aSourceArea.aEnd.Col(),
+                  aSourceArea.aEnd.Row(), &aProgress, aMark, nCount, meDir, 
FILL_SIMPLE);
+        mrDocFunc.AdjustRowHeight(aRange, true, mbApi);
+
+        if (mbRecord) // only now is Draw-Undo available
+        {
+            
mrDocShell.GetUndoManager()->AddUndoAction(std::make_unique<ScUndoAutoFill>(
+                &mrDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), 
aMark, meDir, FILL_SIMPLE,
+                FILL_DAY, MAXDOUBLE, 1.0, 1e307));
+        }
+
+        mrDocShell.PostPaintGridAll();
+        aModificator.SetDocumentModified();
+
+        bSuccess = true;
+    }
+    else if (!mbApi)
+        mrDocShell.ErrorMessage(aTester.GetMessageId());
+
+    return bSuccess;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to