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: */
