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/view/viewfun2.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
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <scitems.hxx>
21
22
#include <algorithm>
23
24
#include <sfx2/app.hxx>
25
#include <sfx2/request.hxx>
26
#include <editeng/borderline.hxx>
27
#include <editeng/boxitem.hxx>
28
#include <editeng/fontitem.hxx>
29
#include <editeng/lineitem.hxx>
30
#include <editeng/scriptsetitem.hxx>
31
#include <svl/srchitem.hxx>
32
#include <sfx2/linkmgr.hxx>
33
#include <sfx2/dispatch.hxx>
34
#include <sfx2/docfilt.hxx>
35
#include <sfx2/docfile.hxx>
36
#include <sfx2/objitem.hxx>
37
#include <sfx2/viewfrm.hxx>
38
#include <svl/numformat.hxx>
39
#include <svl/stritem.hxx>
40
#include <svl/zforlist.hxx>
41
#include <svx/srchdlg.hxx>
42
#include <svx/svdview.hxx>
43
#include <vcl/svapp.hxx>
44
#include <vcl/weld/MessageDialog.hxx>
45
#include <vcl/weld/WaitObject.hxx>
46
#include <osl/diagnose.h>
47
48
#include <viewfunc.hxx>
49
#include <vcl/uitest/logger.hxx>
50
#include <vcl/uitest/eventdescription.hxx>
51
52
#include <sc.hrc>
53
#include <globstr.hrc>
54
#include <scresid.hxx>
55
56
#include <attrib.hxx>
57
#include <autoform.hxx>
58
#include <formulacell.hxx>
59
#include <cellmergeoption.hxx>
60
#include <compiler.hxx>
61
#include <docfunc.hxx>
62
#include <docpool.hxx>
63
#include <docsh.hxx>
64
#include <global.hxx>
65
#include <patattr.hxx>
66
#include <printfun.hxx>
67
#include <refundo.hxx>
68
#include <table.hxx>
69
#include <tablink.hxx>
70
#include <tabvwsh.hxx>
71
#include <uiitems.hxx>
72
#include <undoblk.hxx>
73
#include <undotab.hxx>
74
#include <sizedev.hxx>
75
#include <editable.hxx>
76
#include <docuno.hxx>
77
#include <charthelper.hxx>
78
#include <tabbgcolor.hxx>
79
#include <clipparam.hxx>
80
#include <prnsave.hxx>
81
#include <searchresults.hxx>
82
#include <tokenarray.hxx>
83
#include <rowheightcontext.hxx>
84
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
85
#include <comphelper/lok.hxx>
86
#include <mergecellsdialog.hxx>
87
#include <sheetevents.hxx>
88
#include <columnspanset.hxx>
89
#include <SheetViewManager.hxx>
90
91
#include <vector>
92
#include <memory>
93
#include <boost/property_tree/json_parser.hpp>
94
#include <tools/json_writer.hxx>
95
96
#include <officecfg/Office/Calc.hxx>
97
#include <sfx2/lokhelper.hxx>
98
99
using namespace com::sun::star;
100
using ::editeng::SvxBorderLine;
101
102
namespace {
103
104
void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
105
0
{
106
0
    EventDescription aDescription;
107
0
    aDescription.aID = "grid_window";
108
0
    aDescription.aAction = rAction;
109
0
    aDescription.aParameters = std::move(aParameters);
110
0
    aDescription.aParent = "MainWindow";
111
0
    aDescription.aKeyWord = "ScGridWinUIObject";
112
113
0
    UITestLogger::getInstance().logEvent(aDescription);
114
0
}
115
}
116
117
bool ScViewFunc::AdjustBlockHeight( bool bPaint, ScMarkData* pMarkData, bool bRangeWidthChanged )
118
0
{
119
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
120
0
    if (!pMarkData)
121
0
        pMarkData = &GetViewData().GetMarkData();
122
123
0
    ScDocument& rDoc = pDocSh->GetDocument();
124
0
    std::vector<sc::ColRowSpan> aMarkedRows = pMarkData->GetMarkedRowSpans();
125
126
0
    if (aMarkedRows.empty())
127
0
    {
128
0
        SCROW nCurRow = GetViewData().GetCurY();
129
0
        aMarkedRows.emplace_back(nCurRow, nCurRow);
130
0
    }
131
132
0
    if (comphelper::LibreOfficeKit::isActive())
133
0
    {
134
0
        SCCOLROW nStart = aMarkedRows[0].mnStart;
135
0
        OnLOKSetWidthOrHeight(nStart, /*width: */ false);
136
0
    }
137
138
0
    double nPPTX = GetViewData().GetPPTX();
139
0
    double nPPTY = GetViewData().GetPPTY();
140
0
    double fZoomX = GetViewData().GetZoomX();
141
0
    double fZoomY = GetViewData().GetZoomY();
142
143
0
    ScSizeDeviceProvider aProv(*pDocSh);
144
0
    if (aProv.IsPrinter())
145
0
    {
146
0
        nPPTX = aProv.GetPPTX();
147
0
        nPPTY = aProv.GetPPTY();
148
0
        fZoomX = fZoomY = 1.0;
149
0
    }
150
151
0
    sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, fZoomX, fZoomY, aProv.GetDevice());
152
0
    bool bAnyChanged = false;
153
0
    for (const SCTAB& nTab : *pMarkData)
154
0
    {
155
0
        bool bChanged = false;
156
0
        SCROW nPaintY = 0;
157
0
        for (const auto& rRow : aMarkedRows)
158
0
        {
159
0
            SCROW nStartNo = rRow.mnStart;
160
0
            SCROW nEndNo = rRow.mnEnd;
161
0
            ScAddress aTopLeft(0, nStartNo, nTab);
162
0
            rDoc.UpdateScriptTypes(aTopLeft, rDoc.GetSheetLimits().GetMaxColCount(), nEndNo-nStartNo+1);
163
0
            if (rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, true))
164
0
            {
165
0
                if (!bChanged)
166
0
                    nPaintY = nStartNo;
167
0
                bAnyChanged = bChanged = true;
168
0
            }
169
0
        }
170
        // tdf#76183: recalculate objects' positions
171
0
        if (bChanged)
172
0
            rDoc.SetDrawPageSize(nTab);
173
0
        if ( bPaint && bChanged )
174
0
            pDocSh->PostPaint( 0, nPaintY, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
175
0
                                                PaintPartFlags::Grid | PaintPartFlags::Left );
176
0
    }
177
178
0
    if ( bPaint && bAnyChanged )
179
0
        pDocSh->UpdateOle(GetViewData());
180
181
0
    if (comphelper::LibreOfficeKit::isActive())
182
0
    {
183
0
        ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
184
0
                GetViewData().GetViewShell(),
185
0
                bRangeWidthChanged /* bColumns */, true /* bRows */,
186
0
                true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
187
0
                false /* bGroups */, GetViewData().GetTabNumber());
188
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNumber());
189
0
    }
190
191
0
    return bAnyChanged;
192
0
}
193
194
bool ScViewFunc::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, bool bApi )
195
0
{
196
0
    if (comphelper::LibreOfficeKit::isActive())
197
0
    {
198
0
        OnLOKSetWidthOrHeight(nStartRow, /*width: */ false);
199
0
    }
200
201
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
202
0
    ScDocument& rDoc = pDocSh->GetDocument();
203
0
    SCTAB nTab = GetViewData().CurrentTabForData();
204
0
    double nPPTX = GetViewData().GetPPTX();
205
0
    double nPPTY = GetViewData().GetPPTY();
206
0
    double fZoomX = GetViewData().GetZoomX();
207
0
    double fZoomY = GetViewData().GetZoomY();
208
0
    sal_uInt16 nOldPixel = 0;
209
0
    if (nStartRow == nEndRow)
210
0
        nOldPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY);
211
212
0
    ScSizeDeviceProvider aProv(*pDocSh);
213
0
    if (aProv.IsPrinter())
214
0
    {
215
0
        nPPTX = aProv.GetPPTX();
216
0
        nPPTY = aProv.GetPPTY();
217
0
        fZoomX = fZoomY = 1.0;
218
0
    }
219
0
    sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, fZoomX, fZoomY, aProv.GetDevice());
220
0
    bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab, bApi);
221
222
    // tdf#76183: recalculate objects' positions
223
0
    if (bChanged)
224
0
        rDoc.SetDrawPageSize(nTab);
225
226
0
    if (bChanged && ( nStartRow == nEndRow ))
227
0
    {
228
0
        sal_uInt16 nNewPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY);
229
0
        if ( nNewPixel == nOldPixel )
230
0
            bChanged = false;
231
0
    }
232
233
0
    if ( bChanged )
234
0
        pDocSh->PostPaint( 0, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
235
0
                                            PaintPartFlags::Grid | PaintPartFlags::Left );
236
237
0
    if (comphelper::LibreOfficeKit::isActive())
238
0
    {
239
0
        ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
240
0
                GetViewData().GetViewShell(),
241
0
                false /* bColumns */, true /* bRows */,
242
0
                true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
243
0
                false /* bGroups */, GetViewData().GetTabNumber());
244
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNumber());
245
0
    }
246
247
0
    return bChanged;
248
0
}
249
250
namespace {
251
252
enum ScAutoSum
253
{
254
    ScAutoSumNone = 0,
255
    ScAutoSumData,
256
    ScAutoSumSum,
257
    ScAutoSumAverage,
258
    ScAutoSumMax,
259
    ScAutoSumMin,
260
    ScAutoSumCount,
261
    ScAutoSumCountA,
262
    ScAutoSumProduct,
263
    ScAutoSumStDev,
264
    ScAutoSumStDevP,
265
    ScAutoSumVar,
266
    ScAutoSumVarP,
267
    ScAutoSumEnd
268
};
269
270
}
271
272
static ScAutoSum lcl_IsAutoSumData( ScDocument& rDoc, SCCOL nCol, SCROW nRow,
273
        SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend )
274
0
{
275
0
    ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab));
276
0
    if (aCell.hasNumeric())
277
0
    {
278
0
        if (aCell.getType() == CELLTYPE_FORMULA)
279
0
        {
280
0
            ScAutoSum val = ScAutoSumNone;
281
0
            ScTokenArray* pCode = aCell.getFormula()->GetCode();
282
0
            if ( pCode )
283
0
            {
284
0
                switch( pCode->GetOuterFuncOpCode() )
285
0
                {
286
0
                    case ocSum     : val = ScAutoSumSum;
287
0
                        break;
288
0
                    case ocAverage : val = ScAutoSumAverage;
289
0
                        break;
290
0
                    case ocMax     : val = ScAutoSumMax;
291
0
                        break;
292
0
                    case ocMin     : val = ScAutoSumMin;
293
0
                        break;
294
0
                    case ocCount   : val = ScAutoSumCount;
295
0
                        break;
296
0
                    case ocCount2  : val = ScAutoSumCountA;
297
0
                        break;
298
0
                    case ocProduct : val = ScAutoSumProduct;
299
0
                        break;
300
0
                    case ocStDev   : val = ScAutoSumStDev;
301
0
                        break;
302
0
                    case ocStDevP  : val = ScAutoSumStDevP;
303
0
                        break;
304
0
                    case ocVar     : val = ScAutoSumVar;
305
0
                        break;
306
0
                    case ocVarP    : val = ScAutoSumVarP;
307
0
                        break;
308
0
                    default        :
309
0
                        break;
310
0
                }
311
0
                if ( pCode->GetAdjacentExtendOfOuterFuncRefs( nExtend,
312
0
                        ScAddress( nCol, nRow, nTab ), eDir ) )
313
0
                    return val;
314
0
            }
315
0
        }
316
0
        return ScAutoSumData;
317
0
    }
318
0
    return ScAutoSumNone;
319
0
}
320
321
0
#define SC_AUTOSUM_MAXCOUNT     20
322
323
static ScAutoSum lcl_SeekAutoSumData( ScDocument& rDoc, SCCOL& nCol, SCROW& nRow,
324
        SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend )
325
0
{
326
0
    sal_uInt16 nCount = 0;
327
0
    while (nCount < SC_AUTOSUM_MAXCOUNT)
328
0
    {
329
0
        if ( eDir == DIR_TOP )
330
0
        {
331
0
            if (nRow > 0)
332
0
                --nRow;
333
0
            else
334
0
                return ScAutoSumNone;
335
0
        }
336
0
        else
337
0
        {
338
0
            if (nCol > 0)
339
0
                --nCol;
340
0
            else
341
0
                return ScAutoSumNone;
342
0
        }
343
0
        ScAutoSum eSum;
344
0
        if ( (eSum = lcl_IsAutoSumData(
345
0
                rDoc, nCol, nRow, nTab, eDir, nExtend )) != ScAutoSumNone )
346
0
            return eSum;
347
0
        ++nCount;
348
0
    }
349
0
    return ScAutoSumNone;
350
0
}
351
352
#undef SC_AUTOSUM_MAXCOUNT
353
354
static bool lcl_FindNextSumEntryInColumn( ScDocument& rDoc, SCCOL nCol, SCROW& nRow,
355
                                   SCTAB nTab, SCCOLROW& nExtend, SCROW nMinRow )
356
0
{
357
0
    const SCROW nTmp = nRow;
358
0
    ScAutoSum eSkip = ScAutoSumNone;
359
0
    for (;;)
360
0
    {
361
0
        eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend );
362
0
        if (eSkip != ScAutoSumData || nRow <= nMinRow )
363
0
            break;
364
0
        --nRow;
365
0
    }
366
0
    return eSkip >= ScAutoSumSum && nRow < nTmp;
367
0
}
368
369
static bool lcl_FindNextSumEntryInRow( ScDocument& rDoc, SCCOL& nCol, SCROW nRow,
370
                                SCTAB nTab, SCCOLROW& nExtend, SCCOL nMinCol )
371
0
{
372
0
    const SCCOL nTmp = nCol;
373
0
    ScAutoSum eSkip = ScAutoSumNone;
374
0
    for (;;)
375
0
    {
376
0
        eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend );
377
0
        if (eSkip != ScAutoSumData || nCol <= nMinCol )
378
0
            break;
379
0
        --nCol;
380
0
    }
381
0
    return eSkip >= ScAutoSumSum && nCol < nTmp;
382
0
}
383
384
static ScAutoSum lcl_GetAutoSumForColumnRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange )
385
0
{
386
0
    const ScAddress aStart = rRange.aStart;
387
0
    const ScAddress aEnd = rRange.aEnd;
388
0
    if ( aStart.Col() != aEnd.Col() )
389
0
    {
390
0
        return ScAutoSumNone;
391
0
    }
392
393
0
    const SCTAB nTab = aEnd.Tab();
394
0
    const SCCOL nCol = aEnd.Col();
395
0
    SCROW nEndRow = aEnd.Row();
396
0
    SCROW nStartRow = nEndRow;
397
0
    SCCOLROW nExtend = 0;
398
0
    ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nCol, nEndRow, nTab, DIR_TOP, nExtend /*out*/ );
399
400
0
    if ( eSum >= ScAutoSumSum )
401
0
    {
402
0
        bool bContinue = false;
403
0
        do
404
0
        {
405
0
            rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) );
406
0
            nEndRow = static_cast< SCROW >( nExtend );
407
0
            bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, aStart.Row() );
408
0
            if ( bContinue )
409
0
            {
410
0
                nStartRow = nEndRow;
411
0
            }
412
0
        } while ( bContinue );
413
0
    }
414
0
    else
415
0
    {
416
0
        while ( nStartRow > aStart.Row() )
417
0
        {
418
0
            eSum = lcl_IsAutoSumData( rDoc, nCol, nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ );
419
0
            if (eSum >= ScAutoSumSum )
420
0
                break;
421
0
            --nStartRow;
422
0
        }
423
0
        rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) );
424
0
        if (eSum == ScAutoSumNone)
425
0
            eSum = ScAutoSumData;
426
0
    }
427
428
0
    return eSum;
429
0
}
430
431
static ScAutoSum lcl_GetAutoSumForRowRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange )
432
0
{
433
0
    const ScAddress aStart = rRange.aStart;
434
0
    const ScAddress aEnd = rRange.aEnd;
435
0
    if ( aStart.Row() != aEnd.Row() )
436
0
    {
437
0
        return ScAutoSumNone;
438
0
    }
439
440
0
    const SCTAB nTab = aEnd.Tab();
441
0
    const SCROW nRow = aEnd.Row();
442
0
    SCCOL nEndCol = aEnd.Col();
443
0
    SCCOL nStartCol = nEndCol;
444
0
    SCCOLROW nExtend = 0;
445
0
    ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nEndCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ );
446
447
0
    if ( eSum >= ScAutoSumSum )
448
0
    {
449
0
        bool bContinue = false;
450
0
        do
451
0
        {
452
0
            rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) );
453
0
            nEndCol = static_cast< SCCOL >( nExtend );
454
0
            bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, aStart.Col() );
455
0
            if ( bContinue )
456
0
            {
457
0
                nStartCol = nEndCol;
458
0
            }
459
0
        } while ( bContinue );
460
0
    }
461
0
    else
462
0
    {
463
0
        while ( nStartCol > aStart.Col() )
464
0
        {
465
0
            eSum = lcl_IsAutoSumData( rDoc, nStartCol-1, nRow, nTab, DIR_LEFT, nExtend /*out*/ );
466
0
            if (eSum >= ScAutoSumSum )
467
0
                break;
468
0
            --nStartCol;
469
0
        }
470
0
        rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) );
471
0
        if (eSum == ScAutoSumNone)
472
0
            eSum = ScAutoSumData;
473
0
    }
474
475
0
    return eSum;
476
0
}
477
478
static sal_Int8 GetSubTotal( const OpCode eCode )
479
0
{
480
0
    sal_Int8 val;
481
0
    switch ( eCode )
482
0
    {
483
0
        case ocSum     : val = 9;
484
0
            break;
485
0
        case ocAverage : val = 1;
486
0
            break;
487
0
        case ocMax     : val = 4;
488
0
            break;
489
0
        case ocMin     : val = 5;
490
0
            break;
491
0
        case ocCount   : val = 2;
492
0
            break;
493
0
        case ocCount2  : val = 3;
494
0
            break;
495
0
        case ocProduct : val = 6;
496
0
            break;
497
0
        case ocStDev   : val = 7;
498
0
            break;
499
0
        case ocStDevP  : val = 8;
500
0
            break;
501
0
        case ocVar     : val = 10;
502
0
            break;
503
0
        case ocVarP    : val = 11;
504
0
            break;
505
0
        default        : val = 9;
506
0
    }
507
508
0
    return val;
509
0
}
510
511
bool ScViewFunc::GetAutoSumArea( ScRangeList& rRangeList )
512
0
{
513
0
    ScDocument& rDoc = GetViewData().GetDocument();
514
0
    SCTAB nTab = GetViewData().CurrentTabForData();
515
516
0
    SCCOL nCol = GetViewData().GetCurX();
517
0
    SCROW nRow = GetViewData().GetCurY();
518
519
0
    SCCOL nStartCol = nCol;
520
0
    SCROW nStartRow = nRow;
521
0
    SCCOL nEndCol    = nCol;
522
0
    SCROW nEndRow    = nRow;
523
0
    SCCOL nSeekCol   = nCol;
524
0
    SCROW nSeekRow   = nRow;
525
0
    SCCOLROW nExtend;       // will become valid via reference for ScAutoSumSum
526
527
0
    bool bCol = false;
528
0
    bool bRow = false;
529
530
0
    ScAutoSum eSum;
531
0
    if ( nRow != 0
532
0
            && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab,
533
0
                DIR_TOP, nExtend /*out*/ )) == ScAutoSumData )
534
0
            && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab,
535
0
                DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData )
536
0
        )
537
0
    {
538
0
        bRow = true;
539
0
        nSeekRow = nRow - 1;
540
0
    }
541
0
    else if ( nCol != 0 && (eSum = lcl_IsAutoSumData( rDoc, nCol-1, nRow, nTab,
542
0
            DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData )
543
0
    {
544
0
        bCol = true;
545
0
        nSeekCol = nCol - 1;
546
0
    }
547
0
    else if ( (eSum = lcl_SeekAutoSumData( rDoc, nCol, nSeekRow, nTab, DIR_TOP, nExtend /*out*/ )) != ScAutoSumNone )
548
0
        bRow = true;
549
0
    else if (( eSum = lcl_SeekAutoSumData( rDoc, nSeekCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ )) != ScAutoSumNone )
550
0
        bCol = true;
551
552
0
    if ( bCol || bRow )
553
0
    {
554
0
        if ( bRow )
555
0
        {
556
0
            nStartRow = nSeekRow;       // nSeekRow might be adjusted via reference
557
0
            if ( eSum >= ScAutoSumSum  && eSum < ScAutoSumEnd )
558
0
                nEndRow = nStartRow;        // only sum sums
559
0
            else
560
0
                nEndRow = nRow - 1;     // maybe extend data area at bottom
561
0
        }
562
0
        else
563
0
        {
564
0
            nStartCol = nSeekCol;       // nSeekCol might be adjusted via reference
565
0
            if ( eSum >= ScAutoSumSum )
566
0
                nEndCol = nStartCol;        // only sum sums
567
0
            else
568
0
                nEndCol = nCol - 1;     // maybe extend data area to the right
569
0
        }
570
0
        bool bContinue = false;
571
0
        do
572
0
        {
573
0
            if ( eSum == ScAutoSumData )
574
0
            {
575
0
                if ( bRow )
576
0
                {
577
0
                    while ( nStartRow != 0 && lcl_IsAutoSumData( rDoc, nCol,
578
0
                            nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ ) == eSum )
579
0
                        --nStartRow;
580
0
                }
581
0
                else
582
0
                {
583
0
                    while ( nStartCol != 0 && lcl_IsAutoSumData( rDoc, nStartCol-1,
584
0
                            nRow, nTab, DIR_LEFT, nExtend /*out*/ ) == eSum )
585
0
                        --nStartCol;
586
0
                }
587
0
            }
588
0
            rRangeList.push_back(
589
0
                ScRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ) );
590
0
            if ( eSum >= ScAutoSumSum )
591
0
            {
592
0
                if ( bRow )
593
0
                {
594
0
                    nEndRow = static_cast< SCROW >( nExtend );
595
0
                    bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, 0 );
596
0
                    if ( bContinue )
597
0
                    {
598
0
                        nStartRow = nEndRow;
599
0
                    }
600
0
                }
601
0
                else
602
0
                {
603
0
                    nEndCol = static_cast< SCCOL >( nExtend );
604
0
                    bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, 0 );
605
0
                    if ( bContinue )
606
0
                    {
607
0
                        nStartCol = nEndCol;
608
0
                    }
609
0
                }
610
0
            }
611
0
        } while ( bContinue );
612
0
        return true;
613
0
    }
614
0
    return false;
615
0
}
616
617
void ScViewFunc::EnterAutoSum(const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr, const OpCode eCode)
618
0
{
619
0
    OUString aFormula = GetAutoSumFormula( rRangeList, bSubTotal, rAddr , eCode);
620
0
    EnterBlock( aFormula, nullptr );
621
0
}
622
623
bool ScViewFunc::AutoSum( const ScRange& rRange, bool bSubTotal, bool bSetCursor, bool bContinue , const OpCode eCode)
624
0
{
625
0
    ScDocument& rDoc = GetViewData().GetDocument();
626
0
    const SCTAB nTab = rRange.aStart.Tab();
627
0
    SCCOL nStartCol = rRange.aStart.Col();
628
0
    SCROW nStartRow = rRange.aStart.Row();
629
0
    const SCCOL nEndCol = rRange.aEnd.Col();
630
0
    const SCROW nEndRow = rRange.aEnd.Row();
631
0
    SCCOLROW nExtend = 0; // out parameter for lcl_IsAutoSumData
632
633
    // ignore rows at the top of the given range which don't contain autosum data
634
0
    bool bRowData = false;
635
0
    for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
636
0
    {
637
0
        for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
638
0
        {
639
0
            if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend ) != ScAutoSumNone )
640
0
            {
641
0
                bRowData = true;
642
0
                break;
643
0
            }
644
0
        }
645
0
        if ( bRowData )
646
0
        {
647
0
            nStartRow = nRow;
648
0
            break;
649
0
        }
650
0
    }
651
0
    if ( !bRowData )
652
0
    {
653
0
        return false;
654
0
    }
655
656
    // ignore columns at the left of the given range which don't contain autosum data
657
0
    bool bColData = false;
658
0
    for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
659
0
    {
660
0
        for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
661
0
        {
662
0
            if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend ) != ScAutoSumNone )
663
0
            {
664
0
                bColData = true;
665
0
                break;
666
0
            }
667
0
        }
668
0
        if ( bColData )
669
0
        {
670
0
            nStartCol = nCol;
671
0
            break;
672
0
        }
673
0
    }
674
0
    if ( !bColData )
675
0
    {
676
0
        return false;
677
0
    }
678
679
0
    const bool bEndRowEmpty = rDoc.IsBlockEmpty( nStartCol, nEndRow, nEndCol, nEndRow, nTab );
680
0
    const bool bEndColEmpty = rDoc.IsBlockEmpty( nEndCol, nStartRow, nEndCol, nEndRow, nTab );
681
0
    bool bRow = ( nStartRow != nEndRow ) && ( bEndRowEmpty || !bEndColEmpty );
682
0
    bool bCol = ( nStartCol != nEndCol ) && ( bEndColEmpty || nStartRow == nEndRow );
683
684
    // find an empty row for entering the result
685
0
    SCROW nInsRow = nEndRow;
686
0
    if ( bRow && !bEndRowEmpty )
687
0
    {
688
0
        if ( nInsRow < rDoc.MaxRow() )
689
0
        {
690
0
            ++nInsRow;
691
0
            while ( !rDoc.IsBlockEmpty( nStartCol, nInsRow, nEndCol, nInsRow, nTab ) )
692
0
            {
693
0
                if ( nInsRow < rDoc.MaxRow() )
694
0
                {
695
0
                    ++nInsRow;
696
0
                }
697
0
                else
698
0
                {
699
0
                    bRow = false;
700
0
                    break;
701
0
                }
702
0
            }
703
0
        }
704
0
        else
705
0
        {
706
0
            bRow = false;
707
0
        }
708
0
    }
709
710
    // find an empty column for entering the result
711
0
    SCCOL nInsCol = nEndCol;
712
0
    if ( bCol && !bEndColEmpty )
713
0
    {
714
0
        if ( nInsCol < rDoc.MaxCol() )
715
0
        {
716
0
            ++nInsCol;
717
0
            while ( !rDoc.IsBlockEmpty( nInsCol, nStartRow, nInsCol, nEndRow, nTab ) )
718
0
            {
719
0
                if ( nInsCol < rDoc.MaxCol() )
720
0
                {
721
0
                    ++nInsCol;
722
0
                }
723
0
                else
724
0
                {
725
0
                    bCol = false;
726
0
                    break;
727
0
                }
728
0
            }
729
0
        }
730
0
        else
731
0
        {
732
0
            bCol = false;
733
0
        }
734
0
    }
735
736
0
    if ( !bRow && !bCol )
737
0
    {
738
0
        return false;
739
0
    }
740
741
0
    SCCOL nMarkEndCol = nEndCol;
742
0
    SCROW nMarkEndRow = nEndRow;
743
0
    ScAutoSum eSum = ScAutoSumNone;
744
0
    SCROW nColSums = 0;
745
0
    SCCOL nRowSums = 0;
746
0
    SCROW nColSumsStartRow = 0;
747
0
    SCCOL nRowSumsStartCol = 0;
748
749
0
    if ( bRow )
750
0
    {
751
        // calculate the row sums for all columns of the given range
752
753
0
        SCROW nSumEndRow = nEndRow;
754
755
0
        if ( bEndRowEmpty )
756
0
        {
757
            // the last row of the given range is empty;
758
            // don't take into account for calculating the autosum
759
0
            --nSumEndRow;
760
0
        }
761
0
        else
762
0
        {
763
            // increase mark range
764
0
            ++nMarkEndRow;
765
0
        }
766
767
0
        for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
768
0
        {
769
0
            if ( !rDoc.IsBlockEmpty( nCol, nStartRow, nCol, nSumEndRow, nTab ) )
770
0
            {
771
0
                ScRangeList aRangeList;
772
                // Include the originally selected start row.
773
0
                const ScRange aRange( nCol, rRange.aStart.Row(), nTab, nCol, nSumEndRow, nTab );
774
0
                if ( (eSum = lcl_GetAutoSumForColumnRange( rDoc, aRangeList, aRange )) != ScAutoSumNone )
775
0
                {
776
0
                    if (++nRowSums == 1)
777
0
                        nRowSumsStartCol = aRangeList[0].aStart.Col();
778
0
                    const OUString aFormula = GetAutoSumFormula(
779
0
                        aRangeList, bSubTotal, ScAddress(nCol, nInsRow, nTab), eCode);
780
0
                    EnterData( nCol, nInsRow, nTab, aFormula );
781
0
                }
782
0
            }
783
0
        }
784
0
    }
785
786
0
    if ( bCol )
787
0
    {
788
        // calculate the column sums for all rows of the given range
789
790
0
        SCCOL nSumEndCol = nEndCol;
791
792
0
        if ( bEndColEmpty )
793
0
        {
794
            // the last column of the given range is empty;
795
            // don't take into account for calculating the autosum
796
0
            --nSumEndCol;
797
0
        }
798
0
        else
799
0
        {
800
            // increase mark range
801
0
            ++nMarkEndCol;
802
0
        }
803
804
0
        for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
805
0
        {
806
0
            if ( !rDoc.IsBlockEmpty( nStartCol, nRow, nSumEndCol, nRow, nTab ) )
807
0
            {
808
0
                ScRangeList aRangeList;
809
                // Include the originally selected start column.
810
0
                const ScRange aRange( rRange.aStart.Col(), nRow, nTab, nSumEndCol, nRow, nTab );
811
0
                if ( (eSum = lcl_GetAutoSumForRowRange( rDoc, aRangeList, aRange )) != ScAutoSumNone )
812
0
                {
813
0
                    if (++nColSums == 1)
814
0
                        nColSumsStartRow = aRangeList[0].aStart.Row();
815
0
                    const OUString aFormula = GetAutoSumFormula( aRangeList, bSubTotal, ScAddress(nInsCol, nRow, nTab), eCode );
816
0
                    EnterData( nInsCol, nRow, nTab, aFormula );
817
0
                }
818
0
            }
819
0
        }
820
0
    }
821
822
    // Set new mark range and cursor position.
823
    // For sum of sums (and data until sum) mark the actual resulting range if
824
    // there is only one, or the data range if more than one. Otherwise use the
825
    // original selection. All extended by end column/row where the sum is put.
826
0
    const ScRange aMarkRange(
827
0
            (eSum >= ScAutoSumSum ?
828
0
             (nRowSums == 1 ? nRowSumsStartCol : nStartCol) :
829
0
             rRange.aStart.Col()),
830
0
            (eSum >= ScAutoSumSum ?
831
0
             (nColSums == 1 ? nColSumsStartRow : nStartRow) :
832
0
             rRange.aStart.Row()),
833
0
            nTab, nMarkEndCol, nMarkEndRow, nTab );
834
0
    MarkRange( aMarkRange, false, bContinue );
835
0
    if ( bSetCursor )
836
0
    {
837
0
        SetCursor( nMarkEndCol, nMarkEndRow );
838
0
    }
839
840
0
    return true;
841
0
}
842
843
OUString ScViewFunc::GetAutoSumFormula( const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr , const OpCode eCode)
844
0
{
845
0
    ScViewData& rViewData = GetViewData();
846
0
    ScDocument& rDoc = rViewData.GetDocument();
847
0
    ScTokenArray aArray(rDoc);
848
849
0
    aArray.AddOpCode(bSubTotal ? ocSubTotal : eCode);
850
0
    aArray.AddOpCode(ocOpen);
851
852
0
    if (bSubTotal)
853
0
    {
854
0
        aArray.AddDouble( GetSubTotal( eCode ) );
855
0
        aArray.AddOpCode(ocSep);
856
0
    }
857
858
0
    if(!rRangeList.empty())
859
0
    {
860
0
        size_t ListSize = rRangeList.size();
861
0
        for ( size_t i = 0; i < ListSize; ++i )
862
0
        {
863
0
            const ScRange & r = rRangeList[i];
864
0
            if (i != 0)
865
0
                aArray.AddOpCode(ocSep);
866
0
            ScComplexRefData aRef;
867
0
            aRef.InitRangeRel(rDoc, r, rAddr);
868
0
            aArray.AddDoubleReference(aRef);
869
0
        }
870
0
    }
871
872
0
    aArray.AddOpCode(ocClose);
873
874
0
    ScCompiler aComp(rDoc, rAddr, aArray, rDoc.GetGrammar());
875
0
    OUStringBuffer aBuf;
876
0
    aComp.CreateStringFromTokenArray(aBuf);
877
0
    aBuf.insert(0, "=");
878
0
    return aBuf.makeStringAndClear();
879
0
}
880
881
void ScViewFunc::EnterBlock( const OUString& rString, const EditTextObject* pData )
882
0
{
883
    //  test for multi selection
884
885
0
    SCCOL nCol = GetViewData().GetCurX();
886
0
    SCROW nRow = GetViewData().GetCurY();
887
0
    SCTAB nTab = GetViewData().CurrentTabForData();
888
0
    ScMarkData& rMark = GetViewData().GetMarkData();
889
0
    if ( rMark.IsMultiMarked() )
890
0
    {
891
0
        rMark.MarkToSimple();
892
0
        if ( rMark.IsMultiMarked() )
893
0
        {       // "Insert into multi selection not possible"
894
0
            ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
895
896
            //  insert into single cell
897
0
            if ( pData )
898
0
                EnterData(nCol, nRow, nTab, *pData);
899
0
            else
900
0
                EnterData( nCol, nRow, nTab, rString );
901
0
            return;
902
0
        }
903
0
    }
904
905
0
    if (GetViewData().SelectionForbidsCellFill())
906
0
    {
907
0
        PaintArea(nCol, nRow, nCol, nRow);        // possibly the edit-engine is still painted there
908
0
        return;
909
0
    }
910
911
0
    ScDocument& rDoc = GetViewData().GetDocument();
912
0
    OUString aNewStr = rString;
913
0
    if ( pData )
914
0
    {
915
0
        const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
916
0
        ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEditEnginePool(), rDoc );
917
0
        aEngine.SetTextCurrentDefaults(*pData);
918
919
0
        ScEditAttrTester aTester( &aEngine );
920
0
        if (!aTester.NeedsObject())
921
0
        {
922
0
            aNewStr = aEngine.GetText();
923
0
            pData = nullptr;
924
0
        }
925
0
    }
926
927
    //  Insert via PasteFromClip
928
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
929
930
0
    ScAddress aPos( nCol, nRow, nTab );
931
932
0
    ScDocumentUniquePtr pInsDoc(new ScDocument( SCDOCMODE_CLIP ));
933
0
    pInsDoc->ResetClip( &rDoc, nTab );
934
935
0
    if (aNewStr[0] == '=')                      // Formula ?
936
0
    {
937
        //  SetString not possible, because in Clipboard-Documents nothing will be compiled!
938
0
        pInsDoc->SetFormulaCell(aPos, new ScFormulaCell(rDoc, aPos, aNewStr));
939
0
    }
940
0
    else if ( pData )
941
0
    {
942
        // A copy of pData will be stored.
943
0
        pInsDoc->SetEditText(aPos, *pData, rDoc.GetEditEnginePool());
944
0
    }
945
0
    else
946
0
        pInsDoc->SetString( nCol, nRow, nTab, aNewStr );
947
948
0
    pInsDoc->SetClipArea( ScRange(aPos) );
949
    // insert Block, with Undo etc.
950
0
    if ( !PasteFromClip( InsertDeleteFlags::CONTENTS, pInsDoc.get(), ScPasteFunc::NONE, false, false,
951
0
            false, INS_NONE, InsertDeleteFlags::ATTRIB ) )
952
0
        return;
953
954
0
    const SfxUInt32Item& rItem = pInsDoc->GetAttr(nCol, nRow, nTab, ATTR_VALUE_FORMAT);
955
    // set number format if incompatible
956
    // MarkData was already MarkToSimple'ed in PasteFromClip
957
0
    const ScRange& aRange = rMark.GetMarkArea();
958
0
    ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
959
0
    aPattern.ItemSetPut(rItem);
960
0
    SvNumFormatType nNewType = rDoc.GetFormatTable()->GetType(rItem.GetValue());
961
0
    rDoc.ApplyPatternIfNumberformatIncompatible( aRange, rMark,
962
0
        aPattern, nNewType );
963
0
}
964
965
//  manual page break
966
967
void ScViewFunc::InsertPageBreak( bool bColumn, bool bRecord, const ScAddress* pPos,
968
                                    bool bSetModified )
969
0
{
970
0
    SCTAB nTab = GetViewData().CurrentTabForData();
971
0
    ScAddress aCursor;
972
0
    if (pPos)
973
0
        aCursor = *pPos;
974
0
    else
975
0
        aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
976
977
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
978
0
                        InsertPageBreak( bColumn, aCursor, bRecord, bSetModified );
979
980
0
    if ( bSuccess && bSetModified )
981
0
        UpdatePageBreakData( true );    // for PageBreak-Mode
982
0
}
983
984
void ScViewFunc::DeletePageBreak( bool bColumn, bool bRecord, const ScAddress* pPos,
985
                                    bool bSetModified )
986
0
{
987
0
    SCTAB nTab = GetViewData().CurrentTabForData();
988
0
    ScAddress aCursor;
989
0
    if (pPos)
990
0
        aCursor = *pPos;
991
0
    else
992
0
        aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
993
994
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
995
0
                        RemovePageBreak( bColumn, aCursor, bRecord, bSetModified );
996
997
0
    if ( bSuccess && bSetModified )
998
0
        UpdatePageBreakData( true );    // for PageBreak-Mode
999
0
}
1000
1001
void ScViewFunc::RemoveManualBreaks()
1002
0
{
1003
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1004
0
    ScDocument& rDoc = pDocSh->GetDocument();
1005
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1006
0
    bool bUndo(rDoc.IsUndoEnabled());
1007
1008
0
    if (bUndo)
1009
0
    {
1010
0
        ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
1011
0
        pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
1012
0
        rDoc.CopyToDocument( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
1013
0
        pDocSh->GetUndoManager()->AddUndoAction(
1014
0
                                std::make_unique<ScUndoRemoveBreaks>( *pDocSh, nTab, std::move(pUndoDoc) ) );
1015
0
    }
1016
1017
0
    rDoc.RemoveManualBreaks(nTab);
1018
0
    rDoc.UpdatePageBreaks(nTab);
1019
1020
0
    UpdatePageBreakData( true );
1021
0
    pDocSh->SetDocumentModified();
1022
0
    pDocSh->PostPaint( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
1023
0
}
1024
1025
void ScViewFunc::SetPrintZoom(sal_uInt16 nScale)
1026
0
{
1027
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1028
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1029
0
    pDocSh->SetPrintZoom( nTab, nScale, 0/*nPages*/ );
1030
0
}
1031
1032
void ScViewFunc::AdjustPrintZoom()
1033
0
{
1034
0
    ScRange aRange;
1035
0
    if ( GetViewData().GetSimpleArea( aRange ) != SC_MARK_SIMPLE )
1036
0
        aRange = GetViewData().GetMarkData().GetMultiMarkArea();
1037
0
    GetViewData().GetDocShell()->AdjustPrintZoom( aRange );
1038
0
}
1039
1040
void ScViewFunc::SetPrintRanges( bool bEntireSheet, const OUString* pPrint,
1041
                                const OUString* pRepCol, const OUString* pRepRow,
1042
                                bool bAddPrint )
1043
0
{
1044
    //  on all selected tables
1045
1046
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
1047
0
    ScDocument& rDoc    = pDocSh->GetDocument();
1048
0
    ScMarkData& rMark   = GetViewData().GetMarkData();
1049
0
    bool bUndo (rDoc.IsUndoEnabled());
1050
1051
0
    std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
1052
1053
0
    ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0);
1054
1055
0
    for (const SCTAB& nTab : rMark)
1056
0
    {
1057
0
        ScRange aRange( 0,0,nTab );
1058
1059
        //  print ranges
1060
1061
0
        if( !bAddPrint )
1062
0
        {
1063
0
            rDoc.ClearPrintRanges( nTab );
1064
0
            rDoc.ClearPrintNamedRanges(nTab);
1065
0
        }
1066
1067
0
        if( bEntireSheet )
1068
0
        {
1069
0
            rDoc.SetPrintEntireSheet( nTab );
1070
0
        }
1071
0
        else if ( pPrint )
1072
0
        {
1073
0
            if ( !pPrint->isEmpty() )
1074
0
            {
1075
0
                const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
1076
0
                sal_Int32 nPos = 0;
1077
0
                do
1078
0
                {
1079
0
                    const OUString aToken = pPrint->getToken(0, sep, nPos);
1080
0
                    if ( aRange.ParseAny( aToken, rDoc, aDetails ) & ScRefFlags::VALID )
1081
0
                        rDoc.AddPrintRange( nTab, aRange );
1082
0
                }
1083
0
                while (nPos >= 0);
1084
0
            }
1085
0
        }
1086
0
        else    // NULL = use selection (print range is always set), use empty string to delete all ranges
1087
0
        {
1088
0
            if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
1089
0
            {
1090
0
                rDoc.AddPrintRange( nTab, aRange );
1091
0
            }
1092
0
            else if ( rMark.IsMultiMarked() )
1093
0
            {
1094
0
                rMark.MarkToMulti();
1095
0
                ScRangeListRef pList( new ScRangeList );
1096
0
                rMark.FillRangeListWithMarks( pList.get(), false );
1097
0
                for (size_t i = 0, n = pList->size(); i < n; ++i)
1098
0
                {
1099
0
                    const ScRange & rR = (*pList)[i];
1100
0
                    rDoc.AddPrintRange(nTab, rR);
1101
0
                }
1102
0
            }
1103
0
        }
1104
1105
        //  repeat columns
1106
1107
0
        if ( pRepCol )
1108
0
        {
1109
0
            if ( pRepCol->isEmpty() )
1110
0
                rDoc.SetRepeatColRange( nTab, std::nullopt );
1111
0
            else
1112
0
                if ( aRange.ParseAny( *pRepCol, rDoc, aDetails ) & ScRefFlags::VALID )
1113
0
                    rDoc.SetRepeatColRange( nTab, std::move(aRange) );
1114
0
        }
1115
1116
        //  repeat rows
1117
1118
0
        if ( pRepRow )
1119
0
        {
1120
0
            if ( pRepRow->isEmpty() )
1121
0
                rDoc.SetRepeatRowRange( nTab, std::nullopt );
1122
0
            else
1123
0
                if ( aRange.ParseAny( *pRepRow, rDoc, aDetails ) & ScRefFlags::VALID )
1124
0
                    rDoc.SetRepeatRowRange( nTab, std::move(aRange) );
1125
0
        }
1126
0
    }
1127
1128
    //  undo (for all tables)
1129
0
    if (bUndo)
1130
0
    {
1131
0
        SCTAB nCurTab = GetViewData().CurrentTabForData();
1132
0
        std::unique_ptr<ScPrintRangeSaver> pNewRanges = rDoc.CreatePrintRangeSaver();
1133
0
        if (comphelper::LibreOfficeKit::isActive())
1134
0
        {
1135
0
            tools::JsonWriter aJsonWriter;
1136
0
            pNewRanges->GetPrintRangesInfo(aJsonWriter);
1137
1138
0
            SfxViewShell* pViewShell = GetViewData().GetViewShell();
1139
0
            const OString message = aJsonWriter.finishAndGetAsOString();
1140
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_PRINT_RANGES, message);
1141
0
        }
1142
1143
0
        pDocSh->GetUndoManager()->AddUndoAction(
1144
0
                    std::make_unique<ScUndoPrintRange>( *pDocSh, nCurTab, std::move(pOldRanges), std::move(pNewRanges) ) );
1145
0
    }
1146
0
    else
1147
0
        pOldRanges.reset();
1148
1149
    //  update page breaks
1150
1151
0
    for (const auto& rTab : rMark)
1152
0
        ScPrintFunc( *pDocSh, pDocSh->GetPrinter(), rTab ).UpdatePages();
1153
1154
0
    SfxBindings& rBindings = GetViewData().GetBindings();
1155
0
    rBindings.Invalidate( SID_DELETE_PRINTAREA );
1156
1157
0
    pDocSh->SetDocumentModified();
1158
0
}
1159
1160
//  Merge cells
1161
1162
bool ScViewFunc::TestMergeCells()           // pre-test (for menu)
1163
0
{
1164
    //  simple test: true if there's a selection but no multi selection and not filtered
1165
1166
0
    const ScMarkData& rMark = GetViewData().GetMarkData();
1167
0
    if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1168
0
    {
1169
0
        ScRange aRange;
1170
0
        bool bMergeable = ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE );
1171
0
        bMergeable = bMergeable && ( aRange.aStart.Col() != aRange.aEnd.Col() ||
1172
0
                                   aRange.aStart.Row() != aRange.aEnd.Row() );
1173
0
        return bMergeable;
1174
0
    }
1175
0
    else
1176
0
        return false;
1177
0
}
1178
1179
void ScViewFunc::MergeCells( bool bApi, bool bDoContents, bool bCenter,
1180
                             const sal_uInt16 nSlot )
1181
0
{
1182
    //  Editable- and Being-Nested- test must be at the beginning (in DocFunc too),
1183
    //  so that the Contents-QueryBox won't appear
1184
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
1185
0
    if (!aTester.IsEditable())
1186
0
    {
1187
0
        ErrorMessage(aTester.GetMessageId());
1188
0
        return;
1189
0
    }
1190
1191
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1192
0
    rMark.MarkToSimple();
1193
0
    if (!rMark.IsMarked())
1194
0
    {
1195
0
        ErrorMessage(STR_NOMULTISELECT);
1196
0
        return;
1197
0
    }
1198
1199
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1200
0
    ScDocument& rDoc = pDocSh->GetDocument();
1201
1202
0
    const ScRange& aMarkRange = rMark.GetMarkArea();
1203
0
    SCCOL nStartCol = aMarkRange.aStart.Col();
1204
0
    SCROW nStartRow = aMarkRange.aStart.Row();
1205
0
    SCTAB nStartTab = aMarkRange.aStart.Tab();
1206
0
    SCCOL nEndCol = aMarkRange.aEnd.Col();
1207
0
    SCROW nEndRow = aMarkRange.aEnd.Row();
1208
0
    SCTAB nEndTab = aMarkRange.aEnd.Tab();
1209
0
    if ( nStartCol == nEndCol && nStartRow == nEndRow )
1210
0
    {
1211
        // nothing to do
1212
0
        return;
1213
0
    }
1214
1215
0
    if ( rDoc.HasAttrib( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
1216
0
                            HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
1217
0
    {       // "Don't nest merging  !"
1218
0
        ErrorMessage(STR_MSSG_MERGECELLS_0);
1219
0
        return;
1220
0
    }
1221
1222
    // Check for the contents of all selected tables.
1223
0
    bool bAskDialog = false;
1224
0
    ScCellMergeOption aMergeOption(nStartCol, nStartRow, nEndCol, nEndRow, bCenter);
1225
0
    for (const SCTAB& i : rMark)
1226
0
    {
1227
0
        aMergeOption.maTabs.insert(i);
1228
1229
0
        sc::MultiDataCellState aState = rDoc.HasMultipleDataCells(aMergeOption.getSingleRange(i));
1230
0
        switch (aState.meState)
1231
0
        {
1232
0
            case sc::MultiDataCellState::HasMultipleCells:
1233
0
            {
1234
                // this range contains multiple data cells.
1235
0
                bAskDialog = true;
1236
0
                break;
1237
0
            }
1238
0
            case sc::MultiDataCellState::HasOneCell:
1239
0
            {
1240
                // this range contains only one data cell.
1241
0
                if (nStartCol != aState.mnCol1 || nStartRow != aState.mnRow1)
1242
0
                    bDoContents = true; // move the value to the top-left.
1243
0
                break;
1244
0
            }
1245
0
            default:
1246
0
                ;
1247
0
        }
1248
0
    }
1249
1250
0
    bool bEmptyMergedCells = officecfg::Office::Calc::Compatibility::MergeCells::EmptyMergedCells::get();
1251
1252
0
    auto doMerge = [this, pDocSh, aMergeOption=std::move(aMergeOption),
1253
0
                    bApi, nStartCol, nStartRow, aMarkRange]
1254
0
        (bool bNowDoContents, bool bNowEmptyMergedCells)
1255
0
    {
1256
0
        if (pDocSh->GetDocFunc().MergeCells(aMergeOption, bNowDoContents, true/*bRecord*/,
1257
0
                                             bApi, bNowEmptyMergedCells))
1258
0
        {
1259
0
            SetCursor( nStartCol, nStartRow );
1260
            // DoneBlockMode( sal_False);
1261
0
            Unmark();
1262
1263
0
            pDocSh->UpdateOle(GetViewData());
1264
0
            UpdateInputLine();
1265
1266
0
            OUString aStartAddress = aMarkRange.aStart.GetColRowString();
1267
0
            OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
1268
1269
0
            collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"MERGE_CELLS"_ustr);
1270
0
        }
1271
0
    };
1272
1273
0
    if (bAskDialog)
1274
0
    {
1275
0
        bool bShowDialog = officecfg::Office::Calc::Compatibility::MergeCells::ShowDialog::get();
1276
0
        if (!bApi && bShowDialog)
1277
0
        {
1278
0
            auto pBox = std::make_shared<ScMergeCellsDialog>(GetViewData().GetDialogParent());
1279
1280
0
            SfxViewShell* pViewShell = GetViewData().GetViewShell();
1281
1282
0
            weld::DialogController::runAsync(pBox, [pBox, bDoContents, bEmptyMergedCells, pViewShell,
1283
0
                                                    nSlot, bApi, doMerge=std::move(doMerge)](sal_Int32 nRetVal) {
1284
0
                if (nRetVal == RET_OK)
1285
0
                {
1286
0
                    bool bRealDoContents = bDoContents;
1287
0
                    bool bRealEmptyMergedCells = bEmptyMergedCells;
1288
0
                    switch (pBox->GetMergeCellsOption())
1289
0
                    {
1290
0
                    case MoveContentHiddenCells:
1291
0
                        bRealDoContents = true;
1292
0
                        break;
1293
0
                    case KeepContentHiddenCells:
1294
0
                        bRealEmptyMergedCells = false;
1295
0
                        break;
1296
0
                    case EmptyContentHiddenCells:
1297
0
                        bRealEmptyMergedCells = true;
1298
0
                        break;
1299
0
                    default:
1300
0
                        assert(!"Unknown option for merge cells.");
1301
0
                        break;
1302
0
                    }
1303
1304
0
                    doMerge(bRealDoContents, bRealEmptyMergedCells);
1305
1306
0
                    if (nSlot != 0)
1307
0
                    {
1308
0
                        SfxRequest aReq(pViewShell->GetViewFrame(), nSlot);
1309
0
                        if (!bApi && bRealDoContents)
1310
0
                            aReq.AppendItem(SfxBoolItem(nSlot, bDoContents));
1311
0
                        SfxBindings& rBindings = pViewShell->GetViewFrame().GetBindings();
1312
0
                        rBindings.Invalidate(nSlot);
1313
0
                        aReq.Done();
1314
0
                    }
1315
0
                }
1316
                // else cancelled
1317
0
            });
1318
0
        }
1319
0
    } else
1320
0
        doMerge(bDoContents, bEmptyMergedCells);
1321
0
}
1322
1323
bool ScViewFunc::TestRemoveMerge()
1324
0
{
1325
0
    bool bMerged = false;
1326
0
    ScRange aRange;
1327
0
    if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE)
1328
0
    {
1329
0
        ScDocument& rDoc = GetViewData().GetDocument();
1330
0
        if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
1331
0
            bMerged = true;
1332
0
    }
1333
0
    return bMerged;
1334
0
}
1335
1336
static bool lcl_extendMergeRange(ScCellMergeOption& rOption, const ScRange& rRange)
1337
0
{
1338
0
    bool bExtended = false;
1339
0
    if (rOption.mnStartCol > rRange.aStart.Col())
1340
0
    {
1341
0
        rOption.mnStartCol = rRange.aStart.Col();
1342
0
        bExtended = true;
1343
0
    }
1344
0
    if (rOption.mnStartRow > rRange.aStart.Row())
1345
0
    {
1346
0
        rOption.mnStartRow = rRange.aStart.Row();
1347
0
        bExtended = true;
1348
0
    }
1349
0
    if (rOption.mnEndCol < rRange.aEnd.Col())
1350
0
    {
1351
0
        rOption.mnEndCol = rRange.aEnd.Col();
1352
0
        bExtended = true;
1353
0
    }
1354
0
    if (rOption.mnEndRow < rRange.aEnd.Row())
1355
0
    {
1356
0
        rOption.mnEndRow = rRange.aEnd.Row();
1357
0
        bExtended = true;
1358
0
    }
1359
0
    return bExtended;
1360
0
}
1361
1362
bool ScViewFunc::RemoveMerge()
1363
0
{
1364
0
    ScRange aRange;
1365
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
1366
0
    if (!aTester.IsEditable())
1367
0
    {
1368
0
        ErrorMessage(aTester.GetMessageId());
1369
0
        return false;
1370
0
    }
1371
0
    else if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE)
1372
0
    {
1373
0
        ScDocument& rDoc = GetViewData().GetDocument();
1374
0
        ScRange aExtended( aRange );
1375
0
        rDoc.ExtendMerge( aExtended );
1376
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1377
0
        const ScMarkData& rMark = GetViewData().GetMarkData();
1378
0
        ScCellMergeOption aOption(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row());
1379
0
        bool bExtended = false;
1380
0
        do
1381
0
        {
1382
0
            bExtended = false;
1383
0
            for (const SCTAB& i : rMark)
1384
0
            {
1385
0
                aOption.maTabs.insert(i);
1386
0
                aExtended.aStart.SetTab(i);
1387
0
                aExtended.aEnd.SetTab(i);
1388
0
                rDoc.ExtendMerge(aExtended);
1389
0
                rDoc.ExtendOverlapped(aExtended);
1390
1391
                // Expand the current range to be inclusive of all merged
1392
                // areas on all sheets.
1393
0
                bExtended = lcl_extendMergeRange(aOption, aExtended);
1394
0
            }
1395
0
        }
1396
0
        while (bExtended);
1397
1398
0
        bool bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, true/*bRecord*/, nullptr);
1399
0
        aExtended = aOption.getFirstSingleRange();
1400
0
        MarkRange( aExtended );
1401
1402
0
        if (bOk)
1403
0
            pDocSh->UpdateOle(GetViewData());
1404
0
    }
1405
1406
0
    OUString aCellLocation = aRange.aStart.GetColRowString();
1407
0
    collectUIInformation({{"CELL", aCellLocation}}, u"UNMERGE_CELL"_ustr);
1408
1409
0
    return true;        //! bOk ??
1410
0
}
1411
1412
void ScViewFunc::FillSimple( FillDir eDir )
1413
0
{
1414
0
    ScRange aRange;
1415
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE
1416
0
        || GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE_FILTERED)
1417
0
    {
1418
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1419
0
        const ScMarkData& rMark = GetViewData().GetMarkData();
1420
0
        bool bSuccess = pDocSh->GetDocFunc().FillSimple( aRange, &rMark, eDir, false );
1421
0
        if (bSuccess)
1422
0
        {
1423
0
            pDocSh->UpdateOle(GetViewData());
1424
0
            UpdateScrollBars();
1425
1426
0
            auto& rDoc = pDocSh->GetDocument();
1427
0
            const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
1428
0
            const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell();
1429
0
            if ( bDoAutoSpell )
1430
0
            {
1431
                // Copy AutoSpellData from above(left/right/below) if no selection.
1432
0
                switch (eDir)
1433
0
                {
1434
0
                    case FILL_TO_BOTTOM:
1435
0
                        if (aRange.aStart.Row() > 0 && aRange.aStart.Row() == aRange.aEnd.Row())
1436
0
                            aRange.aStart.IncRow(-1);
1437
0
                    break;
1438
0
                    case FILL_TO_TOP:
1439
0
                        if (aRange.aEnd.Row() < rDoc.MaxRow() && aRange.aStart.Row() == aRange.aEnd.Row())
1440
0
                            aRange.aEnd.IncRow(1);
1441
0
                    break;
1442
0
                    case FILL_TO_RIGHT:
1443
0
                        if (aRange.aStart.Col() > 0 && aRange.aStart.Col() == aRange.aEnd.Col())
1444
0
                            aRange.aStart.IncCol(-1);
1445
0
                    break;
1446
0
                    case FILL_TO_LEFT:
1447
0
                        if (aRange.aEnd.Col() < rDoc.MaxCol() && aRange.aStart.Col() == aRange.aEnd.Col())
1448
0
                            aRange.aEnd.IncCol(1);
1449
0
                    break;
1450
0
                }
1451
0
                CopyAutoSpellData(eDir, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(),
1452
0
                        ::std::numeric_limits<sal_uLong>::max());
1453
0
            }
1454
1455
            // Invalidate cell slots and update input line with new content.
1456
0
            CellContentChanged();
1457
0
        }
1458
0
    }
1459
0
    else
1460
0
        ErrorMessage(STR_NOMULTISELECT);
1461
0
}
1462
1463
void ScViewFunc::FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
1464
                             double fStart, double fStep, double fMax )
1465
0
{
1466
0
    ScRange aRange;
1467
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1468
0
    {
1469
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1470
0
        const ScMarkData& rMark = GetViewData().GetMarkData();
1471
0
        bool bSuccess = pDocSh->GetDocFunc().
1472
0
                        FillSeries( aRange, &rMark, eDir, eCmd, eDateCmd,
1473
0
                                    fStart, fStep, fMax, false );
1474
0
        if (bSuccess)
1475
0
        {
1476
0
            pDocSh->UpdateOle(GetViewData());
1477
0
            UpdateScrollBars();
1478
1479
0
            HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange);
1480
0
        }
1481
0
    }
1482
0
    else
1483
0
        ErrorMessage(STR_NOMULTISELECT);
1484
0
}
1485
1486
void ScViewFunc::FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
1487
                            SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
1488
0
{
1489
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1490
0
    ScRange aRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab );
1491
0
    ScRange aSourceRange( aRange );
1492
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1493
0
    const ScMarkData& rMark = GetViewData().GetMarkData();
1494
0
    bool bSuccess = pDocSh->GetDocFunc().
1495
0
                    FillAuto( aRange, &rMark, eDir, nCount, false );
1496
0
    if (!bSuccess)
1497
0
        return;
1498
1499
0
    MarkRange( aRange, false );         // aRange was modified in FillAuto
1500
0
    pDocSh->UpdateOle(GetViewData());
1501
0
    UpdateScrollBars();
1502
1503
0
    const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
1504
0
    const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell();
1505
0
    if ( bDoAutoSpell )
1506
0
        CopyAutoSpellData(eDir, nStartCol, nStartRow, nEndCol, nEndRow, nCount);
1507
1508
0
    ScModelObj* pModelObj = pDocSh->GetModel();
1509
1510
0
    ScRangeList aChangeRanges;
1511
0
    ScRange aChangeRange( aRange );
1512
0
    switch (eDir)
1513
0
    {
1514
0
        case FILL_TO_BOTTOM:
1515
0
            aChangeRange.aStart.SetRow( aSourceRange.aEnd.Row() + 1 );
1516
0
            break;
1517
0
        case FILL_TO_TOP:
1518
0
            aChangeRange.aEnd.SetRow( aSourceRange.aStart.Row() - 1 );
1519
0
            break;
1520
0
        case FILL_TO_RIGHT:
1521
0
            aChangeRange.aStart.SetCol( aSourceRange.aEnd.Col() + 1 );
1522
0
            break;
1523
0
        case FILL_TO_LEFT:
1524
0
            aChangeRange.aEnd.SetCol( aSourceRange.aStart.Col() - 1 );
1525
0
            break;
1526
0
        default:
1527
0
            break;
1528
0
    }
1529
0
    aChangeRanges.push_back( aChangeRange );
1530
1531
0
    if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
1532
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
1533
0
    else if (pModelObj)
1534
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
1535
0
}
1536
1537
void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
1538
                                   SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
1539
0
{
1540
0
    const ScDocument* pDoc = &GetViewData().GetDocument();
1541
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1542
0
    CellType eCellType;
1543
1544
0
    ScGridWindow* pWin = GetActiveWin();
1545
0
    if ( pWin->InsideVisibleRange(nStartCol, nStartRow) && pWin->InsideVisibleRange(nEndCol, nEndRow) )
1546
0
    {
1547
0
        if ( nCount == ::std::numeric_limits<sal_uLong>::max() )
1548
0
        {
1549
0
            switch( eDir )
1550
0
            {
1551
0
                case FILL_TO_BOTTOM:
1552
0
                    for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1553
0
                    {
1554
0
                        eCellType = pDoc->GetCellType(nColItr, nStartRow, nTab); // We need this optimization only for EditTextObject source cells
1555
0
                        if (eCellType != CELLTYPE_EDIT)
1556
0
                            continue;
1557
1558
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nStartRow);
1559
0
                        if (!aRangeResult.HasRanges())
1560
0
                            continue;
1561
0
                        for ( SCROW nRowItr = nStartRow + 1; nRowItr <= nEndRow; ++nRowItr )
1562
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1563
0
                    }
1564
0
                    break;
1565
0
                case FILL_TO_TOP:
1566
0
                    for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1567
0
                    {
1568
0
                        eCellType = pDoc->GetCellType(nColItr, nEndRow, nTab); // We need this optimization only for EditTextObject source cells
1569
0
                        if (eCellType != CELLTYPE_EDIT)
1570
0
                            continue;
1571
1572
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nEndRow);
1573
0
                        if (!aRangeResult.HasRanges())
1574
0
                            continue;
1575
0
                        for ( SCROW nRowItr = nEndRow - 1; nRowItr >= nStartRow; --nRowItr )
1576
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1577
0
                    }
1578
0
                    break;
1579
0
                case FILL_TO_RIGHT:
1580
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1581
0
                    {
1582
0
                        eCellType = pDoc->GetCellType(nStartCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
1583
0
                        if (eCellType != CELLTYPE_EDIT)
1584
0
                            continue;
1585
1586
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nStartCol, nRowItr);
1587
0
                        if (!aRangeResult.HasRanges())
1588
0
                            continue;
1589
0
                        for ( SCCOL nColItr = nStartCol + 1; nColItr <= nEndCol; ++nColItr )
1590
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1591
0
                    }
1592
0
                    break;
1593
0
                case FILL_TO_LEFT:
1594
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1595
0
                    {
1596
0
                        eCellType = pDoc->GetCellType(nEndCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
1597
0
                        if (eCellType != CELLTYPE_EDIT)
1598
0
                            continue;
1599
1600
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nEndCol, nRowItr);
1601
0
                        if (!aRangeResult.HasRanges())
1602
0
                            continue;
1603
0
                        for ( SCCOL nColItr = nEndCol - 1; nColItr >= nStartCol; --nColItr )
1604
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1605
0
                    }
1606
0
                    break;
1607
0
            }
1608
0
            return;
1609
0
        }
1610
1611
0
        SCROW nRowRepeatSize = nEndRow - nStartRow + 1;
1612
0
        SCCOL nColRepeatSize = nEndCol - nStartCol + 1;
1613
0
        SCROW nTillRow = 0;
1614
0
        SCCOL nTillCol = 0;
1615
0
        std::vector<std::vector<sc::MisspellRangeResult>> aSourceSpellRanges(nRowRepeatSize, std::vector<sc::MisspellRangeResult>(nColRepeatSize));
1616
1617
0
        for ( SCROW nRowIdx = 0; nRowIdx < nRowRepeatSize; ++nRowIdx )
1618
0
        {
1619
0
            for ( SCCOL nColIdx = 0; nColIdx < nColRepeatSize; ++nColIdx )
1620
0
            {
1621
0
                eCellType = pDoc->GetCellType(nStartCol + nColIdx, nStartRow + nRowIdx, nTab); // We need this optimization only for EditTextObject source cells
1622
0
                if (eCellType != CELLTYPE_EDIT)
1623
0
                    continue;
1624
1625
0
                aSourceSpellRanges[nRowIdx][nColIdx] = pWin->GetAutoSpellData( nStartCol + nColIdx, nStartRow + nRowIdx );
1626
0
            }
1627
0
        }
1628
1629
0
        switch( eDir )
1630
0
        {
1631
0
            case FILL_TO_BOTTOM:
1632
0
                nTillRow = nEndRow + nCount;
1633
0
                for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1634
0
                {
1635
0
                    for ( SCROW nRowItr = nEndRow + 1; nRowItr <= nTillRow; ++nRowItr )
1636
0
                    {
1637
0
                        size_t nSourceRowIdx = ( nRowItr - nEndRow - 1 ) % nRowRepeatSize;
1638
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
1639
0
                        if (!aRangeResult.HasRanges())
1640
0
                            continue;
1641
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1642
0
                    }
1643
0
                }
1644
0
                break;
1645
1646
0
            case FILL_TO_TOP:
1647
0
                nTillRow = nStartRow - nCount;
1648
0
                for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1649
0
                {
1650
0
                    for ( SCROW nRowItr = nStartRow - 1; nRowItr >= nTillRow; --nRowItr )
1651
0
                    {
1652
0
                        size_t nSourceRowIdx = nRowRepeatSize - 1 - ( ( nStartRow - 1 - nRowItr ) % nRowRepeatSize );
1653
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
1654
0
                        if (!aRangeResult.HasRanges())
1655
0
                            continue;
1656
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1657
0
                    }
1658
0
                }
1659
0
                break;
1660
1661
0
            case FILL_TO_RIGHT:
1662
0
                nTillCol = nEndCol + nCount;
1663
0
                for ( SCCOL nColItr = nEndCol + 1; nColItr <= nTillCol; ++nColItr )
1664
0
                {
1665
0
                    size_t nSourceColIdx = ( nColItr - nEndCol - 1 ) % nColRepeatSize;
1666
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1667
0
                    {
1668
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
1669
0
                        if (!aRangeResult.HasRanges())
1670
0
                            continue;
1671
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1672
0
                    }
1673
0
                }
1674
0
                break;
1675
1676
0
            case FILL_TO_LEFT:
1677
0
                nTillCol = nStartCol - nCount;
1678
0
                for ( SCCOL nColItr = nStartCol - 1; nColItr >= nTillCol; --nColItr )
1679
0
                {
1680
0
                    size_t nSourceColIdx = nColRepeatSize - 1 - ( ( nStartCol - 1 - nColItr ) % nColRepeatSize );
1681
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1682
0
                    {
1683
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
1684
0
                        if (!aRangeResult.HasRanges())
1685
0
                            continue;
1686
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1687
0
                    }
1688
0
                }
1689
0
                break;
1690
0
        }
1691
0
    }
1692
0
    else
1693
0
        pWin->ResetAutoSpellForContentChange();
1694
1695
0
}
1696
1697
void ScViewFunc::FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink )
1698
0
{
1699
    //! allow source sheet to be protected
1700
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
1701
0
    if (!aTester.IsEditable())
1702
0
    {
1703
0
        ErrorMessage(aTester.GetMessageId());
1704
0
        return;
1705
0
    }
1706
1707
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1708
0
    ScDocument& rDoc = pDocSh->GetDocument();
1709
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1710
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1711
0
    bool bUndo(rDoc.IsUndoEnabled());
1712
1713
0
    ScRange aMarkRange;
1714
0
    rMark.MarkToSimple();
1715
0
    bool bMulti = rMark.IsMultiMarked();
1716
0
    if (bMulti)
1717
0
        aMarkRange = rMark.GetMultiMarkArea();
1718
0
    else if (rMark.IsMarked())
1719
0
        aMarkRange = rMark.GetMarkArea();
1720
0
    else
1721
0
        aMarkRange = ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
1722
1723
0
    ScDocumentUniquePtr pUndoDoc;
1724
1725
0
    if (bUndo)
1726
0
    {
1727
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1728
0
        pUndoDoc->InitUndo( rDoc, nTab, nTab );
1729
1730
0
        for (const SCTAB& i : rMark)
1731
0
            if (i != nTab )
1732
0
            {
1733
0
                pUndoDoc->AddUndoTab( i, i );
1734
0
                aMarkRange.aStart.SetTab( i );
1735
0
                aMarkRange.aEnd.SetTab( i );
1736
0
                rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc );
1737
0
            }
1738
0
    }
1739
1740
0
    if (bMulti)
1741
0
        rDoc.FillTabMarked( nTab, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
1742
0
    else
1743
0
    {
1744
0
        aMarkRange.aStart.SetTab( nTab );
1745
0
        aMarkRange.aEnd.SetTab( nTab );
1746
0
        rDoc.FillTab( aMarkRange, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
1747
0
    }
1748
1749
0
    if (bUndo)
1750
0
    {   //! for ChangeTrack not until the end
1751
0
        pDocSh->GetUndoManager()->AddUndoAction(
1752
0
            std::make_unique<ScUndoFillTable>( *pDocSh, rMark,
1753
0
                                aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nTab,
1754
0
                                aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab,
1755
0
                                std::move(pUndoDoc), bMulti, nTab, nFlags, nFunction, bSkipEmpty, bAsLink ) );
1756
0
    }
1757
1758
0
    pDocSh->PostPaintGridAll();
1759
0
    pDocSh->PostDataChanged();
1760
0
}
1761
1762
/** Downward fill of selected cell(s) by double-clicking cross-hair cursor
1763
1764
    Either, extends a current selection if non-empty cells exist immediately
1765
    below the selection, overwriting cells below the selection up to the
1766
    minimum row of already filled cells.
1767
1768
    Or, extends a current selection down to the last non-empty cell of an
1769
    adjacent column when the lower-right corner of the selection is
1770
    double-clicked. It uses a left-adjoining non-empty column as a guide if
1771
    such is available, otherwise a right-adjoining non-empty column is used.
1772
1773
    @return No return value
1774
1775
    @see #i12313#
1776
*/
1777
void ScViewFunc::FillCrossDblClick()
1778
0
{
1779
0
    ScRange aRange;
1780
0
    GetViewData().GetSimpleArea( aRange );
1781
0
    aRange.PutInOrder();
1782
1783
0
    SCTAB nTab = GetViewData().GetCurPos().Tab();
1784
0
    SCCOL nStartX = aRange.aStart.Col();
1785
0
    SCROW nStartY = aRange.aStart.Row();
1786
0
    SCCOL nEndX   = aRange.aEnd.Col();
1787
0
    SCROW nEndY   = aRange.aEnd.Row();
1788
1789
0
    ScDocument& rDoc = GetViewData().GetDocument();
1790
1791
0
    if (nEndY >= rDoc.MaxRow())
1792
        // Nothing to fill.
1793
0
        return;
1794
1795
    // Make sure the selection is not empty
1796
0
    if ( rDoc.IsBlockEmpty( nStartX, nStartY, nEndX, nEndY, nTab ) )
1797
0
        return;
1798
1799
    // If there is data in all columns immediately below the selection then
1800
    // switch to overwriting fill.
1801
0
    SCROW nOverWriteEndRow = rDoc.MaxRow();
1802
0
    for (SCCOL nCol = nStartX; nCol <= nEndX; ++nCol)
1803
0
    {
1804
0
        if (rDoc.HasData( nCol, nEndY + 1, nTab))
1805
0
        {
1806
            // Determine the shortest data column to end the fill.
1807
0
            SCROW nY = nEndY + 1;
1808
            // FindAreaPos() returns the start row of the next data block if
1809
            // the current row is the last row of a data block and an empty
1810
            // cell follows. Somewhat unexpected behaviour...
1811
            // So check beforehand if there is one non-empty cell following.
1812
0
            if (rDoc.HasData( nCol, nY + 1, nTab))
1813
0
            {
1814
0
                rDoc.FindAreaPos( nCol, nY, nTab, SC_MOVE_DOWN);
1815
0
                if (nOverWriteEndRow > nY)
1816
0
                    nOverWriteEndRow = nY;
1817
0
            }
1818
0
            else
1819
0
            {
1820
0
                nOverWriteEndRow = nY;
1821
0
            }
1822
0
        }
1823
0
        else
1824
0
        {
1825
0
            nOverWriteEndRow = 0;
1826
0
            break;  // for
1827
0
        }
1828
0
    }
1829
1830
0
    if (nOverWriteEndRow > nEndY)
1831
0
    {
1832
0
        FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nOverWriteEndRow - nEndY);
1833
0
        return;
1834
0
    }
1835
1836
    // Non-overwriting fill follows.
1837
1838
0
    const bool bDataLeft = (nStartX > 0);
1839
0
    if (!bDataLeft && nEndX >= rDoc.MaxCol())
1840
        // Absolutely no data left or right of selection.
1841
0
        return;
1842
1843
    // Check that there is
1844
    // 1) data immediately left (preferred) or right of start (row) of selection
1845
    // 2) data there below
1846
    // 3) no data immediately below selection
1847
1848
0
    SCCOL nMovX = (bDataLeft ? nStartX - 1 : nEndX + 1);
1849
0
    SCROW nMovY = nStartY;
1850
0
    bool bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
1851
0
    if (!bDataFound && bDataLeft && nEndX < rDoc.MaxCol())
1852
0
    {
1853
0
        nMovX = nEndX + 1;  // check right
1854
0
        bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
1855
0
    }
1856
1857
0
    if (!(bDataFound && rDoc.IsEmptyData( nStartX, nEndY + 1, nEndX, nEndY + 1, nTab )))
1858
0
        return;
1859
1860
    // Get end of data left or right.
1861
0
    rDoc.FindAreaPos( nMovX, nMovY, nTab, SC_MOVE_DOWN);
1862
    // Find minimum end row of below empty area and data right.
1863
0
    for (SCCOL nX = nStartX; nX <= nEndX; ++nX)
1864
0
    {
1865
0
        SCROW nY = nEndY + 1;
1866
        // Get next row with data in this column.
1867
0
        rDoc.FindAreaPos( nX, nY, nTab, SC_MOVE_DOWN);
1868
0
        if (nMovY == rDoc.MaxRow() && nY == rDoc.MaxRow())
1869
0
        {
1870
            // FindAreaPos() returns MAXROW also if there is no data at all
1871
            // from the start, so check if that contains data if the nearby
1872
            // (left or right) data ends there and increment if no data
1873
            // here, pretending the next data would be thereafter so nMovY
1874
            // will not be decremented.
1875
0
            if (!rDoc.HasData( nX, nY, nTab))
1876
0
                ++nY;
1877
0
        }
1878
0
        if (nMovY > nY - 1)
1879
0
            nMovY = nY - 1;
1880
0
    }
1881
1882
0
    if (nMovY > nEndY)
1883
0
    {
1884
0
        FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nMovY - nEndY);
1885
0
    }
1886
0
}
1887
1888
void ScViewFunc::ConvertFormulaToValue()
1889
0
{
1890
0
    ScRange aRange;
1891
0
    GetViewData().GetSimpleArea(aRange);
1892
0
    aRange.PutInOrder();
1893
1894
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1895
0
    pDocSh->GetDocFunc().ConvertFormulaToValue(aRange, true);
1896
    // tdf#131326 - invalidate cell slots and update input line with new content
1897
0
    CellContentChanged();
1898
0
    pDocSh->PostPaint(aRange, PaintPartFlags::Grid);
1899
0
}
1900
1901
void ScViewFunc::TransliterateText( TransliterationFlags nType )
1902
0
{
1903
0
    ScMarkData aFuncMark = GetViewData().GetMarkData();
1904
0
    if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
1905
0
    {
1906
        //  no selection -> use cursor position
1907
1908
0
        ScAddress aCursor( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().CurrentTabForData() );
1909
0
        aFuncMark.SetMarkArea( ScRange( aCursor ) );
1910
0
    }
1911
1912
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
1913
0
                        TransliterateText( aFuncMark, nType, false );
1914
0
    if (bSuccess)
1915
0
    {
1916
0
        GetViewData().GetViewShell()->UpdateInputHandler();
1917
0
    }
1918
0
}
1919
1920
//  AutoFormat
1921
1922
void ScViewFunc::AutoFormat( sal_uInt16 nFormatNo )
1923
0
{
1924
0
    ScRange aRange;
1925
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1926
0
    {
1927
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1928
0
        ScMarkData& rMark = GetViewData().GetMarkData();
1929
1930
0
        bool bSuccess = pDocSh->GetDocFunc().AutoFormat( aRange, &rMark, nFormatNo, false );
1931
0
        if (bSuccess)
1932
0
            pDocSh->UpdateOle(GetViewData());
1933
0
    }
1934
0
    else
1935
0
        ErrorMessage(STR_NOMULTISELECT);
1936
0
}
1937
1938
// Search & Replace
1939
1940
bool ScViewFunc::SearchAndReplace( const SvxSearchItem* pSearchItem,
1941
                                        bool bAddUndo, bool bIsApi )
1942
0
{
1943
0
    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
1944
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1945
0
    ScDocument& rDoc = pDocSh->GetDocument();
1946
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1947
0
    if (bAddUndo && !rDoc.IsUndoEnabled())
1948
0
        bAddUndo = false;
1949
1950
0
    bool bCursorMoved = false;
1951
0
    SCCOL nOrigPosX = GetViewData().GetCurX();
1952
0
    SCROW nOrigPosY = GetViewData().GetCurY();
1953
0
    if ( !rMark.IsMarked() && !rMark.IsMultiMarked() && (pSearchItem->HasStartPoint()) )
1954
0
    {
1955
        // No selection -> but we have a start point (top left corner of the
1956
        // current view), start searching from there, not from the current
1957
        // cursor position.
1958
0
        SCCOL nPosX;
1959
0
        SCROW nPosY;
1960
1961
0
        int nPixelX = pSearchItem->GetStartPointX() * GetViewData().GetPPTX();
1962
0
        int nPixelY = pSearchItem->GetStartPointY() * GetViewData().GetPPTY();
1963
1964
0
        GetViewData().GetPosFromPixel(nPixelX, nPixelY, GetViewData().GetActivePart(), nPosX, nPosY);
1965
1966
0
        AlignToCursor( nPosX, nPosY, SC_FOLLOW_JUMP );
1967
0
        SetCursor( nPosX, nPosY, true );
1968
0
        bCursorMoved = true;
1969
0
    }
1970
1971
0
    SCCOL nCol, nOldCol;
1972
0
    SCROW nRow, nOldRow;
1973
0
    SCTAB nTab, nOldTab;
1974
0
    nCol = nOldCol = GetViewData().GetCurX();
1975
0
    nRow = nOldRow = GetViewData().GetCurY();
1976
0
    nTab = nOldTab = GetViewData().CurrentTabForData();
1977
1978
0
    SvxSearchCmd nCommand = pSearchItem->GetCommand();
1979
0
    bool bAllTables = pSearchItem->IsAllTables();
1980
0
    std::set<SCTAB> aOldSelectedTables;
1981
0
    SCTAB nLastTab = rDoc.GetTableCount() - 1;
1982
0
    SCTAB nStartTab, nEndTab;
1983
0
    if ( bAllTables )
1984
0
    {
1985
0
        nStartTab = 0;
1986
0
        nEndTab = nLastTab;
1987
0
        std::set<SCTAB> aTmp(rMark.begin(), rMark.end());
1988
0
        aOldSelectedTables.swap(aTmp);
1989
0
    }
1990
0
    else
1991
0
    {   //! at least one is always selected
1992
0
        nStartTab = rMark.GetFirstSelected();
1993
0
        nEndTab = rMark.GetLastSelected();
1994
0
    }
1995
1996
0
    if (   nCommand == SvxSearchCmd::FIND
1997
0
        || nCommand == SvxSearchCmd::FIND_ALL)
1998
0
        bAddUndo = false;
1999
2000
    //!     account for bAttrib during Undo !!!
2001
2002
0
    ScDocumentUniquePtr pUndoDoc;
2003
0
    std::unique_ptr<ScMarkData> pUndoMark;
2004
0
    OUString aUndoStr;
2005
0
    if (bAddUndo)
2006
0
    {
2007
0
        pUndoMark.reset(new ScMarkData(rMark));                // Mark is being modified
2008
0
        if ( nCommand == SvxSearchCmd::REPLACE_ALL )
2009
0
        {
2010
0
            pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
2011
0
            pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
2012
0
        }
2013
0
    }
2014
2015
0
    if ( bAllTables )
2016
0
    {   //! select all, after pUndoMark has been created
2017
0
        for ( SCTAB j = nStartTab; j <= nEndTab; j++ )
2018
0
        {
2019
0
            rMark.SelectTable( j, true );
2020
0
        }
2021
0
    }
2022
2023
0
    DoneBlockMode(true);                // don't delete mark
2024
0
    InitOwnBlockMode( ScRange( nCol, nRow, nStartTab, nCol, nRow, nEndTab));
2025
2026
0
    bool bFirst = true;
2027
0
    bool bFound = false;
2028
0
    while (true)
2029
0
    {
2030
0
        GetFrameWin()->EnterWait();
2031
0
        ScRangeList aMatchedRanges;
2032
0
        bool bMatchedRangesWereClamped = false;
2033
0
        if (rDoc.SearchAndReplace(*pSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, pUndoDoc.get(), bMatchedRangesWereClamped))
2034
0
        {
2035
0
            bFound = true;
2036
0
            if (bAddUndo)
2037
0
            {
2038
0
                GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
2039
0
                    std::make_unique<ScUndoReplace>( *GetViewData().GetDocShell(), *pUndoMark,
2040
0
                                        nCol, nRow, nTab,
2041
0
                                        aUndoStr, std::move(pUndoDoc), pSearchItem ) );
2042
0
            }
2043
2044
0
            if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL)
2045
0
            {
2046
0
                SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2047
0
                bool bShow = GetViewData().GetViewShell()->GetViewData().GetOptions().GetOption(sc::ViewOption::SUMMARY);
2048
2049
0
                if (bShow && pViewFrm && !comphelper::LibreOfficeKit::isActive())
2050
0
                {
2051
0
                    pViewFrm->ShowChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
2052
0
                    SfxChildWindow* pWnd = pViewFrm->GetChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
2053
0
                    if (pWnd)
2054
0
                    {
2055
0
                        sc::SearchResultsDlg* pDlg = static_cast<sc::SearchResultsDlg*>(pWnd->GetController().get());
2056
0
                        if (pDlg)
2057
0
                        {
2058
0
                            const bool bCellNotes = (pSearchItem->GetCellType() == SvxSearchCellType::NOTE);
2059
                            // ScCellIterator iterates over cells with content,
2060
                            // for empty cells iterate over match positions.
2061
0
                            const bool bEmptyCells = (!bCellNotes
2062
0
                                    && ((nCommand == SvxSearchCmd::FIND_ALL
2063
0
                                            && ScDocument::IsEmptyCellSearch(*pSearchItem))
2064
0
                                        || (nCommand == SvxSearchCmd::REPLACE_ALL
2065
0
                                            && pSearchItem->GetReplaceString().isEmpty())));
2066
0
                            pDlg->FillResults(rDoc, aMatchedRanges, bCellNotes, bEmptyCells, bMatchedRangesWereClamped);
2067
0
                        }
2068
0
                    }
2069
0
                }
2070
2071
0
                rMark.ResetMark();
2072
0
                for (size_t i = 0, n = aMatchedRanges.size(); i < n; ++i)
2073
0
                {
2074
0
                    const ScRange& r = aMatchedRanges[i];
2075
0
                    if (r.aStart.Tab() == nTab)
2076
0
                        rMark.SetMultiMarkArea(r);
2077
0
                }
2078
0
            }
2079
2080
0
            break;                  // break 'while (TRUE)'
2081
0
        }
2082
0
        else if ( bFirst && (nCommand == SvxSearchCmd::FIND ||
2083
0
                nCommand == SvxSearchCmd::REPLACE) )
2084
0
        {
2085
0
            bFirst = false;
2086
0
            GetFrameWin()->LeaveWait();
2087
0
            if (!bIsApi)
2088
0
            {
2089
0
                if ( nStartTab == nEndTab )
2090
0
                    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::EndSheet);
2091
0
                else
2092
0
                    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
2093
2094
0
                rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
2095
0
                if (pSearchItem->GetBackward())
2096
0
                    nTab = nEndTab;
2097
0
                else
2098
0
                    nTab = nStartTab;
2099
0
            }
2100
0
            else
2101
0
            {
2102
0
                break;                  // break 'while (TRUE)'
2103
0
            }
2104
0
        }
2105
0
        else                            // nothing found
2106
0
        {
2107
0
            if ( nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL )
2108
0
            {
2109
0
                pDocSh->PostPaintGridAll();                             // Mark
2110
0
            }
2111
2112
0
            GetFrameWin()->LeaveWait();
2113
0
            if (!bIsApi)
2114
0
            {
2115
0
                GetViewData().GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, pSearchItem->GetSearchString().toUtf8());
2116
0
                SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
2117
0
            }
2118
2119
0
            break;                      // break 'while (TRUE)'
2120
0
        }
2121
0
    }                               // of while true
2122
2123
0
    if (!aOldSelectedTables.empty())
2124
0
    {
2125
        // restore originally selected table
2126
0
        for (SCTAB i = 0; i <= nEndTab; ++i)
2127
0
            rMark.SelectTable(i, false);
2128
2129
0
        for (const auto& rTab : aOldSelectedTables)
2130
0
            rMark.SelectTable(rTab, true);
2131
2132
0
        if ( bFound )
2133
0
        {   // if a table is selected as a "match" it remains selected.
2134
0
            rMark.SelectTable( nTab, true );
2135
            // It's a swap if only one table was selected before
2136
            //! otherwise now one table more might be selected
2137
0
            if ( aOldSelectedTables.size() == 1 && nTab != nOldTab )
2138
0
                rMark.SelectTable( nOldTab, false );
2139
0
        }
2140
0
    }
2141
2142
    // Avoid LOK selection notifications before we have all the results.
2143
0
    GetViewData().GetViewShell()->setTiledSearching(true);
2144
0
    MarkDataChanged();
2145
0
    GetViewData().GetViewShell()->setTiledSearching(false);
2146
2147
0
    if ( bFound )
2148
0
    {
2149
0
        if ( nTab != GetViewData().CurrentTabForData() )
2150
0
            SetTabNo( nTab );
2151
2152
        //  if nothing is marked, DoneBlockMode, then marking can start
2153
        //  directly from this place via Shift-Cursor
2154
0
        if (!rMark.IsMarked() && !rMark.IsMultiMarked())
2155
0
            DoneBlockMode(true);
2156
2157
0
        AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
2158
0
        SetCursor( nCol, nRow, true );
2159
2160
0
        if (comphelper::LibreOfficeKit::isActive())
2161
0
        {
2162
0
            Point aCurPos = GetViewData().GetScrPos(nCol, nRow, GetViewData().GetActivePart());
2163
2164
            // just update the cell selection
2165
0
            ScGridWindow* pGridWindow = GetViewData().GetActiveWin();
2166
            // Don't move cell selection handles for find-all: selection of all but the first result would be lost.
2167
0
            if (pGridWindow && nCommand == SvxSearchCmd::FIND)
2168
0
            {
2169
                // move the cell selection handles
2170
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_RESET, aCurPos.X(), aCurPos.Y());
2171
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aCurPos.X(), aCurPos.Y());
2172
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aCurPos.X(), aCurPos.Y());
2173
0
            }
2174
2175
0
            if (pGridWindow)
2176
0
            {
2177
0
                std::vector<tools::Rectangle> aLogicRects;
2178
0
                pGridWindow->GetCellSelection(aLogicRects);
2179
2180
0
                boost::property_tree::ptree aTree;
2181
0
                aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr());
2182
0
                aTree.put("highlightAll", nCommand == SvxSearchCmd::FIND_ALL);
2183
2184
0
                boost::property_tree::ptree aSelections;
2185
0
                for (const tools::Rectangle& rLogicRect : aLogicRects)
2186
0
                {
2187
0
                    boost::property_tree::ptree aSelection;
2188
0
                    aSelection.put("part", OString::number(nTab).getStr());
2189
0
                    aSelection.put("rectangles", rLogicRect.toString().getStr());
2190
0
                    aSelections.push_back(std::make_pair("", aSelection));
2191
0
                }
2192
0
                aTree.add_child("searchResultSelection", aSelections);
2193
2194
0
                std::stringstream aStream;
2195
0
                boost::property_tree::write_json(aStream, aTree);
2196
0
                OString aPayload( aStream.str() );
2197
0
                SfxViewShell* pViewShell = GetViewData().GetViewShell();
2198
0
                pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload);
2199
2200
                // Trigger LOK_CALLBACK_TEXT_SELECTION now.
2201
0
                MarkDataChanged();
2202
0
            }
2203
0
        }
2204
2205
0
        if (   nCommand == SvxSearchCmd::REPLACE
2206
0
            || nCommand == SvxSearchCmd::REPLACE_ALL )
2207
0
        {
2208
0
            if ( nCommand == SvxSearchCmd::REPLACE )
2209
0
            {
2210
0
                pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid );
2211
2212
                // jump to next cell if we replaced everything in the cell
2213
                // where the cursor was positioned (but avoid switching tabs)
2214
0
                if ( nCol == nOldCol && nRow == nOldRow && nTab == nOldTab )
2215
0
                {
2216
0
                    SvxSearchItem aSearchItem = ScGlobal::GetSearchItem();
2217
0
                    aSearchItem.SetCommand(SvxSearchCmd::FIND);
2218
0
                    aSearchItem.SetWhich(SID_SEARCH_ITEM);
2219
2220
0
                    ScRangeList aMatchedRanges;
2221
0
                    bool bMatchedRangesWereClamped;
2222
0
                    ScTable::UpdateSearchItemAddressForReplace( aSearchItem, nCol, nRow );
2223
0
                    if ( rDoc.SearchAndReplace( aSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, nullptr, bMatchedRangesWereClamped ) &&
2224
0
                            ( nTab == nOldTab ) &&
2225
0
                            ( nCol != nOldCol || nRow != nOldRow ) )
2226
0
                    {
2227
0
                        AlignToCursor(nCol, nRow, SC_FOLLOW_JUMP);
2228
0
                        SetCursor( nCol, nRow, true );
2229
0
                    }
2230
0
                }
2231
0
            }
2232
0
            else
2233
0
                pDocSh->PostPaintGridAll();
2234
0
            pDocSh->SetDocumentModified();
2235
0
        }
2236
0
        else if ( nCommand == SvxSearchCmd::FIND_ALL )
2237
0
            pDocSh->PostPaintGridAll();                             // mark
2238
0
        GetFrameWin()->LeaveWait();
2239
0
    }
2240
0
    else if (bCursorMoved)
2241
0
    {
2242
0
        SetCursor(nOrigPosX, nOrigPosY, true);
2243
0
    }
2244
0
    return bFound;
2245
0
}
2246
2247
// Goal Seek
2248
2249
void ScViewFunc::Solve( const ScSolveParam& rParam )
2250
0
{
2251
0
    ScDocument& rDoc = GetViewData().GetDocument();
2252
2253
0
    SCCOL nDestCol = rParam.aRefVariableCell.Col();
2254
0
    SCROW nDestRow = rParam.aRefVariableCell.Row();
2255
0
    SCTAB nDestTab = rParam.aRefVariableCell.Tab();
2256
2257
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nDestTab, nDestCol, nDestRow, nDestCol, nDestRow);
2258
0
    if (!aTester.IsEditable())
2259
0
    {
2260
0
        ErrorMessage(aTester.GetMessageId());
2261
0
        return;
2262
0
    }
2263
2264
0
    OUString  aTargetValStr;
2265
0
    if ( rParam.pStrTargetVal )
2266
0
        aTargetValStr = *rParam.pStrTargetVal;
2267
2268
0
    OUString  aMsgStr;
2269
0
    OUString  aResStr;
2270
0
    double  nSolveResult;
2271
0
    GetFrameWin()->EnterWait();
2272
2273
0
    bool    bExact =
2274
0
                rDoc.Solver(
2275
0
                    rParam.aRefFormulaCell.Col(),
2276
0
                    rParam.aRefFormulaCell.Row(),
2277
0
                    rParam.aRefFormulaCell.Tab(),
2278
0
                    nDestCol, nDestRow, nDestTab,
2279
0
                    aTargetValStr,
2280
0
                    nSolveResult);
2281
2282
0
    GetFrameWin()->LeaveWait();
2283
2284
0
    SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2285
0
    sal_uLong nFormat = 0;
2286
0
    const ScPatternAttr* pPattern = rDoc.GetPattern( nDestCol, nDestRow, nDestTab );
2287
0
    if ( pPattern )
2288
0
        nFormat = pPattern->GetNumberFormat( pFormatter );
2289
0
    const Color* p;
2290
0
    pFormatter->GetOutputString( nSolveResult, nFormat, aResStr, &p );
2291
2292
0
    if ( bExact )
2293
0
    {
2294
0
        aMsgStr += ScResId( STR_MSSG_SOLVE_0 ) +
2295
0
            aResStr +
2296
0
            ScResId( STR_MSSG_SOLVE_1 );
2297
0
    }
2298
0
    else
2299
0
    {
2300
0
        aMsgStr  = ScResId( STR_MSSG_SOLVE_2 ) +
2301
0
            ScResId( STR_MSSG_SOLVE_3 ) +
2302
0
            aResStr +
2303
0
            ScResId( STR_MSSG_SOLVE_4 );
2304
0
    }
2305
2306
0
    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
2307
0
                                              VclMessageType::Question, VclButtonsType::YesNo, aMsgStr));
2308
0
    xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0));
2309
0
    xBox->set_default_response(RET_NO);
2310
0
    int nResponse = xBox->run();
2311
0
    if (nResponse == RET_YES)
2312
0
        EnterValue( nDestCol, nDestRow, nDestTab, nSolveResult );
2313
2314
0
    GetViewData().GetViewShell()->UpdateInputHandler( true );
2315
0
}
2316
2317
//  multi operation
2318
2319
void ScViewFunc::TabOp( const ScTabOpParam& rParam, bool bRecord )
2320
0
{
2321
0
    ScRange aRange;
2322
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
2323
0
    {
2324
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
2325
0
        ScMarkData& rMark = GetViewData().GetMarkData();
2326
0
        pDocSh->GetDocFunc().TabOp( aRange, &rMark, rParam, bRecord, false );
2327
0
    }
2328
0
    else
2329
0
        ErrorMessage(STR_NOMULTISELECT);
2330
0
}
2331
2332
void ScViewFunc::MakeScenario( const OUString& rName, const OUString& rComment,
2333
                                    const Color& rColor, ScScenarioFlags nFlags )
2334
0
{
2335
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2336
0
    ScMarkData& rMark   = GetViewData().GetMarkData();
2337
0
    SCTAB       nTab    = GetViewData().CurrentTabForData();
2338
2339
0
    SCTAB nNewTab = pDocSh->MakeScenario( nTab, rName, rComment, rColor, nFlags, rMark );
2340
0
    if (nFlags & ScScenarioFlags::CopyAll)
2341
0
        SetTabNo( nNewTab, true );          // ScScenarioFlags::CopyAll -> visible
2342
0
    else
2343
0
    {
2344
0
        SfxBindings& rBindings = GetViewData().GetBindings();
2345
0
        rBindings.Invalidate( SID_STATUS_DOCPOS );      // Statusbar
2346
0
        rBindings.Invalidate( SID_ROWCOL_SELCOUNT );    // Statusbar
2347
0
        rBindings.Invalidate( SID_TABLES_COUNT );
2348
0
        rBindings.Invalidate( SID_SELECT_SCENARIO );
2349
0
        rBindings.Invalidate( FID_TABLE_SHOW );
2350
0
    }
2351
0
}
2352
2353
void ScViewFunc::ExtendScenario()
2354
0
{
2355
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
2356
0
    if (!aTester.IsEditable())
2357
0
    {
2358
0
        ErrorMessage(aTester.GetMessageId());
2359
0
        return;
2360
0
    }
2361
2362
        //  Undo: apply attributes
2363
2364
0
    ScDocument& rDoc = GetViewData().GetDocument();
2365
0
    ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
2366
0
    aPattern.ItemSetPut(ScMergeFlagAttr(ScMF::Scenario));
2367
0
    aPattern.ItemSetPut(ScProtectionAttr(true));
2368
0
    ApplySelectionPattern(aPattern);
2369
0
}
2370
2371
void ScViewFunc::UseScenario( const OUString& rName )
2372
0
{
2373
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2374
0
    SCTAB       nTab    = GetViewData().CurrentTabForData();
2375
2376
0
    DoneBlockMode();
2377
0
    InitOwnBlockMode( ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab));
2378
0
    pDocSh->UseScenario( nTab, rName );
2379
0
}
2380
2381
//  Insert table
2382
2383
bool ScViewFunc::InsertTable( const OUString& rName, SCTAB nTab, bool bRecord )
2384
0
{
2385
    //  Order Table/Name is inverted for DocFunc
2386
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
2387
0
                        InsertTable( nTab, rName, bRecord, false );
2388
0
    if (bSuccess)
2389
0
        SetTabNo( nTab, true );
2390
2391
0
    return bSuccess;
2392
0
}
2393
2394
//  Insert tables
2395
2396
void ScViewFunc::InsertTables(std::vector<OUString>& aNames, SCTAB nTab,
2397
                                            SCTAB nCount, bool bRecord )
2398
0
{
2399
0
    ScDocShell* pDocSh    = GetViewData().GetDocShell();
2400
0
    ScDocument& rDoc     = pDocSh->GetDocument();
2401
0
    if (bRecord && !rDoc.IsUndoEnabled())
2402
0
        bRecord = false;
2403
2404
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2405
2406
0
    if (bRecord)
2407
0
    {
2408
0
        rDoc.BeginDrawUndo();                            //    InsertTab creates a SdrUndoNewPage
2409
0
    }
2410
2411
0
    bool bFlag=false;
2412
2413
0
    if(aNames.empty())
2414
0
    {
2415
0
        rDoc.CreateValidTabNames(aNames, nCount);
2416
0
    }
2417
0
    if (rDoc.InsertTabs(nTab, aNames))
2418
0
    {
2419
0
        pDocSh->Broadcast( ScTablesHint( SC_TABS_INSERTED, nTab, nCount ) );
2420
0
        bFlag = true;
2421
0
    }
2422
2423
0
    if (!bFlag)
2424
0
        return;
2425
2426
0
    if (bRecord)
2427
0
        pDocSh->GetUndoManager()->AddUndoAction(
2428
0
                    std::make_unique<ScUndoInsertTables>( *pDocSh, nTab, std::move(aNames)));
2429
2430
    //    Update views
2431
2432
0
    SetTabNo( nTab, true );
2433
0
    pDocSh->PostPaintExtras();
2434
0
    pDocSh->SetDocumentModified();
2435
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2436
0
}
2437
2438
bool ScViewFunc::AppendTable( const OUString& rName, bool bRecord )
2439
0
{
2440
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2441
0
    ScDocument& rDoc   = pDocSh->GetDocument();
2442
0
    if (bRecord && !rDoc.IsUndoEnabled())
2443
0
        bRecord = false;
2444
2445
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2446
2447
0
    if (bRecord)
2448
0
        rDoc.BeginDrawUndo();                          //  InsertTab creates a SdrUndoNewPage
2449
2450
0
    if (rDoc.InsertTab( SC_TAB_APPEND, rName ))
2451
0
    {
2452
0
        SCTAB nTab = rDoc.GetTableCount()-1;
2453
0
        if (bRecord)
2454
0
            pDocSh->GetUndoManager()->AddUndoAction(
2455
0
                        std::make_unique<ScUndoInsertTab>( *pDocSh, nTab, true, rName));
2456
0
        GetViewData().InsertTab( nTab );
2457
0
        SetTabNo( nTab, true );
2458
0
        pDocSh->PostPaintExtras();
2459
0
        pDocSh->SetDocumentModified();
2460
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2461
0
        return true;
2462
0
    }
2463
0
    else
2464
0
    {
2465
0
        return false;
2466
0
    }
2467
0
}
2468
2469
void ScViewFunc::DeleteTable( SCTAB nTab, bool bRecord )
2470
0
{
2471
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2472
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2473
2474
0
    bool bSuccess = pDocSh->GetDocFunc().DeleteTable( nTab, bRecord );
2475
0
    if (bSuccess)
2476
0
    {
2477
0
        SCTAB nNewTab = nTab;
2478
0
        if ( nNewTab >= rDoc.GetTableCount() )
2479
0
            --nNewTab;
2480
0
        SetTabNo( nNewTab, true );
2481
0
    }
2482
0
}
2483
2484
//only use this method for undo for now, all sheets must be connected
2485
//this method doesn't support undo for now, merge it when it with the other method later
2486
void ScViewFunc::DeleteTables( const SCTAB nTab, SCTAB nSheets )
2487
0
{
2488
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2489
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2490
0
    bool bVbaEnabled = rDoc.IsInVBAMode();
2491
0
    SCTAB       nNewTab = nTab;
2492
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2493
2494
0
    while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
2495
0
        --nNewTab;
2496
2497
0
    if (!rDoc.DeleteTabs(nTab, nSheets))
2498
0
        return;
2499
2500
0
    if( bVbaEnabled )
2501
0
    {
2502
0
        for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
2503
0
        {
2504
0
            OUString sCodeName;
2505
0
            bool bHasCodeName = rDoc.GetCodeName( nTab + aTab, sCodeName );
2506
0
            if ( bHasCodeName )
2507
0
                VBA_DeleteModule( *pDocSh, sCodeName );
2508
0
        }
2509
0
    }
2510
2511
0
    pDocSh->Broadcast( ScTablesHint( SC_TABS_DELETED, nTab, nSheets ) );
2512
0
    if ( nNewTab >= rDoc.GetTableCount() )
2513
0
        nNewTab = rDoc.GetTableCount() - 1;
2514
0
    SetTabNo( nNewTab, true );
2515
2516
0
    pDocSh->PostPaintExtras();
2517
0
    pDocSh->SetDocumentModified();
2518
2519
0
    SfxApplication* pSfxApp = SfxGetpApp();                                // Navigator
2520
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2521
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
2522
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
2523
0
}
2524
2525
bool ScViewFunc::DeleteTables(const std::vector<SCTAB>& rTabs, bool bRecord)
2526
0
{
2527
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2528
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2529
0
    bool bVbaEnabled = rDoc.IsInVBAMode();
2530
0
    SCTAB nNewTab = rTabs.front();
2531
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2532
0
    if (bRecord && !rDoc.IsUndoEnabled())
2533
0
        bRecord = false;
2534
0
    if ( bVbaEnabled )
2535
0
        bRecord = false;
2536
2537
0
    while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
2538
0
        --nNewTab;
2539
2540
0
    bool bWasLinked = false;
2541
0
    ScDocumentUniquePtr pUndoDoc;
2542
0
    std::unique_ptr<ScRefUndoData> pUndoData;
2543
0
    if (bRecord)
2544
0
    {
2545
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2546
0
        SCTAB nCount = rDoc.GetTableCount();
2547
2548
0
        OUString aOldName;
2549
0
        bool isFirstTab = true;
2550
0
        for (SCTAB nTab : rTabs)
2551
0
        {
2552
0
            if (isFirstTab)
2553
0
            {
2554
0
                pUndoDoc->InitUndo( rDoc, nTab,nTab, true,true );   // incl. column/row flags
2555
0
                isFirstTab = false;
2556
0
            }
2557
0
            else
2558
0
                pUndoDoc->AddUndoTab( nTab,nTab, true,true );       // incl. column/row flags
2559
2560
0
            rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL,false, *pUndoDoc );
2561
0
            rDoc.GetName( nTab, aOldName );
2562
0
            pUndoDoc->RenameTab( nTab, aOldName );
2563
0
            if (rDoc.IsLinked(nTab))
2564
0
            {
2565
0
                bWasLinked = true;
2566
0
                pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab),
2567
0
                                    rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
2568
0
                                    rDoc.GetLinkTab(nTab),
2569
0
                                    rDoc.GetLinkRefreshDelay(nTab) );
2570
0
            }
2571
0
            if ( rDoc.IsScenario(nTab) )
2572
0
            {
2573
0
                pUndoDoc->SetScenario( nTab, true );
2574
0
                OUString aComment;
2575
0
                Color  aColor;
2576
0
                ScScenarioFlags nScenFlags;
2577
0
                rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags );
2578
0
                pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
2579
0
                bool bActive = rDoc.IsActiveScenario( nTab );
2580
0
                pUndoDoc->SetActiveScenario( nTab, bActive );
2581
0
            }
2582
0
            pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) );
2583
0
            pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
2584
0
            auto pSheetEvents = rDoc.GetSheetEvents( nTab );
2585
0
            pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
2586
0
            pUndoDoc->SetLayoutRTL( nTab, rDoc.IsLayoutRTL( nTab ) );
2587
2588
0
            if ( rDoc.IsTabProtected( nTab ) )
2589
0
                pUndoDoc->SetTabProtection(nTab, rDoc.GetTabProtection(nTab));
2590
2591
            //  Drawing-Layer is responsible for its Undo  !!!
2592
            //      pUndoDoc->TransferDrawPage(rDoc, nTab,nTab);
2593
0
        }
2594
2595
0
        pUndoDoc->AddUndoTab( 0, nCount-1 );            //  all Tabs for references
2596
2597
        // Deleting these tabs rewrites any formula on another sheet that
2598
        // refers to one of them into a #REF! error. Snapshot that sheet's
2599
        // formulas too, so ScMoveUndo::UndoRef() has the original formula to
2600
        // put back on undo instead of leaving the error in place.
2601
0
        for (SCTAB nOtherTab = 0; nOtherTab < nCount; ++nOtherTab)
2602
0
        {
2603
0
            if (std::find(rTabs.begin(), rTabs.end(), nOtherTab) != rTabs.end())
2604
0
                continue;
2605
0
            rDoc.CopyToDocument(0,0,nOtherTab, rDoc.MaxCol(),rDoc.MaxRow(),nOtherTab,
2606
0
                                 InsertDeleteFlags::FORMULA, false, *pUndoDoc );
2607
0
        }
2608
2609
0
        rDoc.BeginDrawUndo();                          //  DeleteTab creates a SdrUndoDelPage
2610
2611
0
        pUndoData.reset(new ScRefUndoData( rDoc ));
2612
0
    }
2613
2614
0
    bool bDelDone = false;
2615
2616
0
    std::vector<ScTable*> aSheetViewHolderTablesToDelete;
2617
2618
0
    for (sal_Int32 i = rTabs.size() - 1; i >= 0; --i)
2619
0
    {
2620
0
        SCTAB nTab = rTabs[i];
2621
0
        OUString sCodeName;
2622
0
        bool bHasCodeName = rDoc.GetCodeName(nTab, sCodeName);
2623
2624
        // If we delete the current viewed table, make sure that we exit any sheet views
2625
0
        if (GetViewData().GetTabNumber() == nTab && GetViewData().GetSheetViewID() != sc::DefaultSheetViewID)
2626
0
            GetViewData().SetSheetViewID(sc::DefaultSheetViewID);
2627
2628
0
        if (auto pManager = rDoc.GetSheetViewManager(nTab))
2629
0
        {
2630
0
            for (auto const& rSheetView : pManager->iterateValidSheetViews())
2631
0
            {
2632
0
                aSheetViewHolderTablesToDelete.push_back(rSheetView.getTablePointer());
2633
0
            }
2634
0
        }
2635
2636
0
        if (rDoc.DeleteTab(nTab))
2637
0
        {
2638
0
            bDelDone = true;
2639
0
            if( bVbaEnabled && bHasCodeName )
2640
0
            {
2641
0
                VBA_DeleteModule( *pDocSh, sCodeName );
2642
0
            }
2643
0
            pDocSh->Broadcast( ScTablesHint(SC_TAB_DELETED, nTab) );
2644
0
        }
2645
0
    }
2646
2647
    // Delete sheet view holder tables if it's table has been deleted
2648
0
    for (auto* pTable : aSheetViewHolderTablesToDelete)
2649
0
    {
2650
0
        SCTAB nTab = pTable->GetTab();
2651
0
        if (rDoc.DeleteTab(nTab))
2652
0
        {
2653
0
            pDocSh->Broadcast(ScTablesHint(SC_TAB_DELETED, nTab));
2654
0
        }
2655
0
    }
2656
2657
0
    if (bRecord)
2658
0
    {
2659
0
        pDocSh->GetUndoManager()->AddUndoAction(
2660
0
                    std::make_unique<ScUndoDeleteTab>( *GetViewData().GetDocShell(), rTabs,
2661
0
                                            std::move(pUndoDoc), std::move(pUndoData) ));
2662
0
    }
2663
2664
0
    if (bDelDone)
2665
0
    {
2666
0
        if ( nNewTab >= rDoc.GetTableCount() )
2667
0
            nNewTab = rDoc.GetTableCount() - 1;
2668
2669
0
        SetTabNo( nNewTab, true );
2670
2671
0
        if (bWasLinked)
2672
0
        {
2673
0
            pDocSh->UpdateLinks();              // update Link-Manager
2674
0
            GetViewData().GetBindings().Invalidate(SID_LINKS);
2675
0
        }
2676
2677
0
        pDocSh->PostPaintExtras();
2678
0
        pDocSh->SetDocumentModified();
2679
2680
0
        SfxApplication* pSfxApp = SfxGetpApp();                                // Navigator
2681
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2682
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
2683
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
2684
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
2685
0
    }
2686
0
    return bDelDone;
2687
0
}
2688
2689
bool ScViewFunc::RenameTable( const OUString& rName, SCTAB nTab )
2690
0
{
2691
    //  order Table/Name is inverted for DocFunc
2692
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
2693
0
                        RenameTable( nTab, rName, true, false );
2694
0
    if (bSuccess)
2695
0
    {
2696
        //  the table name might be part of a formula
2697
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2698
0
    }
2699
0
    return bSuccess;
2700
0
}
2701
2702
bool ScViewFunc::SetTabBgColor( const Color& rColor, SCTAB nTab )
2703
0
{
2704
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( nTab, rColor, true, false );
2705
0
    if (bSuccess)
2706
0
    {
2707
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2708
0
    }
2709
0
    return bSuccess;
2710
0
}
2711
2712
bool ScViewFunc::SetTabBgColor( ScUndoTabColorInfo::List& rUndoSetTabBgColorInfoList )
2713
0
{
2714
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( rUndoSetTabBgColorInfoList, false );
2715
0
    if (bSuccess)
2716
0
    {
2717
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2718
0
    }
2719
0
    return bSuccess;
2720
0
}
2721
2722
void ScViewFunc::InsertAreaLink( const OUString& rFile,
2723
                                    const OUString& rFilter, const OUString& rOptions,
2724
                                    const OUString& rSource )
2725
0
{
2726
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2727
0
    SCCOL nPosX = GetViewData().GetCurX();
2728
0
    SCROW nPosY = GetViewData().GetCurY();
2729
0
    SCTAB nTab = GetViewData().CurrentTabForData();
2730
0
    ScAddress aPos( nPosX, nPosY, nTab );
2731
2732
0
    pDocSh->GetDocFunc().InsertAreaLink( rFile, rFilter, rOptions, rSource, ScRange(aPos), 0/*nRefresh*/, false, false );
2733
0
}
2734
2735
void ScViewFunc::InsertTableLink( const OUString& rFile,
2736
                                    const OUString& rFilter, const OUString& rOptions,
2737
                                    std::u16string_view rTabName )
2738
0
{
2739
0
    OUString aFilterName = rFilter;
2740
0
    OUString aOpt = rOptions;
2741
0
    ScDocumentLoader aLoader( rFile, aFilterName, aOpt );
2742
0
    if (aLoader.IsError())
2743
0
        return;
2744
2745
0
    ScDocShell* pSrcSh = aLoader.GetDocShell();
2746
0
    ScDocument& rSrcDoc = pSrcSh->GetDocument();
2747
0
    SCTAB nTab = MAXTAB+1;
2748
0
    if (rTabName.empty())                // no name given -> first table
2749
0
        nTab = 0;
2750
0
    else
2751
0
    {
2752
0
        OUString aTemp;
2753
0
        SCTAB nCount = rSrcDoc.GetTableCount();
2754
0
        for (SCTAB i=0; i<nCount; i++)
2755
0
        {
2756
0
            rSrcDoc.GetName( i, aTemp );
2757
0
            if ( aTemp == rTabName )
2758
0
                nTab = i;
2759
0
        }
2760
0
    }
2761
2762
0
    if ( nTab <= MAXTAB )
2763
0
        ImportTables( pSrcSh, 1, &nTab, true,
2764
0
                    GetViewData().CurrentTabForData() );
2765
0
}
2766
2767
//  Copy/link tables from another document
2768
2769
void ScViewFunc::ImportTables( ScDocShell* pSrcShell,
2770
                                SCTAB nCount, const SCTAB* pSrcTabs, bool bLink,SCTAB nTab )
2771
0
{
2772
0
    ScDocument& rSrcDoc = pSrcShell->GetDocument();
2773
2774
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2775
0
    ScDocument& rDoc = pDocSh->GetDocument();
2776
0
    bool bUndo(rDoc.IsUndoEnabled());
2777
2778
0
    bool bError = false;
2779
2780
0
    if (rSrcDoc.GetDrawLayer())
2781
0
        pDocSh->MakeDrawLayer();
2782
2783
0
    if (bUndo)
2784
0
        rDoc.BeginDrawUndo();          // drawing layer must do its own undo actions
2785
2786
0
    SCTAB nInsCount = 0;
2787
0
    SCTAB i;
2788
0
    for( i=0; i<nCount; i++ )
2789
0
    {   // insert sheets first and update all references
2790
0
        OUString aName;
2791
0
        rSrcDoc.GetName( pSrcTabs[i], aName );
2792
0
        rDoc.CreateValidTabName( aName );
2793
0
        if ( !rDoc.InsertTab( nTab+i, aName ) )
2794
0
        {
2795
0
            bError = true;      // total error
2796
0
            break;  // for
2797
0
        }
2798
0
        ++nInsCount;
2799
0
    }
2800
0
    for (i=0; i<nCount && !bError; i++)
2801
0
    {
2802
0
        SCTAB nSrcTab = pSrcTabs[i];
2803
0
        SCTAB nDestTab1=nTab+i;
2804
0
        bool bValid = pDocSh->TransferTab( *pSrcShell, nSrcTab, nDestTab1,
2805
0
            false, false );     // no insert
2806
2807
0
        if (!bValid)
2808
0
        {
2809
0
            bError = true;
2810
0
        }
2811
2812
0
    }
2813
2814
0
    if (bLink)
2815
0
    {
2816
0
        sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
2817
2818
0
        SfxMedium* pMed = pSrcShell->GetMedium();
2819
0
        OUString aFileName = pMed->GetName();
2820
0
        OUString aFilterName;
2821
0
        if (pMed->GetFilter())
2822
0
            aFilterName = pMed->GetFilter()->GetFilterName();
2823
0
        OUString aOptions = ScDocumentLoader::GetOptions(*pMed);
2824
2825
0
        bool bWasThere = rDoc.HasLink( aFileName, aFilterName, aOptions );
2826
2827
0
        sal_uLong nRefresh = 0;
2828
0
        OUString aTabStr;
2829
0
        for (i=0; i<nInsCount; i++)
2830
0
        {
2831
0
            rSrcDoc.GetName( pSrcTabs[i], aTabStr );
2832
0
            rDoc.SetLink( nTab+i, ScLinkMode::NORMAL,
2833
0
                        aFileName, aFilterName, aOptions, aTabStr, nRefresh );
2834
0
        }
2835
2836
0
        if (!bWasThere)         // Insert link only once per source document
2837
0
        {
2838
0
            ScTableLink* pLink = new ScTableLink( *pDocSh, aFileName, aFilterName, aOptions, nRefresh );
2839
0
            pLink->SetInCreate( true );
2840
0
            pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilterName );
2841
0
            pLink->Update();
2842
0
            pLink->SetInCreate( false );
2843
2844
0
            SfxBindings& rBindings = GetViewData().GetBindings();
2845
0
            rBindings.Invalidate( SID_LINKS );
2846
0
        }
2847
0
    }
2848
2849
0
    if (bUndo)
2850
0
    {
2851
0
        pDocSh->GetUndoManager()->AddUndoAction(
2852
0
                std::make_unique<ScUndoImportTab>( *pDocSh, nTab, nCount ) );
2853
0
    }
2854
2855
0
    for (i=0; i<nInsCount; i++)
2856
0
        GetViewData().InsertTab(nTab);
2857
0
    SetTabNo(nTab,true);
2858
0
    pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
2859
0
                                PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
2860
2861
0
    SfxApplication* pSfxApp = SfxGetpApp();
2862
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2863
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
2864
2865
0
    pDocSh->PostPaintExtras();
2866
0
    pDocSh->PostPaintGridAll();
2867
0
    pDocSh->SetDocumentModified();
2868
0
}
2869
2870
//  Move/Copy table to another document
2871
2872
void ScViewFunc::MoveTable(sal_uInt16 nDestDocNo, SCTAB nDestTab, bool bCopy,
2873
                           const OUString* pNewTabName, bool bContextMenu,
2874
                           SCTAB nContextMenuSourceTab)
2875
0
{
2876
0
    ScDocument& rDoc       = GetViewData().GetDocument();
2877
0
    ScDocShell* pDocShell  = GetViewData().GetDocShell();
2878
0
    ScDocShell* pDestShell = nullptr;
2879
0
    ScTabViewShell* pDestViewSh = nullptr;
2880
0
    bool bUndo (rDoc.IsUndoEnabled());
2881
0
    bool bRename = pNewTabName && !pNewTabName->isEmpty();
2882
2883
0
    bool bNewDoc = (nDestDocNo == SC_DOC_NEW);
2884
0
    if ( bNewDoc )
2885
0
    {
2886
0
        nDestTab = 0;           // firstly insert
2887
2888
        //  execute without SfxCallMode::RECORD, because already contained in move command
2889
2890
0
        SfxStringItem aItem( SID_FILE_NAME, "private:factory/" + STRING_SCAPP );
2891
0
        SfxStringItem aTarget( SID_TARGETNAME, u"_blank"_ustr );
2892
2893
0
        const SfxPoolItemHolder aResult(GetViewData().GetDispatcher().ExecuteList(
2894
0
            SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON,
2895
0
            { &aItem, &aTarget }));
2896
2897
0
        if (aResult)
2898
0
        {
2899
0
            if ( auto pObjectItem = dynamic_cast<const SfxObjectItem*>(aResult.getItem()) )
2900
0
                pDestShell = dynamic_cast<ScDocShell*>( pObjectItem->GetShell()  );
2901
0
            else if ( auto pViewFrameItem = dynamic_cast<const SfxViewFrameItem*>(aResult.getItem()))
2902
0
            {
2903
0
                SfxViewFrame* pFrm = pViewFrameItem->GetFrame();
2904
0
                if (pFrm)
2905
0
                    pDestShell = dynamic_cast<ScDocShell*>( pFrm->GetObjectShell()  );
2906
0
            }
2907
0
            if (pDestShell)
2908
0
                pDestViewSh = pDestShell->GetBestViewShell();
2909
0
        }
2910
0
    }
2911
0
    else
2912
0
        pDestShell = ScDocShell::GetShellByNum( nDestDocNo );
2913
2914
0
    if (!pDestShell)
2915
0
    {
2916
0
        OSL_FAIL("Destination document not found !!!");
2917
0
        return;
2918
0
    }
2919
2920
0
    ScMarkData& rMark = GetViewData().GetMarkData();
2921
0
    if (bRename && rMark.GetSelectCount() != 1)
2922
0
    {
2923
        // Custom sheet name is provided, but more than one sheet is selected.
2924
        // We don't support this scenario at the moment.
2925
0
        return;
2926
0
    }
2927
2928
0
    ScDocument& rDestDoc = pDestShell->GetDocument();
2929
2930
0
    if (&rDestDoc != &rDoc)
2931
0
    {
2932
0
        if (bNewDoc)
2933
0
        {
2934
0
            while (rDestDoc.GetTableCount() > 1)
2935
0
                rDestDoc.DeleteTab(0);
2936
0
            rDestDoc.RenameTab( 0, u"______42_____"_ustr );
2937
0
        }
2938
2939
0
        SCTAB       nTabCount   = rDoc.GetTableCount();
2940
0
        SCTAB       nTabSelCount = rMark.GetSelectCount();
2941
2942
0
        std::vector<SCTAB> TheTabs;
2943
2944
0
        for(SCTAB i=0; i<nTabCount; ++i)
2945
0
        {
2946
0
            if(rMark.GetTableSelect(i))
2947
0
            {
2948
0
                OUString aTabName;
2949
0
                rDoc.GetName( i, aTabName);
2950
0
                TheTabs.push_back(i);
2951
0
                for(SCTAB j=i+1;j<nTabCount;j++)
2952
0
                {
2953
0
                    if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
2954
0
                    {
2955
0
                        rDoc.GetName( j, aTabName);
2956
0
                        TheTabs.push_back(j);
2957
0
                        i=j;
2958
0
                    }
2959
0
                    else break;
2960
0
                }
2961
0
            }
2962
0
        }
2963
2964
0
        GetFrameWin()->EnterWait();
2965
2966
0
        if (rDoc.GetDrawLayer())
2967
0
            pDestShell->MakeDrawLayer();
2968
2969
0
        if (!bNewDoc && bUndo)
2970
0
            rDestDoc.BeginDrawUndo();      // drawing layer must do its own undo actions
2971
2972
0
        bool bValid = true;
2973
0
        if(nDestTab==SC_TAB_APPEND)
2974
0
            nDestTab=rDestDoc.GetTableCount();
2975
0
        SCTAB nDestTab1=nDestTab;
2976
0
        ScClipParam aParam;
2977
0
        for( size_t j=0; j<TheTabs.size(); ++j, ++nDestTab1 )
2978
0
        {   // insert sheets first and update all references
2979
0
            OUString aName;
2980
0
            if (bRename)
2981
0
                aName = *pNewTabName;
2982
0
            else
2983
0
                rDoc.GetName( TheTabs[j], aName );
2984
2985
0
            rDestDoc.CreateValidTabName( aName );
2986
0
            if ( !rDestDoc.InsertTab( nDestTab1, aName ) )
2987
0
            {
2988
0
                bValid = false;        // total error
2989
0
                break;  // for
2990
0
            }
2991
0
            ScRange aRange( 0, 0, TheTabs[j], rDoc.MaxCol(), rDoc.MaxRow(), TheTabs[j] );
2992
0
            aParam.maRanges.push_back(aRange);
2993
0
        }
2994
0
        rDoc.SetClipParam(aParam);
2995
0
        if ( bValid )
2996
0
        {
2997
0
            nDestTab1 = nDestTab;
2998
0
            for(SCTAB nTab : TheTabs)
2999
0
            {
3000
0
                bValid = pDestShell->TransferTab( *pDocShell, nTab, nDestTab1, false, false );
3001
0
                nDestTab1++;
3002
0
            }
3003
0
        }
3004
0
        if (!bNewDoc && bUndo)
3005
0
        {
3006
0
            OUString sName;
3007
0
            rDestDoc.GetName(nDestTab, sName);
3008
0
            pDestShell->GetUndoManager()->AddUndoAction(
3009
0
                            std::make_unique<ScUndoImportTab>( *pDestShell, nDestTab,
3010
0
                                static_cast<SCTAB>(TheTabs.size())));
3011
3012
0
        }
3013
0
        else
3014
0
        {
3015
0
            pDestShell->GetUndoManager()->Clear();
3016
0
        }
3017
3018
0
        GetFrameWin()->LeaveWait();
3019
3020
0
        if (!bValid)
3021
0
        {
3022
0
            ErrorMessage(STR_TABINSERT_ERROR);
3023
0
            return;
3024
0
        }
3025
3026
0
        if (!bCopy)
3027
0
        {
3028
0
            if(nTabCount!=nTabSelCount)
3029
0
                DeleteTables(TheTabs); // incl. Paint & Undo
3030
0
            else
3031
0
                ErrorMessage(STR_TABREMOVE_ERROR);
3032
0
        }
3033
3034
0
        if (bNewDoc)
3035
0
        {
3036
            //  ChartListenerCollection must be updated before DeleteTab
3037
0
            if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
3038
0
                rDestDoc.UpdateChartListenerCollection();
3039
3040
0
            SCTAB nNumTabsInserted = static_cast<SCTAB>(TheTabs.size());
3041
0
            pDestShell->Broadcast( ScTablesHint( SC_TABS_INSERTED, 0, nNumTabsInserted ) );
3042
3043
0
            rDestDoc.DeleteTab( nNumTabsInserted );   // old first table
3044
0
            pDestShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nNumTabsInserted ) );
3045
3046
0
            if (pDestViewSh)
3047
0
            {
3048
                // Make sure to clear the cached page view after sheet
3049
                // deletion, which still points to the sdr page belonging to
3050
                // the deleted sheet.
3051
0
                SdrView* pSdrView = pDestViewSh->GetScDrawView();
3052
0
                if (pSdrView)
3053
0
                    pSdrView->ClearPageView();
3054
3055
0
                pDestViewSh->TabChanged();      // pages on the drawing layer
3056
0
            }
3057
0
            pDestShell->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
3058
0
                                    PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left |
3059
0
                                    PaintPartFlags::Extras | PaintPartFlags::Size );
3060
            //  PaintPartFlags::Size for outline
3061
0
        }
3062
0
        else
3063
0
        {
3064
0
            pDestShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestTab ) );
3065
0
            pDestShell->PostPaintExtras();
3066
0
            pDestShell->PostPaintGridAll();
3067
0
        }
3068
3069
0
        TheTabs.clear();
3070
3071
0
        pDestShell->SetDocumentModified();
3072
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3073
0
    }
3074
0
    else
3075
0
    {
3076
        // Move or copy within the same document.
3077
0
        SCTAB       nTabCount   = rDoc.GetTableCount();
3078
3079
0
        std::unique_ptr<std::vector<SCTAB>> pSrcTabs(new std::vector<SCTAB>);
3080
0
        std::unique_ptr<std::vector<SCTAB>> pDestTabs(new std::vector<SCTAB>);
3081
0
        std::unique_ptr<std::vector<OUString>> pTabNames(new std::vector<OUString>);
3082
0
        std::unique_ptr<std::vector<OUString>> pDestNames;
3083
0
        pSrcTabs->reserve(nTabCount);
3084
0
        pDestTabs->reserve(nTabCount);
3085
0
        pTabNames->reserve(nTabCount);
3086
0
        OUString aDestName;
3087
3088
0
        if (bContextMenu)
3089
0
        {
3090
0
            OUString aTabName;
3091
0
            rDoc.GetName(nContextMenuSourceTab, aTabName);
3092
0
            pTabNames->push_back(aTabName);
3093
0
        }
3094
0
        else
3095
0
        {
3096
0
            for(SCTAB i=0;i<nTabCount;i++)
3097
0
            {
3098
0
                if(rMark.GetTableSelect(i))
3099
0
                {
3100
0
                    OUString aTabName;
3101
0
                    rDoc.GetName( i, aTabName);
3102
0
                    pTabNames->push_back(aTabName);
3103
3104
0
                    for(SCTAB j=i+1;j<nTabCount;j++)
3105
0
                    {
3106
0
                        if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
3107
0
                        {
3108
0
                            rDoc.GetName( j, aTabName);
3109
0
                            pTabNames->push_back(aTabName);
3110
0
                            i=j;
3111
0
                        }
3112
0
                        else break;
3113
0
                    }
3114
0
                }
3115
0
            }
3116
0
        }
3117
3118
0
        if (bCopy && bUndo)
3119
0
            rDoc.BeginDrawUndo();          // drawing layer must do its own undo actions
3120
3121
0
        rDoc.GetName( nDestTab, aDestName);
3122
0
        SCTAB nDestTab1=nDestTab;
3123
0
        SCTAB nMovTab=0;
3124
0
        for (size_t j = 0, n = pTabNames->size(); j < n; ++j)
3125
0
        {
3126
0
            nTabCount   = rDoc.GetTableCount();
3127
0
            const OUString& rStr = (*pTabNames)[j];
3128
0
            if(!rDoc.GetTable(rStr,nMovTab))
3129
0
            {
3130
0
                nMovTab=nTabCount;
3131
0
            }
3132
0
            if(!rDoc.GetTable(aDestName,nDestTab1))
3133
0
            {
3134
0
                nDestTab1=nTabCount;
3135
0
            }
3136
0
            pDocShell->MoveTable( nMovTab, nDestTab1, bCopy, false );   // Undo is here
3137
3138
            // tdf#43175 - Adjust chart references on every copied sheet
3139
0
            if (bCopy)
3140
0
            {
3141
                // New position of source table after moving
3142
0
                SCTAB nSrcTab = (nDestTab1 <= nMovTab) ? nMovTab + 1 : nMovTab;
3143
                //#i29848# adjust references to data on the copied sheet
3144
0
                ScChartHelper::AdjustRangesOfChartsOnDestinationPage(rDoc, rDestDoc, nSrcTab,
3145
0
                                                                     nDestTab1);
3146
0
            }
3147
3148
0
            if(bCopy && rDoc.IsScenario(nMovTab))
3149
0
            {
3150
0
                OUString aComment;
3151
0
                Color  aColor;
3152
0
                ScScenarioFlags nFlags;
3153
3154
0
                rDoc.GetScenarioData(nMovTab, aComment,aColor, nFlags);
3155
0
                rDoc.SetScenario(nDestTab1,true);
3156
0
                rDoc.SetScenarioData(nDestTab1,aComment,aColor,nFlags);
3157
0
                bool bActive = rDoc.IsActiveScenario(nMovTab );
3158
0
                rDoc.SetActiveScenario( nDestTab1, bActive );
3159
0
                bool bVisible=rDoc.IsVisible(nMovTab);
3160
0
                rDoc.SetVisible(nDestTab1,bVisible );
3161
0
            }
3162
3163
0
            pSrcTabs->push_back(nMovTab);
3164
3165
0
            if(!bCopy)
3166
0
            {
3167
0
                if(!rDoc.GetTable(rStr,nDestTab1))
3168
0
                {
3169
0
                    nDestTab1=nTabCount;
3170
0
                }
3171
0
            }
3172
3173
0
            pDestTabs->push_back(nDestTab1);
3174
0
        }
3175
3176
        // Rename must be done after all sheets have been moved.
3177
0
        if (bRename)
3178
0
        {
3179
0
            pDestNames.reset(new std::vector<OUString>);
3180
0
            size_t n = pDestTabs->size();
3181
0
            pDestNames->reserve(n);
3182
0
            for (size_t j = 0; j < n; ++j)
3183
0
            {
3184
0
                SCTAB nRenameTab = (*pDestTabs)[j];
3185
0
                OUString aTabName = *pNewTabName;
3186
0
                rDoc.CreateValidTabName( aTabName );
3187
0
                pDestNames->push_back(aTabName);
3188
0
                rDoc.RenameTab(nRenameTab, aTabName);
3189
0
            }
3190
0
        }
3191
0
        else
3192
            // No need to keep this around when we are not renaming.
3193
0
            pTabNames.reset();
3194
3195
0
        SCTAB nTab = GetViewData().CurrentTabForData();
3196
3197
0
        if (comphelper::LibreOfficeKit::isActive() && !pSrcTabs->empty())
3198
0
        {
3199
0
            ScModelObj* pModel = pDocShell->GetModel();
3200
0
            SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
3201
0
        }
3202
3203
0
        if (bUndo)
3204
0
        {
3205
0
            if (bCopy)
3206
0
            {
3207
0
                pDocShell->GetUndoManager()->AddUndoAction(
3208
0
                        std::make_unique<ScUndoCopyTab>(
3209
0
                            *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pDestNames)));
3210
0
            }
3211
0
            else
3212
0
            {
3213
0
                pDocShell->GetUndoManager()->AddUndoAction(
3214
0
                        std::make_unique<ScUndoMoveTab>(
3215
0
                            *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pTabNames), std::move(pDestNames)));
3216
0
            }
3217
0
        }
3218
3219
0
        if (bContextMenu)
3220
0
        {
3221
0
            for (SCTAB i = 0; i < nTabCount; i++)
3222
0
            {
3223
0
                if (rMark.GetTableSelect(i))
3224
0
                    SetTabNo(i, true);
3225
0
            }
3226
0
        }
3227
0
        else
3228
0
        {
3229
0
            SCTAB nNewTab = nDestTab;
3230
0
            if (nNewTab == SC_TAB_APPEND)
3231
0
                nNewTab = rDoc.GetTableCount() - 1;
3232
0
            else if (!bCopy && nTab < nDestTab)
3233
0
                nNewTab--;
3234
3235
0
            SetTabNo(nNewTab, true);
3236
0
        }
3237
0
    }
3238
0
}
3239
3240
void ScViewFunc::ShowTable( const std::vector<OUString>& rNames )
3241
0
{
3242
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
3243
0
    ScDocument& rDoc = pDocSh->GetDocument();
3244
0
    bool bUndo(rDoc.IsUndoEnabled());
3245
3246
0
    std::vector<SCTAB> undoTabs;
3247
0
    SCTAB nPos = 0;
3248
3249
0
    bool bFound(false);
3250
3251
0
    for (const OUString& aName : rNames)
3252
0
    {
3253
0
        if (rDoc.GetTable(aName, nPos))
3254
0
        {
3255
0
            rDoc.SetVisible( nPos, true );
3256
0
            SetTabNo( nPos, true );
3257
0
            SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3258
0
            if (!bFound)
3259
0
                bFound = true;
3260
0
            if (bUndo)
3261
0
                undoTabs.push_back(nPos);
3262
0
        }
3263
0
    }
3264
0
    if (bFound)
3265
0
    {
3266
0
        if (bUndo)
3267
0
        {
3268
0
            pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), true ) );
3269
0
        }
3270
0
        pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
3271
0
        pDocSh->SetDocumentModified();
3272
0
    }
3273
0
}
3274
3275
void ScViewFunc::HideTable( const ScMarkData& rMark, SCTAB nTabToSelect )
3276
0
{
3277
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
3278
0
    ScDocument& rDoc = pDocSh->GetDocument();
3279
0
    bool bUndo(rDoc.IsUndoEnabled());
3280
0
    SCTAB nVisible = 0;
3281
0
    SCTAB nTabCount = rDoc.GetTableCount();
3282
3283
0
    SCTAB nTabSelCount = rMark.GetSelectCount();
3284
3285
    // check to make sure we won't hide all sheets. we need at least one visible at all times.
3286
0
    for ( SCTAB i=0; i < nTabCount && nVisible <= nTabSelCount ; i++ )
3287
0
        if (rDoc.IsVisible(i))
3288
0
            ++nVisible;
3289
3290
0
    if (nVisible <= nTabSelCount)
3291
0
        return;
3292
3293
0
    std::vector<SCTAB> undoTabs;
3294
3295
    // need to take a copy of selectedtabs since it is modified in the loop
3296
0
    const ScMarkData::MarkedTabsType selectedTabs = rMark.GetSelectedTabs();
3297
0
    for (const SCTAB& nTab : selectedTabs)
3298
0
    {
3299
0
        if (rDoc.IsVisible( nTab ))
3300
0
        {
3301
0
            rDoc.SetVisible( nTab, false );
3302
            // Update views
3303
0
            pDocSh->Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
3304
0
            SetTabNo( nTab, true );
3305
            // Store for undo
3306
0
            if (bUndo)
3307
0
                undoTabs.push_back(nTab);
3308
0
        }
3309
0
    }
3310
3311
0
    if (nTabToSelect != -1)
3312
0
        SetTabNo(nTabToSelect);
3313
3314
0
    if (bUndo)
3315
0
    {
3316
0
        pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), false ) );
3317
0
    }
3318
3319
    //  Update views
3320
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3321
0
    pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
3322
0
    pDocSh->SetDocumentModified();
3323
0
}
3324
3325
void ScViewFunc::InsertSpecialChar( const OUString& rStr, const vcl::Font& rFont )
3326
0
{
3327
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
3328
0
    if (!aTester.IsEditable())
3329
0
    {
3330
0
        ErrorMessage(aTester.GetMessageId());
3331
0
        return;
3332
0
    }
3333
3334
0
    const sal_Unicode* pChar    = rStr.getStr();
3335
0
    ScTabViewShell* pViewShell  = GetViewData().GetViewShell();
3336
0
    SvxFontItem     aFontItem( rFont.GetFamilyType(),
3337
0
                               rFont.GetFamilyName(),
3338
0
                               rFont.GetStyleName(),
3339
0
                               rFont.GetPitch(),
3340
0
                               rFont.GetCharSet(),
3341
0
                               ATTR_FONT );
3342
3343
    //  if string contains WEAK characters, set all fonts
3344
0
    SvtScriptType nScript;
3345
0
    ScDocument& rDoc = GetViewData().GetDocument();
3346
0
    if ( rDoc.HasStringWeakCharacters( rStr ) )
3347
0
        nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
3348
0
    else
3349
0
        nScript = rDoc.GetStringScriptType( rStr );
3350
3351
0
    SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, pViewShell->GetPool() );
3352
0
    aSetItem.PutItemForScriptType( nScript, aFontItem );
3353
0
    ApplyUserItemSet( aSetItem.GetItemSet() );
3354
3355
0
    while ( *pChar )
3356
0
        pViewShell->TabKeyInput( KeyEvent( *(pChar++), vcl::KeyCode() ) );
3357
0
}
3358
3359
void ScViewFunc::UpdateLineAttrs( SvxBorderLine&       rLine,
3360
                                  const SvxBorderLine* pDestLine,
3361
                                  const SvxBorderLine* pSrcLine,
3362
                                  bool                 bColor )
3363
0
{
3364
0
    if ( !(pSrcLine && pDestLine) )
3365
0
        return;
3366
3367
0
    if ( bColor )
3368
0
    {
3369
0
        rLine.SetColor      ( pSrcLine->GetColor() );
3370
0
        rLine.SetBorderLineStyle(pDestLine->GetBorderLineStyle());
3371
0
        rLine.SetWidth      ( pDestLine->GetWidth() );
3372
0
    }
3373
0
    else
3374
0
    {
3375
0
        rLine.SetColor      ( pDestLine->GetColor() );
3376
0
        rLine.SetBorderLineStyle(pSrcLine->GetBorderLineStyle());
3377
0
        rLine.SetWidth      ( pSrcLine->GetWidth() );
3378
0
    }
3379
0
}
3380
3381
#define SET_LINE_ATTRIBUTES(LINE,BOXLINE) \
3382
0
    pBoxLine = aBoxItem.Get##LINE();                                \
3383
0
    if ( pBoxLine )                                                 \
3384
0
    {                                                               \
3385
0
        if ( pLine )                                                \
3386
0
        {                                                           \
3387
0
            UpdateLineAttrs( aLine, pBoxLine, pLine, bColorOnly );  \
3388
0
            aBoxItem.SetLine( &aLine, BOXLINE );                    \
3389
0
        }                                                           \
3390
0
        else                                                        \
3391
0
            aBoxItem.SetLine( nullptr, BOXLINE );                      \
3392
0
    }
3393
3394
void ScViewFunc::SetSelectionFrameLines( const SvxBorderLine* pLine,
3395
                                         bool bColorOnly )
3396
0
{
3397
    // Not editable only due to a matrix? Attribute is ok anyhow.
3398
0
    bool bOnlyNotBecauseOfMatrix;
3399
0
    if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
3400
0
    {
3401
0
        ErrorMessage(STR_PROTECTIONERR);
3402
0
        return;
3403
0
    }
3404
3405
0
    ScDocument& rDoc = GetViewData().GetDocument();
3406
0
    ScMarkData aFuncMark( GetViewData().GetMarkData() );       // local copy for UnmarkFiltered
3407
0
    ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
3408
0
    ScDocShell*             pDocSh = GetViewData().GetDocShell();
3409
0
    const ScPatternAttr*    pSelAttrs = GetSelectionPattern();
3410
0
    const SfxItemSet&       rSelItemSet = pSelAttrs->GetItemSet();
3411
3412
0
    const SfxPoolItem*      pBorderAttr = nullptr;
3413
0
    SfxItemState            eItemState = rSelItemSet.GetItemState( ATTR_BORDER, true, &pBorderAttr );
3414
3415
0
    const SfxPoolItem*      pTLBRItem = nullptr;
3416
0
    SfxItemState            eTLBRState = rSelItemSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
3417
3418
0
    const SfxPoolItem*      pBLTRItem = nullptr;
3419
0
    SfxItemState            eBLTRState = rSelItemSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
3420
3421
    // any of the lines visible?
3422
0
    if( !((eItemState != SfxItemState::DEFAULT) || (eTLBRState != SfxItemState::DEFAULT) || (eBLTRState != SfxItemState::DEFAULT)) )
3423
0
        return;
3424
3425
    // none of the lines don't care?
3426
0
    if( (eItemState != SfxItemState::INVALID) && (eTLBRState != SfxItemState::INVALID) && (eBLTRState != SfxItemState::INVALID) )
3427
0
    {
3428
0
        SfxItemSet aOldSet(SfxItemSet::makeFixedSfxItemSet<ATTR_PATTERN_START, ATTR_PATTERN_END>( *rDoc.GetPool() ));
3429
0
        SfxItemSet aNewSet(SfxItemSet::makeFixedSfxItemSet<ATTR_PATTERN_START, ATTR_PATTERN_END>( *rDoc.GetPool() ));
3430
3431
0
        SvxBorderLine           aLine;
3432
3433
0
        if( pBorderAttr )
3434
0
        {
3435
0
            const SvxBorderLine*    pBoxLine = nullptr;
3436
0
            SvxBoxItem      aBoxItem( *static_cast<const SvxBoxItem*>(pBorderAttr) );
3437
0
            SvxBoxInfoItem  aBoxInfoItem( ATTR_BORDER_INNER );
3438
3439
            // here pBoxLine is used
3440
0
            SET_LINE_ATTRIBUTES(Top,SvxBoxItemLine::TOP)
3441
0
            SET_LINE_ATTRIBUTES(Bottom,SvxBoxItemLine::BOTTOM)
3442
0
            SET_LINE_ATTRIBUTES(Left,SvxBoxItemLine::LEFT)
3443
0
            SET_LINE_ATTRIBUTES(Right,SvxBoxItemLine::RIGHT)
3444
3445
0
            aBoxInfoItem.SetLine( aBoxItem.GetTop(), SvxBoxInfoItemLine::HORI );
3446
0
            aBoxInfoItem.SetLine( aBoxItem.GetLeft(), SvxBoxInfoItemLine::VERT );
3447
0
            aBoxInfoItem.ResetFlags(); // set Lines to Valid
3448
3449
0
            aOldSet.Put( *pBorderAttr );
3450
0
            aNewSet.Put( aBoxItem );
3451
0
            aNewSet.Put( aBoxInfoItem );
3452
0
        }
3453
3454
0
        if( pTLBRItem && static_cast<const SvxLineItem*>(pTLBRItem)->GetLine() )
3455
0
        {
3456
0
            SvxLineItem aTLBRItem( *static_cast<const SvxLineItem*>(pTLBRItem) );
3457
0
            UpdateLineAttrs( aLine, aTLBRItem.GetLine(), pLine, bColorOnly );
3458
0
            aTLBRItem.SetLine( &aLine );
3459
0
            aOldSet.Put( *pTLBRItem );
3460
0
            aNewSet.Put( aTLBRItem );
3461
0
        }
3462
3463
0
        if( pBLTRItem && static_cast<const SvxLineItem*>(pBLTRItem)->GetLine() )
3464
0
        {
3465
0
            SvxLineItem aBLTRItem( *static_cast<const SvxLineItem*>(pBLTRItem) );
3466
0
            UpdateLineAttrs( aLine, aBLTRItem.GetLine(), pLine, bColorOnly );
3467
0
            aBLTRItem.SetLine( &aLine );
3468
0
            aOldSet.Put( *pBLTRItem );
3469
0
            aNewSet.Put( aBLTRItem );
3470
0
        }
3471
3472
0
        ApplyAttributes( aNewSet, aOldSet );
3473
0
    }
3474
0
    else // if ( eItemState == SfxItemState::INVALID )
3475
0
    {
3476
0
        aFuncMark.MarkToMulti();
3477
0
        rDoc.ApplySelectionLineStyle( aFuncMark, pLine, bColorOnly );
3478
0
    }
3479
3480
0
    const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
3481
0
    SCCOL nStartCol = aMarkRange.aStart.Col();
3482
0
    SCROW nStartRow = aMarkRange.aStart.Row();
3483
0
    SCTAB nStartTab = aMarkRange.aStart.Tab();
3484
0
    SCCOL nEndCol = aMarkRange.aEnd.Col();
3485
0
    SCROW nEndRow = aMarkRange.aEnd.Row();
3486
0
    SCTAB nEndTab = aMarkRange.aEnd.Tab();
3487
0
    pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
3488
0
                       nEndCol, nEndRow, nEndTab,
3489
0
                       PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
3490
3491
0
    pDocSh->UpdateOle(GetViewData());
3492
0
    pDocSh->SetDocumentModified();
3493
0
}
3494
3495
#undef SET_LINE_ATTRIBUTES
3496
3497
void ScViewFunc::SetValidation( const ScValidationData& rNew )
3498
0
{
3499
0
    ScDocument& rDoc = GetViewData().GetDocument();
3500
0
    sal_uInt32 nIndex = rDoc.AddValidationEntry(rNew);      // for it there is no Undo
3501
0
    SfxUInt32Item aItem( ATTR_VALIDDATA, nIndex );
3502
3503
0
    ApplyAttr( aItem );         // with Paint and Undo...
3504
0
}
3505
3506
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */