Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/operation/FillSimpleOperation.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include <operation/FillSimpleOperation.hxx>
11
12
#include <docfunc.hxx>
13
#include <docsh.hxx>
14
#include <editable.hxx>
15
#include <globstr.hrc>
16
#include <markdata.hxx>
17
#include <progress.hxx>
18
#include <scresid.hxx>
19
#include <undoblk.hxx>
20
21
#include <vcl/weld/WaitObject.hxx>
22
#include <vcl/weld/Window.hxx>
23
24
#include <memory>
25
26
namespace
27
{
28
void adjustFillRangeForAdjacentCopy(const ScDocument& rDoc, ScRange& rRange, FillDir eDir)
29
0
{
30
0
    switch (eDir)
31
0
    {
32
0
        case FILL_TO_BOTTOM:
33
0
        {
34
0
            if (rRange.aStart.Row() == 0)
35
0
                return;
36
37
0
            if (rRange.aStart.Row() != rRange.aEnd.Row())
38
0
                return;
39
40
            // Include the above row.
41
0
            ScAddress& s = rRange.aStart;
42
0
            s.SetRow(s.Row() - 1);
43
0
        }
44
0
        break;
45
0
        case FILL_TO_TOP:
46
0
        {
47
0
            if (rRange.aStart.Row() == rDoc.MaxRow())
48
0
                return;
49
50
0
            if (rRange.aStart.Row() != rRange.aEnd.Row())
51
0
                return;
52
53
            // Include the row below.
54
0
            ScAddress& e = rRange.aEnd;
55
0
            e.SetRow(e.Row() + 1);
56
0
        }
57
0
        break;
58
0
        case FILL_TO_LEFT:
59
0
        {
60
0
            if (rRange.aStart.Col() == rDoc.MaxCol())
61
0
                return;
62
63
0
            if (rRange.aStart.Col() != rRange.aEnd.Col())
64
0
                return;
65
66
            // Include the column to the right.
67
0
            ScAddress& e = rRange.aEnd;
68
0
            e.SetCol(e.Col() + 1);
69
0
        }
70
0
        break;
71
0
        case FILL_TO_RIGHT:
72
0
        {
73
0
            if (rRange.aStart.Col() == 0)
74
0
                return;
75
76
0
            if (rRange.aStart.Col() != rRange.aEnd.Col())
77
0
                return;
78
79
            // Include the column to the left.
80
0
            ScAddress& s = rRange.aStart;
81
0
            s.SetCol(s.Col() - 1);
82
0
        }
83
0
        break;
84
0
        default:;
85
0
    }
86
0
}
87
}
88
89
namespace sc
90
{
91
FillSimpleOperation::FillSimpleOperation(ScDocFunc& rDocFunc, ScDocShell& rDocShell,
92
                                         const ScRange& rRange, const ScMarkData* pTabMark,
93
                                         FillDir eDir, bool bApi)
94
0
    : Operation(OperationType::FillSimple, true, bApi)
95
0
    , mrDocFunc(rDocFunc)
96
0
    , mrDocShell(rDocShell)
97
0
    , maRange(rRange)
98
0
    , mpTabMark(pTabMark)
99
0
    , meDir(eDir)
100
0
{
101
0
}
102
103
bool FillSimpleOperation::canRunTheOperation() const
104
0
{
105
0
    return !isInputOnSheetViewAutoFilter(maRange);
106
0
}
107
108
bool FillSimpleOperation::runImplementation()
109
0
{
110
0
    ScDocShellModificator aModificator(mrDocShell);
111
0
    ScDocument& rDoc = mrDocShell.GetDocument();
112
113
0
    bool bSuccess = false;
114
0
    ScRange aRange = convertRange(maRange);
115
0
    adjustFillRangeForAdjacentCopy(rDoc, aRange, meDir);
116
117
0
    SCCOL nStartCol = aRange.aStart.Col();
118
0
    SCROW nStartRow = aRange.aStart.Row();
119
0
    SCTAB nStartTab = aRange.aStart.Tab();
120
0
    SCCOL nEndCol = aRange.aEnd.Col();
121
0
    SCROW nEndRow = aRange.aEnd.Row();
122
0
    SCTAB nEndTab = aRange.aEnd.Tab();
123
124
0
    if (mbRecord && !rDoc.IsUndoEnabled())
125
0
        mbRecord = false;
126
127
0
    ScMarkData aMark(rDoc.GetSheetLimits());
128
0
    if (mpTabMark)
129
0
        aMark = *mpTabMark;
130
0
    else
131
0
    {
132
0
        for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++)
133
0
            aMark.SelectTable(nTab, true);
134
0
    }
135
136
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestSelectedBlock(
137
0
        rDoc, nStartCol, nStartRow, nEndCol, nEndRow, aMark);
138
0
    if (aTester.IsEditable())
139
0
    {
140
0
        weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
141
142
0
        ScRange aSourceArea = aRange;
143
0
        ScRange aDestArea = aRange;
144
145
0
        SCCOLROW nCount = 0;
146
0
        switch (meDir)
147
0
        {
148
0
            case FILL_TO_BOTTOM:
149
0
                nCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row();
150
0
                aSourceArea.aEnd.SetRow(aSourceArea.aStart.Row());
151
0
                break;
152
0
            case FILL_TO_RIGHT:
153
0
                nCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col();
154
0
                aSourceArea.aEnd.SetCol(aSourceArea.aStart.Col());
155
0
                break;
156
0
            case FILL_TO_TOP:
157
0
                nCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row();
158
0
                aSourceArea.aStart.SetRow(aSourceArea.aEnd.Row());
159
0
                break;
160
0
            case FILL_TO_LEFT:
161
0
                nCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col();
162
0
                aSourceArea.aStart.SetCol(aSourceArea.aEnd.Col());
163
0
                break;
164
0
        }
165
166
0
        ScDocumentUniquePtr pUndoDoc;
167
0
        if (mbRecord)
168
0
        {
169
0
            SCTAB nTabCount = rDoc.GetTableCount();
170
0
            SCTAB nDestStartTab = aDestArea.aStart.Tab();
171
172
0
            pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
173
0
            pUndoDoc->InitUndo(rDoc, nDestStartTab, nDestStartTab);
174
0
            for (const auto& rTab : aMark)
175
0
            {
176
0
                if (rTab >= nTabCount)
177
0
                    break;
178
179
0
                if (rTab != nDestStartTab)
180
0
                    pUndoDoc->AddUndoTab(rTab, rTab);
181
0
            }
182
183
0
            ScRange aCopyRange = aDestArea;
184
0
            aCopyRange.aStart.SetTab(0);
185
0
            aCopyRange.aEnd.SetTab(nTabCount - 1);
186
0
            rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark);
187
0
        }
188
189
0
        sal_uLong nProgCount;
190
0
        if (meDir == FILL_TO_BOTTOM || meDir == FILL_TO_TOP)
191
0
            nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
192
0
        else
193
0
            nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
194
0
        nProgCount *= nCount;
195
0
        ScProgress aProgress(rDoc.GetDocumentShell(), ScResId(STR_FILL_SERIES_PROGRESS), nProgCount,
196
0
                             true);
197
198
0
        rDoc.Fill(aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(),
199
0
                  aSourceArea.aEnd.Row(), &aProgress, aMark, nCount, meDir, FILL_SIMPLE);
200
0
        mrDocFunc.AdjustRowHeight(aRange, true, mbApi);
201
202
0
        if (mbRecord) // only now is Draw-Undo available
203
0
        {
204
0
            mrDocShell.GetUndoManager()->AddUndoAction(std::make_unique<ScUndoAutoFill>(
205
0
                mrDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark, meDir, FILL_SIMPLE,
206
0
                FILL_DAY, MAXDOUBLE, 1.0, 1e307));
207
0
        }
208
209
0
        syncSheetViews();
210
211
0
        mrDocShell.PostPaintGridAll();
212
0
        aModificator.SetDocumentModified();
213
214
0
        bSuccess = true;
215
0
    }
216
0
    else if (!mbApi)
217
0
        mrDocShell.ErrorMessage(aTester.GetMessageId());
218
219
0
    return bSuccess;
220
0
}
221
}
222
223
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */