Coverage Report

Created: 2026-08-14 10:22

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