sc/source/ui/inc/operation/ApplyAttributesOperation.hxx |   38 ++++
 sc/source/ui/operation/ApplyAttributesOperation.cxx     |  152 ++++++++++++++++
 sc/source/ui/view/viewfunc.cxx                          |  123 ++----------
 3 files changed, 210 insertions(+), 103 deletions(-)

New commits:
commit 5e3fb42c870335ca9a7aff733f916ffb1819396a
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Thu Feb 12 18:51:02 2026 +0900
Commit:     Miklos Vajna <[email protected]>
CommitDate: Mon Feb 16 15:28:56 2026 +0100

    sc: Create operations to apply attributes that are in ScViewFunc
    
    When changing the attributes for a cell or cell range, there is
    no direct operation in ScDocFunc or similar, but the change is
    performed in ScViewFunc. This refactores the calles and creates
    operations that don't depend much on the view (can't really
    completely get rid of it yet), so we can use those to implement
    sync in a follow-up commit.
    
    Change-Id: I02d5370201f441a09560e49999bd265cfa184d30
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199288
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/sc/source/ui/inc/operation/ApplyAttributesOperation.hxx 
b/sc/source/ui/inc/operation/ApplyAttributesOperation.hxx
index 7fbc88c84dff..fccbe59707b1 100644
--- a/sc/source/ui/inc/operation/ApplyAttributesOperation.hxx
+++ b/sc/source/ui/inc/operation/ApplyAttributesOperation.hxx
@@ -37,6 +37,44 @@ public:
                              const ScPatternAttr& rPattern, bool bApi);
 };
 
+/** Operation which applies input attributes to marked cells or range and 
remembers changed ranges. */
+class ApplyAttributesWithChangedRangeOperation : public Operation
+{
+private:
+    ScDocShell& mrDocShell;
+    ScMarkData const& mrMark;
+    ScPatternAttr const& mrPattern;
+    bool mbMultiMarked = false;
+    sal_uInt16 mnExtFlags;
+    ScRangeList maChangeRanges;
+
+    bool runImplementation() override;
+
+public:
+    ApplyAttributesWithChangedRangeOperation(ScDocShell& rDocShell, const 
ScMarkData& rMark,
+                                             bool bMultiMarked, const 
ScPatternAttr& rPattern,
+                                             sal_uInt16 nExtFlags, bool bApi);
+    ScRangeList const& getChangedRangeList() { return maChangeRanges; }
+};
+
+/** Operation which applies input attributes to content to a cell. */
+class ApplyAttributesToCellOperation : public Operation
+{
+private:
+    ScDocShell& mrDocShell;
+    ScAddress const& mrPosition;
+    ScPatternAttr const& mrPattern;
+    sal_uInt16 mnExtFlags;
+    ScRangeList maChangeRanges;
+
+    bool runImplementation() override;
+
+public:
+    ApplyAttributesToCellOperation(ScDocShell& rDocShell, ScAddress const& 
rPosition,
+                                   const ScPatternAttr& rPattern, sal_uInt16 
nExtFlags, bool bApi);
+    ScRangeList const& getChangedRangeList() { return maChangeRanges; }
+};
+
 } // end sc namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/operation/ApplyAttributesOperation.cxx 
b/sc/source/ui/operation/ApplyAttributesOperation.cxx
index 6c7a85ca33b3..7887cdbe11c2 100644
--- a/sc/source/ui/operation/ApplyAttributesOperation.cxx
+++ b/sc/source/ui/operation/ApplyAttributesOperation.cxx
@@ -14,8 +14,11 @@
 #include <address.hxx>
 #include <editable.hxx>
 #include <undoblk.hxx>
+#include <undocell.hxx>
 #include <validat.hxx>
 #include <globstr.hrc>
+#include <cellvalue.hxx>
+#include <editeng/editobj.hxx>
 
 #include <memory>
 
@@ -100,6 +103,155 @@ bool ApplyAttributesOperation::runImplementation()
 
     return true;
 }
+
+ApplyAttributesWithChangedRangeOperation::ApplyAttributesWithChangedRangeOperation(
+    ScDocShell& rDocShell, const ScMarkData& rMark, bool bMultiMarked,
+    const ScPatternAttr& rPattern, sal_uInt16 nExtFlags, bool bApi)
+    : Operation(OperationType::ApplyAttributes, true, bApi)
+    , mrDocShell(rDocShell)
+    , mrMark(rMark)
+    , mrPattern(rPattern)
+    , mbMultiMarked(bMultiMarked)
+    , mnExtFlags(nExtFlags)
+{
+}
+
+bool ApplyAttributesWithChangedRangeOperation::runImplementation()
+{
+    ScDocument& rDoc = mrDocShell.GetDocument();
+
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    if (!pViewData)
+        return false;
+
+    bool bRecord = mbRecord;
+    if (!rDoc.IsUndoEnabled())
+        bRecord = false;
+
+    ScMarkData aMark = mrMark;
+
+    ScDocShellModificator aModificator(mrDocShell);
+
+    const ScRange& aMarkRange = aMark.GetMultiMarkArea();
+    SCTAB nTabCount = rDoc.GetTableCount();
+    for (const auto& rTab : aMark)
+    {
+        ScRange aChangeRange(aMarkRange);
+        aChangeRange.aStart.SetTab(rTab);
+        aChangeRange.aEnd.SetTab(rTab);
+        maChangeRanges.push_back(aChangeRange);
+    }
+
+    SCCOL nStartCol = aMarkRange.aStart.Col();
+    SCROW nStartRow = aMarkRange.aStart.Row();
+    SCTAB nStartTab = aMarkRange.aStart.Tab();
+    SCCOL nEndCol = aMarkRange.aEnd.Col();
+    SCROW nEndRow = aMarkRange.aEnd.Row();
+    SCTAB nEndTab = aMarkRange.aEnd.Tab();
+
+    ScEditDataArray* pEditDataArray = nullptr;
+    if (bRecord)
+    {
+        ScRange aCopyRange = aMarkRange;
+        aCopyRange.aStart.SetTab(0);
+        aCopyRange.aEnd.SetTab(nTabCount - 1);
+
+        ScDocumentUniquePtr pUndoDoc(new ScDocument(SCDOCMODE_UNDO));
+        pUndoDoc->InitUndo(rDoc, nStartTab, nStartTab);
+        for (const auto& rTab : aMark)
+            if (rTab != nStartTab)
+                pUndoDoc->AddUndoTab(rTab, rTab);
+        rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, 
mbMultiMarked, *pUndoDoc,
+                            &aMark);
+
+        aMark.MarkToMulti();
+
+        ScUndoSelectionAttr* pUndoAttr = new ScUndoSelectionAttr(
+            &mrDocShell, aMark, nStartCol, nStartRow, nStartTab, nEndCol, 
nEndRow, nEndTab,
+            std::move(pUndoDoc), mbMultiMarked, &mrPattern);
+        
mrDocShell.GetUndoManager()->AddUndoAction(std::unique_ptr<ScUndoSelectionAttr>(pUndoAttr));
+        pEditDataArray = pUndoAttr->GetDataArray();
+    }
+
+    rDoc.ApplySelectionPattern(mrPattern, aMark, pEditDataArray);
+
+    mrDocShell.PostPaint(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, 
nEndTab,
+                         PaintPartFlags::Grid, mnExtFlags | SC_PF_TESTMERGE);
+    mrDocShell.UpdateOle(*pViewData);
+
+    aModificator.SetDocumentModified();
+
+    return true;
+}
+
+ApplyAttributesToCellOperation::ApplyAttributesToCellOperation(ScDocShell& 
rDocShell,
+                                                               ScAddress 
const& rPosition,
+                                                               const 
ScPatternAttr& rPattern,
+                                                               sal_uInt16 
nExtFlags, bool bApi)
+    : Operation(OperationType::ApplyAttributes, true, bApi)
+    , mrDocShell(rDocShell)
+    , mrPosition(rPosition)
+    , mrPattern(rPattern)
+    , mnExtFlags(nExtFlags)
+{
+}
+bool ApplyAttributesToCellOperation::runImplementation()
+{
+    ScDocument& rDoc = mrDocShell.GetDocument();
+
+    ScViewData* pViewData = ScDocShell::GetViewData();
+    if (!pViewData)
+        return false;
+
+    bool bRecord = mbRecord;
+    if (!rDoc.IsUndoEnabled())
+        bRecord = false;
+
+    ScAddress aPosition = mrPosition;
+
+    ScDocShellModificator aModificator(mrDocShell);
+
+    SCCOL nCol = aPosition.Col();
+    SCROW nRow = aPosition.Row();
+    SCTAB nTab = aPosition.Tab();
+
+    std::unique_ptr<EditTextObject> pOldEditData;
+    std::unique_ptr<EditTextObject> pNewEditData;
+
+    ScRefCellValue aCell(rDoc, aPosition);
+    if (aCell.getType() == CELLTYPE_EDIT)
+    {
+        const EditTextObject* pEditObj = aCell.getEditText();
+        pOldEditData = pEditObj->Clone();
+        rDoc.RemoveEditTextCharAttribs(aPosition, mrPattern);
+        pEditObj = rDoc.GetEditText(aPosition);
+        pNewEditData = pEditObj->Clone();
+    }
+
+    maChangeRanges.push_back(ScRange(aPosition));
+    std::optional<ScPatternAttr> pOldPat(*rDoc.GetPattern(nCol, nRow, nTab));
+
+    rDoc.ApplyPattern(nCol, nRow, nTab, mrPattern);
+
+    const ScPatternAttr* pNewPat = rDoc.GetPattern(nCol, nRow, nTab);
+
+    if (bRecord)
+    {
+        std::unique_ptr<ScUndoCursorAttr> pUndo(
+            new ScUndoCursorAttr(&mrDocShell, nCol, nRow, nTab, &*pOldPat, 
pNewPat, &mrPattern));
+        pUndo->SetEditData(std::move(pOldEditData), std::move(pNewEditData));
+        mrDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+    }
+    pOldPat.reset(); // is copied in undo (Pool)
+
+    mrDocShell.PostPaint(nCol, nRow, nTab, nCol, nRow, nTab, 
PaintPartFlags::Grid,
+                         mnExtFlags | SC_PF_TESTMERGE);
+    mrDocShell.UpdateOle(*pViewData);
+    aModificator.SetDocumentModified();
+
+    return true;
+}
+
 } // end sc namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index b1e0f5fc5114..7a11c3baf99c 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -79,6 +79,7 @@
 #include <SparklineList.hxx>
 #include <SheetViewManager.hxx>
 #include <SheetViewOperationsTester.hxx>
+#include <operation/ApplyAttributesOperation.hxx>
 
 #include <memory>
 
@@ -1400,9 +1401,15 @@ void ScViewFunc::ApplySelectionPattern( const 
ScPatternAttr& rAttr, bool bCursor
     ScMarkData aFuncMark( rViewData.GetMarkData() );       // local copy for 
UnmarkFiltered
     ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
 
-    bool bRecord = true;
-    if (!rDoc.IsUndoEnabled())
-        bRecord = false;
+    bool bMultiMarked = aFuncMark.IsMultiMarked();
+    aFuncMark.MarkToMulti();
+    ScAddress aPosition(rViewData.GetCurX(), rViewData.GetCurY(), 
rViewData.CurrentTabForData());
+    bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && 
aFuncMark.GetSelectCount() > 1);
+    if (bOnlyTab)
+    {
+        aFuncMark.SetMarkArea(ScRange(aPosition));
+        aFuncMark.MarkToMulti();
+    }
 
     //  State from old ItemSet doesn't matter for paint flags, as any change 
will be
     //  from SfxItemState::SET in the new ItemSet (default is ignored in 
ApplyPattern).
@@ -1419,113 +1426,23 @@ void ScViewFunc::ApplySelectionPattern( const 
ScPatternAttr& rAttr, bool bCursor
     if ( bSetAlign )
         nExtFlags |= SC_PF_WHOLEROWS;
 
-    ScDocShellModificator aModificator( *pDocSh );
-
-    bool bMulti = aFuncMark.IsMultiMarked();
-    aFuncMark.MarkToMulti();
-    bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && 
aFuncMark.GetSelectCount() > 1);
-    if (bOnlyTab)
-    {
-        SCCOL nCol = rViewData.GetCurX();
-        SCROW nRow = rViewData.GetCurY();
-        SCTAB nTab = rViewData.CurrentTabForData();
-        aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
-        aFuncMark.MarkToMulti();
-    }
-
     ScRangeList aChangeRanges;
-
+    bool bResult = false;
     if (aFuncMark.IsMultiMarked() && !bCursorOnly)
     {
-        const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
-        SCTAB nTabCount = rDoc.GetTableCount();
-        for (const auto& rTab : aFuncMark)
-        {
-            ScRange aChangeRange( aMarkRange );
-            aChangeRange.aStart.SetTab( rTab );
-            aChangeRange.aEnd.SetTab( rTab );
-            aChangeRanges.push_back( aChangeRange );
-        }
-
-        SCCOL nStartCol = aMarkRange.aStart.Col();
-        SCROW nStartRow = aMarkRange.aStart.Row();
-        SCTAB nStartTab = aMarkRange.aStart.Tab();
-        SCCOL nEndCol = aMarkRange.aEnd.Col();
-        SCROW nEndRow = aMarkRange.aEnd.Row();
-        SCTAB nEndTab = aMarkRange.aEnd.Tab();
-
-        ScEditDataArray* pEditDataArray = nullptr;
-        if (bRecord)
-        {
-            ScRange aCopyRange = aMarkRange;
-            aCopyRange.aStart.SetTab(0);
-            aCopyRange.aEnd.SetTab(nTabCount-1);
-
-            ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
-            pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
-            for (const auto& rTab : aFuncMark)
-                if (rTab != nStartTab)
-                    pUndoDoc->AddUndoTab( rTab, rTab );
-            rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, 
bMulti, *pUndoDoc, &aFuncMark );
-
-            aFuncMark.MarkToMulti();
-
-            ScUndoSelectionAttr* pUndoAttr = new ScUndoSelectionAttr(
-                pDocSh, aFuncMark, nStartCol, nStartRow, nStartTab,
-                nEndCol, nEndRow, nEndTab, std::move(pUndoDoc), bMulti, &rAttr 
);
-            
pDocSh->GetUndoManager()->AddUndoAction(std::unique_ptr<ScUndoSelectionAttr>(pUndoAttr));
-            pEditDataArray = pUndoAttr->GetDataArray();
-        }
-
-        rDoc.ApplySelectionPattern( rAttr, aFuncMark, pEditDataArray );
-
-        pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
-                           nEndCol,   nEndRow,   nEndTab,
-                           PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
-        pDocSh->UpdateOle(GetViewData());
-        aModificator.SetDocumentModified();
-        CellContentChanged();
+        sc::ApplyAttributesWithChangedRangeOperation aOperation(*pDocSh, 
aFuncMark, bMultiMarked, rAttr, nExtFlags, false);
+        bResult = aOperation.run();
+        aChangeRanges = aOperation.getChangedRangeList();
     }
-    else                            // single cell - simpler undo
+    else
     {
-        SCCOL nCol = rViewData.GetCurX();
-        SCROW nRow = rViewData.GetCurY();
-        SCTAB nTab = rViewData.CurrentTabForData();
-
-        std::unique_ptr<EditTextObject> pOldEditData;
-        std::unique_ptr<EditTextObject> pNewEditData;
-        ScAddress aPos(nCol, nRow, nTab);
-        ScRefCellValue aCell(rDoc, aPos);
-        if (aCell.getType() == CELLTYPE_EDIT)
-        {
-            const EditTextObject* pEditObj = aCell.getEditText();
-            pOldEditData = pEditObj->Clone();
-            rDoc.RemoveEditTextCharAttribs(aPos, rAttr);
-            pEditObj = rDoc.GetEditText(aPos);
-            pNewEditData = pEditObj->Clone();
-        }
-
-        aChangeRanges.push_back(ScRange(aPos));
-        std::optional<ScPatternAttr> pOldPat(*rDoc.GetPattern( nCol, nRow, 
nTab ));
-
-        rDoc.ApplyPattern( nCol, nRow, nTab, rAttr );
-
-        const ScPatternAttr* pNewPat = rDoc.GetPattern( nCol, nRow, nTab );
-
-        if (bRecord)
-        {
-            std::unique_ptr<ScUndoCursorAttr> pUndo(new ScUndoCursorAttr(
-                pDocSh, nCol, nRow, nTab, &*pOldPat, pNewPat, &rAttr ));
-            pUndo->SetEditData(std::move(pOldEditData), 
std::move(pNewEditData));
-            pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndo));
-        }
-        pOldPat.reset();     // is copied in undo (Pool)
+        sc::ApplyAttributesToCellOperation aOperation(*pDocSh, aPosition, 
rAttr, nExtFlags, false);
+        bResult = aOperation.run();
+        aChangeRanges = aOperation.getChangedRangeList();
+    }
 
-        pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, 
PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
-        pDocSh->UpdateOle(GetViewData());
-        aModificator.SetDocumentModified();
+    if (bResult)
         CellContentChanged();
-    }
 
     ScModelObj* pModelObj = pDocSh->GetModel();
 

Reply via email to