Coverage Report

Created: 2026-04-09 11:41

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/weld.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
    {
1415
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1416
0
        const ScMarkData& rMark = GetViewData().GetMarkData();
1417
0
        bool bSuccess = pDocSh->GetDocFunc().FillSimple( aRange, &rMark, eDir, false );
1418
0
        if (bSuccess)
1419
0
        {
1420
0
            pDocSh->UpdateOle(GetViewData());
1421
0
            UpdateScrollBars();
1422
1423
0
            auto& rDoc = pDocSh->GetDocument();
1424
0
            const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
1425
0
            const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell();
1426
0
            if ( bDoAutoSpell )
1427
0
            {
1428
                // Copy AutoSpellData from above(left/right/below) if no selection.
1429
0
                switch (eDir)
1430
0
                {
1431
0
                    case FILL_TO_BOTTOM:
1432
0
                        if (aRange.aStart.Row() > 0 && aRange.aStart.Row() == aRange.aEnd.Row())
1433
0
                            aRange.aStart.IncRow(-1);
1434
0
                    break;
1435
0
                    case FILL_TO_TOP:
1436
0
                        if (aRange.aEnd.Row() < rDoc.MaxRow() && aRange.aStart.Row() == aRange.aEnd.Row())
1437
0
                            aRange.aEnd.IncRow(1);
1438
0
                    break;
1439
0
                    case FILL_TO_RIGHT:
1440
0
                        if (aRange.aStart.Col() > 0 && aRange.aStart.Col() == aRange.aEnd.Col())
1441
0
                            aRange.aStart.IncCol(-1);
1442
0
                    break;
1443
0
                    case FILL_TO_LEFT:
1444
0
                        if (aRange.aEnd.Col() < rDoc.MaxCol() && aRange.aStart.Col() == aRange.aEnd.Col())
1445
0
                            aRange.aEnd.IncCol(1);
1446
0
                    break;
1447
0
                }
1448
0
                CopyAutoSpellData(eDir, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(),
1449
0
                        ::std::numeric_limits<sal_uLong>::max());
1450
0
            }
1451
1452
            // Invalidate cell slots and update input line with new content.
1453
0
            CellContentChanged();
1454
0
        }
1455
0
    }
1456
0
    else
1457
0
        ErrorMessage(STR_NOMULTISELECT);
1458
0
}
1459
1460
void ScViewFunc::FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
1461
                             double fStart, double fStep, double fMax )
1462
0
{
1463
0
    ScRange aRange;
1464
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1465
0
    {
1466
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1467
0
        const ScMarkData& rMark = GetViewData().GetMarkData();
1468
0
        bool bSuccess = pDocSh->GetDocFunc().
1469
0
                        FillSeries( aRange, &rMark, eDir, eCmd, eDateCmd,
1470
0
                                    fStart, fStep, fMax, false );
1471
0
        if (bSuccess)
1472
0
        {
1473
0
            pDocSh->UpdateOle(GetViewData());
1474
0
            UpdateScrollBars();
1475
1476
0
            HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange);
1477
0
        }
1478
0
    }
1479
0
    else
1480
0
        ErrorMessage(STR_NOMULTISELECT);
1481
0
}
1482
1483
void ScViewFunc::FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
1484
                            SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
1485
0
{
1486
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1487
0
    ScRange aRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab );
1488
0
    ScRange aSourceRange( aRange );
1489
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1490
0
    const ScMarkData& rMark = GetViewData().GetMarkData();
1491
0
    bool bSuccess = pDocSh->GetDocFunc().
1492
0
                    FillAuto( aRange, &rMark, eDir, nCount, false );
1493
0
    if (!bSuccess)
1494
0
        return;
1495
1496
0
    MarkRange( aRange, false );         // aRange was modified in FillAuto
1497
0
    pDocSh->UpdateOle(GetViewData());
1498
0
    UpdateScrollBars();
1499
1500
0
    const ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
1501
0
    const bool bDoAutoSpell = pTabViewShell && pTabViewShell->IsAutoSpell();
1502
0
    if ( bDoAutoSpell )
1503
0
        CopyAutoSpellData(eDir, nStartCol, nStartRow, nEndCol, nEndRow, nCount);
1504
1505
0
    ScModelObj* pModelObj = pDocSh->GetModel();
1506
1507
0
    ScRangeList aChangeRanges;
1508
0
    ScRange aChangeRange( aRange );
1509
0
    switch (eDir)
1510
0
    {
1511
0
        case FILL_TO_BOTTOM:
1512
0
            aChangeRange.aStart.SetRow( aSourceRange.aEnd.Row() + 1 );
1513
0
            break;
1514
0
        case FILL_TO_TOP:
1515
0
            aChangeRange.aEnd.SetRow( aSourceRange.aStart.Row() - 1 );
1516
0
            break;
1517
0
        case FILL_TO_RIGHT:
1518
0
            aChangeRange.aStart.SetCol( aSourceRange.aEnd.Col() + 1 );
1519
0
            break;
1520
0
        case FILL_TO_LEFT:
1521
0
            aChangeRange.aEnd.SetCol( aSourceRange.aStart.Col() - 1 );
1522
0
            break;
1523
0
        default:
1524
0
            break;
1525
0
    }
1526
0
    aChangeRanges.push_back( aChangeRange );
1527
1528
0
    if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
1529
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
1530
0
    else if (pModelObj)
1531
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
1532
0
}
1533
1534
void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
1535
                                   SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
1536
0
{
1537
0
    const ScDocument* pDoc = &GetViewData().GetDocument();
1538
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1539
0
    CellType eCellType;
1540
1541
0
    ScGridWindow* pWin = GetActiveWin();
1542
0
    if ( pWin->InsideVisibleRange(nStartCol, nStartRow) && pWin->InsideVisibleRange(nEndCol, nEndRow) )
1543
0
    {
1544
0
        if ( nCount == ::std::numeric_limits<sal_uLong>::max() )
1545
0
        {
1546
0
            switch( eDir )
1547
0
            {
1548
0
                case FILL_TO_BOTTOM:
1549
0
                    for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1550
0
                    {
1551
0
                        eCellType = pDoc->GetCellType(nColItr, nStartRow, nTab); // We need this optimization only for EditTextObject source cells
1552
0
                        if (eCellType != CELLTYPE_EDIT)
1553
0
                            continue;
1554
1555
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nStartRow);
1556
0
                        if (!aRangeResult.HasRanges())
1557
0
                            continue;
1558
0
                        for ( SCROW nRowItr = nStartRow + 1; nRowItr <= nEndRow; ++nRowItr )
1559
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1560
0
                    }
1561
0
                    break;
1562
0
                case FILL_TO_TOP:
1563
0
                    for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1564
0
                    {
1565
0
                        eCellType = pDoc->GetCellType(nColItr, nEndRow, nTab); // We need this optimization only for EditTextObject source cells
1566
0
                        if (eCellType != CELLTYPE_EDIT)
1567
0
                            continue;
1568
1569
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nColItr, nEndRow);
1570
0
                        if (!aRangeResult.HasRanges())
1571
0
                            continue;
1572
0
                        for ( SCROW nRowItr = nEndRow - 1; nRowItr >= nStartRow; --nRowItr )
1573
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1574
0
                    }
1575
0
                    break;
1576
0
                case FILL_TO_RIGHT:
1577
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1578
0
                    {
1579
0
                        eCellType = pDoc->GetCellType(nStartCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
1580
0
                        if (eCellType != CELLTYPE_EDIT)
1581
0
                            continue;
1582
1583
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nStartCol, nRowItr);
1584
0
                        if (!aRangeResult.HasRanges())
1585
0
                            continue;
1586
0
                        for ( SCCOL nColItr = nStartCol + 1; nColItr <= nEndCol; ++nColItr )
1587
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1588
0
                    }
1589
0
                    break;
1590
0
                case FILL_TO_LEFT:
1591
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1592
0
                    {
1593
0
                        eCellType = pDoc->GetCellType(nEndCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
1594
0
                        if (eCellType != CELLTYPE_EDIT)
1595
0
                            continue;
1596
1597
0
                        sc::MisspellRangeResult aRangeResult = pWin->GetAutoSpellData(nEndCol, nRowItr);
1598
0
                        if (!aRangeResult.HasRanges())
1599
0
                            continue;
1600
0
                        for ( SCCOL nColItr = nEndCol - 1; nColItr >= nStartCol; --nColItr )
1601
0
                            pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1602
0
                    }
1603
0
                    break;
1604
0
            }
1605
0
            return;
1606
0
        }
1607
1608
0
        SCROW nRowRepeatSize = nEndRow - nStartRow + 1;
1609
0
        SCCOL nColRepeatSize = nEndCol - nStartCol + 1;
1610
0
        SCROW nTillRow = 0;
1611
0
        SCCOL nTillCol = 0;
1612
0
        std::vector<std::vector<sc::MisspellRangeResult>> aSourceSpellRanges(nRowRepeatSize, std::vector<sc::MisspellRangeResult>(nColRepeatSize));
1613
1614
0
        for ( SCROW nRowIdx = 0; nRowIdx < nRowRepeatSize; ++nRowIdx )
1615
0
        {
1616
0
            for ( SCCOL nColIdx = 0; nColIdx < nColRepeatSize; ++nColIdx )
1617
0
            {
1618
0
                eCellType = pDoc->GetCellType(nStartCol + nColIdx, nStartRow + nRowIdx, nTab); // We need this optimization only for EditTextObject source cells
1619
0
                if (eCellType != CELLTYPE_EDIT)
1620
0
                    continue;
1621
1622
0
                aSourceSpellRanges[nRowIdx][nColIdx] = pWin->GetAutoSpellData( nStartCol + nColIdx, nStartRow + nRowIdx );
1623
0
            }
1624
0
        }
1625
1626
0
        switch( eDir )
1627
0
        {
1628
0
            case FILL_TO_BOTTOM:
1629
0
                nTillRow = nEndRow + nCount;
1630
0
                for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1631
0
                {
1632
0
                    for ( SCROW nRowItr = nEndRow + 1; nRowItr <= nTillRow; ++nRowItr )
1633
0
                    {
1634
0
                        size_t nSourceRowIdx = ( nRowItr - nEndRow - 1 ) % nRowRepeatSize;
1635
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
1636
0
                        if (!aRangeResult.HasRanges())
1637
0
                            continue;
1638
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1639
0
                    }
1640
0
                }
1641
0
                break;
1642
1643
0
            case FILL_TO_TOP:
1644
0
                nTillRow = nStartRow - nCount;
1645
0
                for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
1646
0
                {
1647
0
                    for ( SCROW nRowItr = nStartRow - 1; nRowItr >= nTillRow; --nRowItr )
1648
0
                    {
1649
0
                        size_t nSourceRowIdx = nRowRepeatSize - 1 - ( ( nStartRow - 1 - nRowItr ) % nRowRepeatSize );
1650
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
1651
0
                        if (!aRangeResult.HasRanges())
1652
0
                            continue;
1653
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1654
0
                    }
1655
0
                }
1656
0
                break;
1657
1658
0
            case FILL_TO_RIGHT:
1659
0
                nTillCol = nEndCol + nCount;
1660
0
                for ( SCCOL nColItr = nEndCol + 1; nColItr <= nTillCol; ++nColItr )
1661
0
                {
1662
0
                    size_t nSourceColIdx = ( nColItr - nEndCol - 1 ) % nColRepeatSize;
1663
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1664
0
                    {
1665
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
1666
0
                        if (!aRangeResult.HasRanges())
1667
0
                            continue;
1668
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1669
0
                    }
1670
0
                }
1671
0
                break;
1672
1673
0
            case FILL_TO_LEFT:
1674
0
                nTillCol = nStartCol - nCount;
1675
0
                for ( SCCOL nColItr = nStartCol - 1; nColItr >= nTillCol; --nColItr )
1676
0
                {
1677
0
                    size_t nSourceColIdx = nColRepeatSize - 1 - ( ( nStartCol - 1 - nColItr ) % nColRepeatSize );
1678
0
                    for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
1679
0
                    {
1680
0
                        sc::MisspellRangeResult aRangeResult = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
1681
0
                        if (!aRangeResult.HasRanges())
1682
0
                            continue;
1683
0
                        pWin->SetAutoSpellData(nColItr, nRowItr, aRangeResult);
1684
0
                    }
1685
0
                }
1686
0
                break;
1687
0
        }
1688
0
    }
1689
0
    else
1690
0
        pWin->ResetAutoSpellForContentChange();
1691
1692
0
}
1693
1694
void ScViewFunc::FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink )
1695
0
{
1696
    //! allow source sheet to be protected
1697
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
1698
0
    if (!aTester.IsEditable())
1699
0
    {
1700
0
        ErrorMessage(aTester.GetMessageId());
1701
0
        return;
1702
0
    }
1703
1704
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1705
0
    ScDocument& rDoc = pDocSh->GetDocument();
1706
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1707
0
    SCTAB nTab = GetViewData().CurrentTabForData();
1708
0
    bool bUndo(rDoc.IsUndoEnabled());
1709
1710
0
    ScRange aMarkRange;
1711
0
    rMark.MarkToSimple();
1712
0
    bool bMulti = rMark.IsMultiMarked();
1713
0
    if (bMulti)
1714
0
        aMarkRange = rMark.GetMultiMarkArea();
1715
0
    else if (rMark.IsMarked())
1716
0
        aMarkRange = rMark.GetMarkArea();
1717
0
    else
1718
0
        aMarkRange = ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
1719
1720
0
    ScDocumentUniquePtr pUndoDoc;
1721
1722
0
    if (bUndo)
1723
0
    {
1724
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1725
0
        pUndoDoc->InitUndo( rDoc, nTab, nTab );
1726
1727
0
        for (const SCTAB& i : rMark)
1728
0
            if (i != nTab )
1729
0
            {
1730
0
                pUndoDoc->AddUndoTab( i, i );
1731
0
                aMarkRange.aStart.SetTab( i );
1732
0
                aMarkRange.aEnd.SetTab( i );
1733
0
                rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc );
1734
0
            }
1735
0
    }
1736
1737
0
    if (bMulti)
1738
0
        rDoc.FillTabMarked( nTab, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
1739
0
    else
1740
0
    {
1741
0
        aMarkRange.aStart.SetTab( nTab );
1742
0
        aMarkRange.aEnd.SetTab( nTab );
1743
0
        rDoc.FillTab( aMarkRange, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
1744
0
    }
1745
1746
0
    if (bUndo)
1747
0
    {   //! for ChangeTrack not until the end
1748
0
        pDocSh->GetUndoManager()->AddUndoAction(
1749
0
            std::make_unique<ScUndoFillTable>( *pDocSh, rMark,
1750
0
                                aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nTab,
1751
0
                                aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab,
1752
0
                                std::move(pUndoDoc), bMulti, nTab, nFlags, nFunction, bSkipEmpty, bAsLink ) );
1753
0
    }
1754
1755
0
    pDocSh->PostPaintGridAll();
1756
0
    pDocSh->PostDataChanged();
1757
0
}
1758
1759
/** Downward fill of selected cell(s) by double-clicking cross-hair cursor
1760
1761
    Either, extends a current selection if non-empty cells exist immediately
1762
    below the selection, overwriting cells below the selection up to the
1763
    minimum row of already filled cells.
1764
1765
    Or, extends a current selection down to the last non-empty cell of an
1766
    adjacent column when the lower-right corner of the selection is
1767
    double-clicked. It uses a left-adjoining non-empty column as a guide if
1768
    such is available, otherwise a right-adjoining non-empty column is used.
1769
1770
    @return No return value
1771
1772
    @see #i12313#
1773
*/
1774
void ScViewFunc::FillCrossDblClick()
1775
0
{
1776
0
    ScRange aRange;
1777
0
    GetViewData().GetSimpleArea( aRange );
1778
0
    aRange.PutInOrder();
1779
1780
0
    SCTAB nTab = GetViewData().GetCurPos().Tab();
1781
0
    SCCOL nStartX = aRange.aStart.Col();
1782
0
    SCROW nStartY = aRange.aStart.Row();
1783
0
    SCCOL nEndX   = aRange.aEnd.Col();
1784
0
    SCROW nEndY   = aRange.aEnd.Row();
1785
1786
0
    ScDocument& rDoc = GetViewData().GetDocument();
1787
1788
0
    if (nEndY >= rDoc.MaxRow())
1789
        // Nothing to fill.
1790
0
        return;
1791
1792
    // Make sure the selection is not empty
1793
0
    if ( rDoc.IsBlockEmpty( nStartX, nStartY, nEndX, nEndY, nTab ) )
1794
0
        return;
1795
1796
    // If there is data in all columns immediately below the selection then
1797
    // switch to overwriting fill.
1798
0
    SCROW nOverWriteEndRow = rDoc.MaxRow();
1799
0
    for (SCCOL nCol = nStartX; nCol <= nEndX; ++nCol)
1800
0
    {
1801
0
        if (rDoc.HasData( nCol, nEndY + 1, nTab))
1802
0
        {
1803
            // Determine the shortest data column to end the fill.
1804
0
            SCROW nY = nEndY + 1;
1805
            // FindAreaPos() returns the start row of the next data block if
1806
            // the current row is the last row of a data block and an empty
1807
            // cell follows. Somewhat unexpected behaviour...
1808
            // So check beforehand if there is one non-empty cell following.
1809
0
            if (rDoc.HasData( nCol, nY + 1, nTab))
1810
0
            {
1811
0
                rDoc.FindAreaPos( nCol, nY, nTab, SC_MOVE_DOWN);
1812
0
                if (nOverWriteEndRow > nY)
1813
0
                    nOverWriteEndRow = nY;
1814
0
            }
1815
0
            else
1816
0
            {
1817
0
                nOverWriteEndRow = nY;
1818
0
            }
1819
0
        }
1820
0
        else
1821
0
        {
1822
0
            nOverWriteEndRow = 0;
1823
0
            break;  // for
1824
0
        }
1825
0
    }
1826
1827
0
    if (nOverWriteEndRow > nEndY)
1828
0
    {
1829
0
        FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nOverWriteEndRow - nEndY);
1830
0
        return;
1831
0
    }
1832
1833
    // Non-overwriting fill follows.
1834
1835
0
    const bool bDataLeft = (nStartX > 0);
1836
0
    if (!bDataLeft && nEndX >= rDoc.MaxCol())
1837
        // Absolutely no data left or right of selection.
1838
0
        return;
1839
1840
    // Check that there is
1841
    // 1) data immediately left (preferred) or right of start (row) of selection
1842
    // 2) data there below
1843
    // 3) no data immediately below selection
1844
1845
0
    SCCOL nMovX = (bDataLeft ? nStartX - 1 : nEndX + 1);
1846
0
    SCROW nMovY = nStartY;
1847
0
    bool bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
1848
0
    if (!bDataFound && bDataLeft && nEndX < rDoc.MaxCol())
1849
0
    {
1850
0
        nMovX = nEndX + 1;  // check right
1851
0
        bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
1852
0
    }
1853
1854
0
    if (!(bDataFound && rDoc.IsEmptyData( nStartX, nEndY + 1, nEndX, nEndY + 1, nTab )))
1855
0
        return;
1856
1857
    // Get end of data left or right.
1858
0
    rDoc.FindAreaPos( nMovX, nMovY, nTab, SC_MOVE_DOWN);
1859
    // Find minimum end row of below empty area and data right.
1860
0
    for (SCCOL nX = nStartX; nX <= nEndX; ++nX)
1861
0
    {
1862
0
        SCROW nY = nEndY + 1;
1863
        // Get next row with data in this column.
1864
0
        rDoc.FindAreaPos( nX, nY, nTab, SC_MOVE_DOWN);
1865
0
        if (nMovY == rDoc.MaxRow() && nY == rDoc.MaxRow())
1866
0
        {
1867
            // FindAreaPos() returns MAXROW also if there is no data at all
1868
            // from the start, so check if that contains data if the nearby
1869
            // (left or right) data ends there and increment if no data
1870
            // here, pretending the next data would be thereafter so nMovY
1871
            // will not be decremented.
1872
0
            if (!rDoc.HasData( nX, nY, nTab))
1873
0
                ++nY;
1874
0
        }
1875
0
        if (nMovY > nY - 1)
1876
0
            nMovY = nY - 1;
1877
0
    }
1878
1879
0
    if (nMovY > nEndY)
1880
0
    {
1881
0
        FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nMovY - nEndY);
1882
0
    }
1883
0
}
1884
1885
void ScViewFunc::ConvertFormulaToValue()
1886
0
{
1887
0
    ScRange aRange;
1888
0
    GetViewData().GetSimpleArea(aRange);
1889
0
    aRange.PutInOrder();
1890
1891
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1892
0
    pDocSh->GetDocFunc().ConvertFormulaToValue(aRange, true);
1893
    // tdf#131326 - invalidate cell slots and update input line with new content
1894
0
    CellContentChanged();
1895
0
    pDocSh->PostPaint(aRange, PaintPartFlags::Grid);
1896
0
}
1897
1898
void ScViewFunc::TransliterateText( TransliterationFlags nType )
1899
0
{
1900
0
    ScMarkData aFuncMark = GetViewData().GetMarkData();
1901
0
    if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
1902
0
    {
1903
        //  no selection -> use cursor position
1904
1905
0
        ScAddress aCursor( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().CurrentTabForData() );
1906
0
        aFuncMark.SetMarkArea( ScRange( aCursor ) );
1907
0
    }
1908
1909
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
1910
0
                        TransliterateText( aFuncMark, nType, false );
1911
0
    if (bSuccess)
1912
0
    {
1913
0
        GetViewData().GetViewShell()->UpdateInputHandler();
1914
0
    }
1915
0
}
1916
1917
//  AutoFormat
1918
1919
void ScViewFunc::AutoFormat( sal_uInt16 nFormatNo )
1920
0
{
1921
0
    ScRange aRange;
1922
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
1923
0
    {
1924
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
1925
0
        ScMarkData& rMark = GetViewData().GetMarkData();
1926
1927
0
        bool bSuccess = pDocSh->GetDocFunc().AutoFormat( aRange, &rMark, nFormatNo, false );
1928
0
        if (bSuccess)
1929
0
            pDocSh->UpdateOle(GetViewData());
1930
0
    }
1931
0
    else
1932
0
        ErrorMessage(STR_NOMULTISELECT);
1933
0
}
1934
1935
// Search & Replace
1936
1937
bool ScViewFunc::SearchAndReplace( const SvxSearchItem* pSearchItem,
1938
                                        bool bAddUndo, bool bIsApi )
1939
0
{
1940
0
    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
1941
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1942
0
    ScDocument& rDoc = pDocSh->GetDocument();
1943
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1944
0
    if (bAddUndo && !rDoc.IsUndoEnabled())
1945
0
        bAddUndo = false;
1946
1947
0
    bool bCursorMoved = false;
1948
0
    SCCOL nOrigPosX = GetViewData().GetCurX();
1949
0
    SCROW nOrigPosY = GetViewData().GetCurY();
1950
0
    if ( !rMark.IsMarked() && !rMark.IsMultiMarked() && (pSearchItem->HasStartPoint()) )
1951
0
    {
1952
        // No selection -> but we have a start point (top left corner of the
1953
        // current view), start searching from there, not from the current
1954
        // cursor position.
1955
0
        SCCOL nPosX;
1956
0
        SCROW nPosY;
1957
1958
0
        int nPixelX = pSearchItem->GetStartPointX() * GetViewData().GetPPTX();
1959
0
        int nPixelY = pSearchItem->GetStartPointY() * GetViewData().GetPPTY();
1960
1961
0
        GetViewData().GetPosFromPixel(nPixelX, nPixelY, GetViewData().GetActivePart(), nPosX, nPosY);
1962
1963
0
        AlignToCursor( nPosX, nPosY, SC_FOLLOW_JUMP );
1964
0
        SetCursor( nPosX, nPosY, true );
1965
0
        bCursorMoved = true;
1966
0
    }
1967
1968
0
    SCCOL nCol, nOldCol;
1969
0
    SCROW nRow, nOldRow;
1970
0
    SCTAB nTab, nOldTab;
1971
0
    nCol = nOldCol = GetViewData().GetCurX();
1972
0
    nRow = nOldRow = GetViewData().GetCurY();
1973
0
    nTab = nOldTab = GetViewData().CurrentTabForData();
1974
1975
0
    SvxSearchCmd nCommand = pSearchItem->GetCommand();
1976
0
    bool bAllTables = pSearchItem->IsAllTables();
1977
0
    std::set<SCTAB> aOldSelectedTables;
1978
0
    SCTAB nLastTab = rDoc.GetTableCount() - 1;
1979
0
    SCTAB nStartTab, nEndTab;
1980
0
    if ( bAllTables )
1981
0
    {
1982
0
        nStartTab = 0;
1983
0
        nEndTab = nLastTab;
1984
0
        std::set<SCTAB> aTmp(rMark.begin(), rMark.end());
1985
0
        aOldSelectedTables.swap(aTmp);
1986
0
    }
1987
0
    else
1988
0
    {   //! at least one is always selected
1989
0
        nStartTab = rMark.GetFirstSelected();
1990
0
        nEndTab = rMark.GetLastSelected();
1991
0
    }
1992
1993
0
    if (   nCommand == SvxSearchCmd::FIND
1994
0
        || nCommand == SvxSearchCmd::FIND_ALL)
1995
0
        bAddUndo = false;
1996
1997
    //!     account for bAttrib during Undo !!!
1998
1999
0
    ScDocumentUniquePtr pUndoDoc;
2000
0
    std::unique_ptr<ScMarkData> pUndoMark;
2001
0
    OUString aUndoStr;
2002
0
    if (bAddUndo)
2003
0
    {
2004
0
        pUndoMark.reset(new ScMarkData(rMark));                // Mark is being modified
2005
0
        if ( nCommand == SvxSearchCmd::REPLACE_ALL )
2006
0
        {
2007
0
            pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
2008
0
            pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
2009
0
        }
2010
0
    }
2011
2012
0
    if ( bAllTables )
2013
0
    {   //! select all, after pUndoMark has been created
2014
0
        for ( SCTAB j = nStartTab; j <= nEndTab; j++ )
2015
0
        {
2016
0
            rMark.SelectTable( j, true );
2017
0
        }
2018
0
    }
2019
2020
0
    DoneBlockMode(true);                // don't delete mark
2021
0
    InitOwnBlockMode( ScRange( nCol, nRow, nStartTab, nCol, nRow, nEndTab));
2022
2023
    //  If search starts at the beginning don't ask again whether it shall start at the beginning
2024
0
    bool bFirst = true;
2025
0
    if ( nCol == 0 && nRow == 0 && nTab == nStartTab && !pSearchItem->GetBackward()  )
2026
0
        bFirst = false;
2027
2028
0
    bool bFound = false;
2029
0
    while (true)
2030
0
    {
2031
0
        GetFrameWin()->EnterWait();
2032
0
        ScRangeList aMatchedRanges;
2033
0
        bool bMatchedRangesWereClamped = false;
2034
0
        if (rDoc.SearchAndReplace(*pSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, pUndoDoc.get(), bMatchedRangesWereClamped))
2035
0
        {
2036
0
            bFound = true;
2037
0
            if (bAddUndo)
2038
0
            {
2039
0
                GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
2040
0
                    std::make_unique<ScUndoReplace>( *GetViewData().GetDocShell(), *pUndoMark,
2041
0
                                        nCol, nRow, nTab,
2042
0
                                        aUndoStr, std::move(pUndoDoc), pSearchItem ) );
2043
0
            }
2044
2045
0
            if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL)
2046
0
            {
2047
0
                SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2048
0
                bool bShow = GetViewData().GetViewShell()->GetViewData().GetOptions().GetOption(sc::ViewOption::SUMMARY);
2049
2050
0
                if (bShow && pViewFrm && !comphelper::LibreOfficeKit::isActive())
2051
0
                {
2052
0
                    pViewFrm->ShowChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
2053
0
                    SfxChildWindow* pWnd = pViewFrm->GetChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
2054
0
                    if (pWnd)
2055
0
                    {
2056
0
                        sc::SearchResultsDlg* pDlg = static_cast<sc::SearchResultsDlg*>(pWnd->GetController().get());
2057
0
                        if (pDlg)
2058
0
                        {
2059
0
                            const bool bCellNotes = (pSearchItem->GetCellType() == SvxSearchCellType::NOTE);
2060
                            // ScCellIterator iterates over cells with content,
2061
                            // for empty cells iterate over match positions.
2062
0
                            const bool bEmptyCells = (!bCellNotes
2063
0
                                    && ((nCommand == SvxSearchCmd::FIND_ALL
2064
0
                                            && ScDocument::IsEmptyCellSearch(*pSearchItem))
2065
0
                                        || (nCommand == SvxSearchCmd::REPLACE_ALL
2066
0
                                            && pSearchItem->GetReplaceString().isEmpty())));
2067
0
                            pDlg->FillResults(rDoc, aMatchedRanges, bCellNotes, bEmptyCells, bMatchedRangesWereClamped);
2068
0
                        }
2069
0
                    }
2070
0
                }
2071
2072
0
                rMark.ResetMark();
2073
0
                for (size_t i = 0, n = aMatchedRanges.size(); i < n; ++i)
2074
0
                {
2075
0
                    const ScRange& r = aMatchedRanges[i];
2076
0
                    if (r.aStart.Tab() == nTab)
2077
0
                        rMark.SetMultiMarkArea(r);
2078
0
                }
2079
0
            }
2080
2081
0
            break;                  // break 'while (TRUE)'
2082
0
        }
2083
0
        else if ( bFirst && (nCommand == SvxSearchCmd::FIND ||
2084
0
                nCommand == SvxSearchCmd::REPLACE) )
2085
0
        {
2086
0
            bFirst = false;
2087
0
            GetFrameWin()->LeaveWait();
2088
0
            if (!bIsApi)
2089
0
            {
2090
0
                if ( nStartTab == nEndTab )
2091
0
                    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::EndSheet);
2092
0
                else
2093
0
                    SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
2094
2095
0
                rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
2096
0
                if (pSearchItem->GetBackward())
2097
0
                    nTab = nEndTab;
2098
0
                else
2099
0
                    nTab = nStartTab;
2100
0
            }
2101
0
            else
2102
0
            {
2103
0
                break;                  // break 'while (TRUE)'
2104
0
            }
2105
0
        }
2106
0
        else                            // nothing found
2107
0
        {
2108
0
            if ( nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL )
2109
0
            {
2110
0
                pDocSh->PostPaintGridAll();                             // Mark
2111
0
            }
2112
2113
0
            GetFrameWin()->LeaveWait();
2114
0
            if (!bIsApi)
2115
0
            {
2116
0
                GetViewData().GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, pSearchItem->GetSearchString().toUtf8());
2117
0
                SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
2118
0
            }
2119
2120
0
            break;                      // break 'while (TRUE)'
2121
0
        }
2122
0
    }                               // of while true
2123
2124
0
    if (!aOldSelectedTables.empty())
2125
0
    {
2126
        // restore originally selected table
2127
0
        for (SCTAB i = 0; i <= nEndTab; ++i)
2128
0
            rMark.SelectTable(i, false);
2129
2130
0
        for (const auto& rTab : aOldSelectedTables)
2131
0
            rMark.SelectTable(rTab, true);
2132
2133
0
        if ( bFound )
2134
0
        {   // if a table is selected as a "match" it remains selected.
2135
0
            rMark.SelectTable( nTab, true );
2136
            // It's a swap if only one table was selected before
2137
            //! otherwise now one table more might be selected
2138
0
            if ( aOldSelectedTables.size() == 1 && nTab != nOldTab )
2139
0
                rMark.SelectTable( nOldTab, false );
2140
0
        }
2141
0
    }
2142
2143
    // Avoid LOK selection notifications before we have all the results.
2144
0
    GetViewData().GetViewShell()->setTiledSearching(true);
2145
0
    MarkDataChanged();
2146
0
    GetViewData().GetViewShell()->setTiledSearching(false);
2147
2148
0
    if ( bFound )
2149
0
    {
2150
0
        if ( nTab != GetViewData().CurrentTabForData() )
2151
0
            SetTabNo( nTab );
2152
2153
        //  if nothing is marked, DoneBlockMode, then marking can start
2154
        //  directly from this place via Shift-Cursor
2155
0
        if (!rMark.IsMarked() && !rMark.IsMultiMarked())
2156
0
            DoneBlockMode(true);
2157
2158
0
        AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
2159
0
        SetCursor( nCol, nRow, true );
2160
2161
0
        if (comphelper::LibreOfficeKit::isActive())
2162
0
        {
2163
0
            Point aCurPos = GetViewData().GetScrPos(nCol, nRow, GetViewData().GetActivePart());
2164
2165
            // just update the cell selection
2166
0
            ScGridWindow* pGridWindow = GetViewData().GetActiveWin();
2167
            // Don't move cell selection handles for find-all: selection of all but the first result would be lost.
2168
0
            if (pGridWindow && nCommand == SvxSearchCmd::FIND)
2169
0
            {
2170
                // move the cell selection handles
2171
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_RESET, aCurPos.X(), aCurPos.Y());
2172
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aCurPos.X(), aCurPos.Y());
2173
0
                pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aCurPos.X(), aCurPos.Y());
2174
0
            }
2175
2176
0
            if (pGridWindow)
2177
0
            {
2178
0
                std::vector<tools::Rectangle> aLogicRects;
2179
0
                pGridWindow->GetCellSelection(aLogicRects);
2180
2181
0
                boost::property_tree::ptree aTree;
2182
0
                aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr());
2183
0
                aTree.put("highlightAll", nCommand == SvxSearchCmd::FIND_ALL);
2184
2185
0
                boost::property_tree::ptree aSelections;
2186
0
                for (const tools::Rectangle& rLogicRect : aLogicRects)
2187
0
                {
2188
0
                    boost::property_tree::ptree aSelection;
2189
0
                    aSelection.put("part", OString::number(nTab).getStr());
2190
0
                    aSelection.put("rectangles", rLogicRect.toString().getStr());
2191
0
                    aSelections.push_back(std::make_pair("", aSelection));
2192
0
                }
2193
0
                aTree.add_child("searchResultSelection", aSelections);
2194
2195
0
                std::stringstream aStream;
2196
0
                boost::property_tree::write_json(aStream, aTree);
2197
0
                OString aPayload( aStream.str() );
2198
0
                SfxViewShell* pViewShell = GetViewData().GetViewShell();
2199
0
                pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload);
2200
2201
                // Trigger LOK_CALLBACK_TEXT_SELECTION now.
2202
0
                MarkDataChanged();
2203
0
            }
2204
0
        }
2205
2206
0
        if (   nCommand == SvxSearchCmd::REPLACE
2207
0
            || nCommand == SvxSearchCmd::REPLACE_ALL )
2208
0
        {
2209
0
            if ( nCommand == SvxSearchCmd::REPLACE )
2210
0
            {
2211
0
                pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid );
2212
2213
                // jump to next cell if we replaced everything in the cell
2214
                // where the cursor was positioned (but avoid switching tabs)
2215
0
                if ( nCol == nOldCol && nRow == nOldRow && nTab == nOldTab )
2216
0
                {
2217
0
                    SvxSearchItem aSearchItem = ScGlobal::GetSearchItem();
2218
0
                    aSearchItem.SetCommand(SvxSearchCmd::FIND);
2219
0
                    aSearchItem.SetWhich(SID_SEARCH_ITEM);
2220
2221
0
                    ScRangeList aMatchedRanges;
2222
0
                    bool bMatchedRangesWereClamped;
2223
0
                    ScTable::UpdateSearchItemAddressForReplace( aSearchItem, nCol, nRow );
2224
0
                    if ( rDoc.SearchAndReplace( aSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, nullptr, bMatchedRangesWereClamped ) &&
2225
0
                            ( nTab == nOldTab ) &&
2226
0
                            ( nCol != nOldCol || nRow != nOldRow ) )
2227
0
                    {
2228
0
                        AlignToCursor(nCol, nRow, SC_FOLLOW_JUMP);
2229
0
                        SetCursor( nCol, nRow, true );
2230
0
                    }
2231
0
                }
2232
0
            }
2233
0
            else
2234
0
                pDocSh->PostPaintGridAll();
2235
0
            pDocSh->SetDocumentModified();
2236
0
        }
2237
0
        else if ( nCommand == SvxSearchCmd::FIND_ALL )
2238
0
            pDocSh->PostPaintGridAll();                             // mark
2239
0
        GetFrameWin()->LeaveWait();
2240
0
    }
2241
0
    else if (bCursorMoved)
2242
0
    {
2243
0
        SetCursor(nOrigPosX, nOrigPosY, true);
2244
0
    }
2245
0
    return bFound;
2246
0
}
2247
2248
// Goal Seek
2249
2250
void ScViewFunc::Solve( const ScSolveParam& rParam )
2251
0
{
2252
0
    ScDocument& rDoc = GetViewData().GetDocument();
2253
2254
0
    SCCOL nDestCol = rParam.aRefVariableCell.Col();
2255
0
    SCROW nDestRow = rParam.aRefVariableCell.Row();
2256
0
    SCTAB nDestTab = rParam.aRefVariableCell.Tab();
2257
2258
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nDestTab, nDestCol, nDestRow, nDestCol, nDestRow);
2259
0
    if (!aTester.IsEditable())
2260
0
    {
2261
0
        ErrorMessage(aTester.GetMessageId());
2262
0
        return;
2263
0
    }
2264
2265
0
    OUString  aTargetValStr;
2266
0
    if ( rParam.pStrTargetVal )
2267
0
        aTargetValStr = *rParam.pStrTargetVal;
2268
2269
0
    OUString  aMsgStr;
2270
0
    OUString  aResStr;
2271
0
    double  nSolveResult;
2272
0
    GetFrameWin()->EnterWait();
2273
2274
0
    bool    bExact =
2275
0
                rDoc.Solver(
2276
0
                    rParam.aRefFormulaCell.Col(),
2277
0
                    rParam.aRefFormulaCell.Row(),
2278
0
                    rParam.aRefFormulaCell.Tab(),
2279
0
                    nDestCol, nDestRow, nDestTab,
2280
0
                    aTargetValStr,
2281
0
                    nSolveResult);
2282
2283
0
    GetFrameWin()->LeaveWait();
2284
2285
0
    SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2286
0
    sal_uLong nFormat = 0;
2287
0
    const ScPatternAttr* pPattern = rDoc.GetPattern( nDestCol, nDestRow, nDestTab );
2288
0
    if ( pPattern )
2289
0
        nFormat = pPattern->GetNumberFormat( pFormatter );
2290
0
    const Color* p;
2291
0
    pFormatter->GetOutputString( nSolveResult, nFormat, aResStr, &p );
2292
2293
0
    if ( bExact )
2294
0
    {
2295
0
        aMsgStr += ScResId( STR_MSSG_SOLVE_0 ) +
2296
0
            aResStr +
2297
0
            ScResId( STR_MSSG_SOLVE_1 );
2298
0
    }
2299
0
    else
2300
0
    {
2301
0
        aMsgStr  = ScResId( STR_MSSG_SOLVE_2 ) +
2302
0
            ScResId( STR_MSSG_SOLVE_3 ) +
2303
0
            aResStr +
2304
0
            ScResId( STR_MSSG_SOLVE_4 );
2305
0
    }
2306
2307
0
    std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
2308
0
                                              VclMessageType::Question, VclButtonsType::YesNo, aMsgStr));
2309
0
    xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0));
2310
0
    xBox->set_default_response(RET_NO);
2311
0
    int nResponse = xBox->run();
2312
0
    if (nResponse == RET_YES)
2313
0
        EnterValue( nDestCol, nDestRow, nDestTab, nSolveResult );
2314
2315
0
    GetViewData().GetViewShell()->UpdateInputHandler( true );
2316
0
}
2317
2318
//  multi operation
2319
2320
void ScViewFunc::TabOp( const ScTabOpParam& rParam, bool bRecord )
2321
0
{
2322
0
    ScRange aRange;
2323
0
    if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
2324
0
    {
2325
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
2326
0
        ScMarkData& rMark = GetViewData().GetMarkData();
2327
0
        pDocSh->GetDocFunc().TabOp( aRange, &rMark, rParam, bRecord, false );
2328
0
    }
2329
0
    else
2330
0
        ErrorMessage(STR_NOMULTISELECT);
2331
0
}
2332
2333
void ScViewFunc::MakeScenario( const OUString& rName, const OUString& rComment,
2334
                                    const Color& rColor, ScScenarioFlags nFlags )
2335
0
{
2336
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2337
0
    ScMarkData& rMark   = GetViewData().GetMarkData();
2338
0
    SCTAB       nTab    = GetViewData().CurrentTabForData();
2339
2340
0
    SCTAB nNewTab = pDocSh->MakeScenario( nTab, rName, rComment, rColor, nFlags, rMark );
2341
0
    if (nFlags & ScScenarioFlags::CopyAll)
2342
0
        SetTabNo( nNewTab, true );          // ScScenarioFlags::CopyAll -> visible
2343
0
    else
2344
0
    {
2345
0
        SfxBindings& rBindings = GetViewData().GetBindings();
2346
0
        rBindings.Invalidate( SID_STATUS_DOCPOS );      // Statusbar
2347
0
        rBindings.Invalidate( SID_ROWCOL_SELCOUNT );    // Statusbar
2348
0
        rBindings.Invalidate( SID_TABLES_COUNT );
2349
0
        rBindings.Invalidate( SID_SELECT_SCENARIO );
2350
0
        rBindings.Invalidate( FID_TABLE_SHOW );
2351
0
    }
2352
0
}
2353
2354
void ScViewFunc::ExtendScenario()
2355
0
{
2356
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
2357
0
    if (!aTester.IsEditable())
2358
0
    {
2359
0
        ErrorMessage(aTester.GetMessageId());
2360
0
        return;
2361
0
    }
2362
2363
        //  Undo: apply attributes
2364
2365
0
    ScDocument& rDoc = GetViewData().GetDocument();
2366
0
    ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
2367
0
    aPattern.ItemSetPut(ScMergeFlagAttr(ScMF::Scenario));
2368
0
    aPattern.ItemSetPut(ScProtectionAttr(true));
2369
0
    ApplySelectionPattern(aPattern);
2370
0
}
2371
2372
void ScViewFunc::UseScenario( const OUString& rName )
2373
0
{
2374
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2375
0
    SCTAB       nTab    = GetViewData().CurrentTabForData();
2376
2377
0
    DoneBlockMode();
2378
0
    InitOwnBlockMode( ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab));
2379
0
    pDocSh->UseScenario( nTab, rName );
2380
0
}
2381
2382
//  Insert table
2383
2384
bool ScViewFunc::InsertTable( const OUString& rName, SCTAB nTab, bool bRecord )
2385
0
{
2386
    //  Order Table/Name is inverted for DocFunc
2387
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
2388
0
                        InsertTable( nTab, rName, bRecord, false );
2389
0
    if (bSuccess)
2390
0
        SetTabNo( nTab, true );
2391
2392
0
    return bSuccess;
2393
0
}
2394
2395
//  Insert tables
2396
2397
void ScViewFunc::InsertTables(std::vector<OUString>& aNames, SCTAB nTab,
2398
                                            SCTAB nCount, bool bRecord )
2399
0
{
2400
0
    ScDocShell* pDocSh    = GetViewData().GetDocShell();
2401
0
    ScDocument& rDoc     = pDocSh->GetDocument();
2402
0
    if (bRecord && !rDoc.IsUndoEnabled())
2403
0
        bRecord = false;
2404
2405
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2406
2407
0
    if (bRecord)
2408
0
    {
2409
0
        rDoc.BeginDrawUndo();                            //    InsertTab creates a SdrUndoNewPage
2410
0
    }
2411
2412
0
    bool bFlag=false;
2413
2414
0
    if(aNames.empty())
2415
0
    {
2416
0
        rDoc.CreateValidTabNames(aNames, nCount);
2417
0
    }
2418
0
    if (rDoc.InsertTabs(nTab, aNames))
2419
0
    {
2420
0
        pDocSh->Broadcast( ScTablesHint( SC_TABS_INSERTED, nTab, nCount ) );
2421
0
        bFlag = true;
2422
0
    }
2423
2424
0
    if (!bFlag)
2425
0
        return;
2426
2427
0
    if (bRecord)
2428
0
        pDocSh->GetUndoManager()->AddUndoAction(
2429
0
                    std::make_unique<ScUndoInsertTables>( *pDocSh, nTab, std::move(aNames)));
2430
2431
    //    Update views
2432
2433
0
    SetTabNo( nTab, true );
2434
0
    pDocSh->PostPaintExtras();
2435
0
    pDocSh->SetDocumentModified();
2436
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2437
0
}
2438
2439
bool ScViewFunc::AppendTable( const OUString& rName, bool bRecord )
2440
0
{
2441
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2442
0
    ScDocument& rDoc   = pDocSh->GetDocument();
2443
0
    if (bRecord && !rDoc.IsUndoEnabled())
2444
0
        bRecord = false;
2445
2446
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2447
2448
0
    if (bRecord)
2449
0
        rDoc.BeginDrawUndo();                          //  InsertTab creates a SdrUndoNewPage
2450
2451
0
    if (rDoc.InsertTab( SC_TAB_APPEND, rName ))
2452
0
    {
2453
0
        SCTAB nTab = rDoc.GetTableCount()-1;
2454
0
        if (bRecord)
2455
0
            pDocSh->GetUndoManager()->AddUndoAction(
2456
0
                        std::make_unique<ScUndoInsertTab>( *pDocSh, nTab, true, rName));
2457
0
        GetViewData().InsertTab( nTab );
2458
0
        SetTabNo( nTab, true );
2459
0
        pDocSh->PostPaintExtras();
2460
0
        pDocSh->SetDocumentModified();
2461
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2462
0
        return true;
2463
0
    }
2464
0
    else
2465
0
    {
2466
0
        return false;
2467
0
    }
2468
0
}
2469
2470
void ScViewFunc::DeleteTable( SCTAB nTab, bool bRecord )
2471
0
{
2472
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2473
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2474
2475
0
    bool bSuccess = pDocSh->GetDocFunc().DeleteTable( nTab, bRecord );
2476
0
    if (bSuccess)
2477
0
    {
2478
0
        SCTAB nNewTab = nTab;
2479
0
        if ( nNewTab >= rDoc.GetTableCount() )
2480
0
            --nNewTab;
2481
0
        SetTabNo( nNewTab, true );
2482
0
    }
2483
0
}
2484
2485
//only use this method for undo for now, all sheets must be connected
2486
//this method doesn't support undo for now, merge it when it with the other method later
2487
void ScViewFunc::DeleteTables( const SCTAB nTab, SCTAB nSheets )
2488
0
{
2489
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2490
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2491
0
    bool bVbaEnabled = rDoc.IsInVBAMode();
2492
0
    SCTAB       nNewTab = nTab;
2493
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2494
2495
0
    while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
2496
0
        --nNewTab;
2497
2498
0
    if (!rDoc.DeleteTabs(nTab, nSheets))
2499
0
        return;
2500
2501
0
    if( bVbaEnabled )
2502
0
    {
2503
0
        for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
2504
0
        {
2505
0
            OUString sCodeName;
2506
0
            bool bHasCodeName = rDoc.GetCodeName( nTab + aTab, sCodeName );
2507
0
            if ( bHasCodeName )
2508
0
                VBA_DeleteModule( *pDocSh, sCodeName );
2509
0
        }
2510
0
    }
2511
2512
0
    pDocSh->Broadcast( ScTablesHint( SC_TABS_DELETED, nTab, nSheets ) );
2513
0
    if ( nNewTab >= rDoc.GetTableCount() )
2514
0
        nNewTab = rDoc.GetTableCount() - 1;
2515
0
    SetTabNo( nNewTab, true );
2516
2517
0
    pDocSh->PostPaintExtras();
2518
0
    pDocSh->SetDocumentModified();
2519
2520
0
    SfxApplication* pSfxApp = SfxGetpApp();                                // Navigator
2521
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2522
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
2523
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
2524
0
}
2525
2526
bool ScViewFunc::DeleteTables(const std::vector<SCTAB>& rTabs, bool bRecord)
2527
0
{
2528
0
    ScDocShell* pDocSh  = GetViewData().GetDocShell();
2529
0
    ScDocument& rDoc    = pDocSh->GetDocument();
2530
0
    bool bVbaEnabled = rDoc.IsInVBAMode();
2531
0
    SCTAB nNewTab = rTabs.front();
2532
0
    weld::WaitObject aWait(GetViewData().GetDialogParent());
2533
0
    if (bRecord && !rDoc.IsUndoEnabled())
2534
0
        bRecord = false;
2535
0
    if ( bVbaEnabled )
2536
0
        bRecord = false;
2537
2538
0
    while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
2539
0
        --nNewTab;
2540
2541
0
    bool bWasLinked = false;
2542
0
    ScDocumentUniquePtr pUndoDoc;
2543
0
    std::unique_ptr<ScRefUndoData> pUndoData;
2544
0
    if (bRecord)
2545
0
    {
2546
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2547
0
        SCTAB nCount = rDoc.GetTableCount();
2548
2549
0
        OUString aOldName;
2550
0
        bool isFirstTab = true;
2551
0
        for (SCTAB nTab : rTabs)
2552
0
        {
2553
0
            if (isFirstTab)
2554
0
            {
2555
0
                pUndoDoc->InitUndo( rDoc, nTab,nTab, true,true );   // incl. column/fow flags
2556
0
                isFirstTab = false;
2557
0
            }
2558
0
            else
2559
0
                pUndoDoc->AddUndoTab( nTab,nTab, true,true );       // incl. column/fow flags
2560
2561
0
            rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL,false, *pUndoDoc );
2562
0
            rDoc.GetName( nTab, aOldName );
2563
0
            pUndoDoc->RenameTab( nTab, aOldName );
2564
0
            if (rDoc.IsLinked(nTab))
2565
0
            {
2566
0
                bWasLinked = true;
2567
0
                pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab),
2568
0
                                    rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
2569
0
                                    rDoc.GetLinkTab(nTab),
2570
0
                                    rDoc.GetLinkRefreshDelay(nTab) );
2571
0
            }
2572
0
            if ( rDoc.IsScenario(nTab) )
2573
0
            {
2574
0
                pUndoDoc->SetScenario( nTab, true );
2575
0
                OUString aComment;
2576
0
                Color  aColor;
2577
0
                ScScenarioFlags nScenFlags;
2578
0
                rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags );
2579
0
                pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
2580
0
                bool bActive = rDoc.IsActiveScenario( nTab );
2581
0
                pUndoDoc->SetActiveScenario( nTab, bActive );
2582
0
            }
2583
0
            pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) );
2584
0
            pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
2585
0
            auto pSheetEvents = rDoc.GetSheetEvents( nTab );
2586
0
            pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
2587
0
            pUndoDoc->SetLayoutRTL( nTab, rDoc.IsLayoutRTL( nTab ) );
2588
2589
0
            if ( rDoc.IsTabProtected( nTab ) )
2590
0
                pUndoDoc->SetTabProtection(nTab, rDoc.GetTabProtection(nTab));
2591
2592
            //  Drawing-Layer is responsible for its Undo  !!!
2593
            //      pUndoDoc->TransferDrawPage(rDoc, nTab,nTab);
2594
0
        }
2595
2596
0
        pUndoDoc->AddUndoTab( 0, nCount-1 );            //  all Tabs for references
2597
2598
0
        rDoc.BeginDrawUndo();                          //  DeleteTab creates a SdrUndoDelPage
2599
2600
0
        pUndoData.reset(new ScRefUndoData( rDoc ));
2601
0
    }
2602
2603
0
    bool bDelDone = false;
2604
2605
0
    std::vector<ScTable*> aSheetViewHolderTablesToDelete;
2606
2607
0
    for (sal_Int32 i = rTabs.size() - 1; i >= 0; --i)
2608
0
    {
2609
0
        SCTAB nTab = rTabs[i];
2610
0
        OUString sCodeName;
2611
0
        bool bHasCodeName = rDoc.GetCodeName(nTab, sCodeName);
2612
2613
        // If we delete the current viewed table, make sure that we exit any sheet views
2614
0
        if (GetViewData().GetTabNumber() == nTab && GetViewData().GetSheetViewID() != sc::DefaultSheetViewID)
2615
0
            GetViewData().SetSheetViewID(sc::DefaultSheetViewID);
2616
2617
0
        if (auto pManager = rDoc.GetSheetViewManager(nTab))
2618
0
        {
2619
0
            for (auto const& pSheetView : pManager->getSheetViews())
2620
0
            {
2621
0
                aSheetViewHolderTablesToDelete.push_back(pSheetView->getTablePointer());
2622
0
            }
2623
0
        }
2624
2625
0
        if (rDoc.DeleteTab(nTab))
2626
0
        {
2627
0
            bDelDone = true;
2628
0
            if( bVbaEnabled && bHasCodeName )
2629
0
            {
2630
0
                VBA_DeleteModule( *pDocSh, sCodeName );
2631
0
            }
2632
0
            pDocSh->Broadcast( ScTablesHint(SC_TAB_DELETED, nTab) );
2633
0
        }
2634
0
    }
2635
2636
    // Delete sheet view holder tables if it's table has been deleted
2637
0
    for (auto* pTable : aSheetViewHolderTablesToDelete)
2638
0
    {
2639
0
        SCTAB nTab = pTable->GetTab();
2640
0
        if (rDoc.DeleteTab(nTab))
2641
0
        {
2642
0
            pDocSh->Broadcast(ScTablesHint(SC_TAB_DELETED, nTab));
2643
0
        }
2644
0
    }
2645
2646
0
    if (bRecord)
2647
0
    {
2648
0
        pDocSh->GetUndoManager()->AddUndoAction(
2649
0
                    std::make_unique<ScUndoDeleteTab>( *GetViewData().GetDocShell(), rTabs,
2650
0
                                            std::move(pUndoDoc), std::move(pUndoData) ));
2651
0
    }
2652
2653
0
    if (bDelDone)
2654
0
    {
2655
0
        if ( nNewTab >= rDoc.GetTableCount() )
2656
0
            nNewTab = rDoc.GetTableCount() - 1;
2657
2658
0
        SetTabNo( nNewTab, true );
2659
2660
0
        if (bWasLinked)
2661
0
        {
2662
0
            pDocSh->UpdateLinks();              // update Link-Manager
2663
0
            GetViewData().GetBindings().Invalidate(SID_LINKS);
2664
0
        }
2665
2666
0
        pDocSh->PostPaintExtras();
2667
0
        pDocSh->SetDocumentModified();
2668
2669
0
        SfxApplication* pSfxApp = SfxGetpApp();                                // Navigator
2670
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2671
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
2672
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
2673
0
        pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
2674
0
    }
2675
0
    return bDelDone;
2676
0
}
2677
2678
bool ScViewFunc::RenameTable( const OUString& rName, SCTAB nTab )
2679
0
{
2680
    //  order Table/Name is inverted for DocFunc
2681
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
2682
0
                        RenameTable( nTab, rName, true, false );
2683
0
    if (bSuccess)
2684
0
    {
2685
        //  the table name might be part of a formula
2686
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2687
0
    }
2688
0
    return bSuccess;
2689
0
}
2690
2691
bool ScViewFunc::SetTabBgColor( const Color& rColor, SCTAB nTab )
2692
0
{
2693
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( nTab, rColor, true, false );
2694
0
    if (bSuccess)
2695
0
    {
2696
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2697
0
    }
2698
0
    return bSuccess;
2699
0
}
2700
2701
bool ScViewFunc::SetTabBgColor( ScUndoTabColorInfo::List& rUndoSetTabBgColorInfoList )
2702
0
{
2703
0
    bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( rUndoSetTabBgColorInfoList, false );
2704
0
    if (bSuccess)
2705
0
    {
2706
0
        GetViewData().GetViewShell()->UpdateInputHandler();
2707
0
    }
2708
0
    return bSuccess;
2709
0
}
2710
2711
void ScViewFunc::InsertAreaLink( const OUString& rFile,
2712
                                    const OUString& rFilter, const OUString& rOptions,
2713
                                    const OUString& rSource )
2714
0
{
2715
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2716
0
    SCCOL nPosX = GetViewData().GetCurX();
2717
0
    SCROW nPosY = GetViewData().GetCurY();
2718
0
    SCTAB nTab = GetViewData().CurrentTabForData();
2719
0
    ScAddress aPos( nPosX, nPosY, nTab );
2720
2721
0
    pDocSh->GetDocFunc().InsertAreaLink( rFile, rFilter, rOptions, rSource, ScRange(aPos), 0/*nRefresh*/, false, false );
2722
0
}
2723
2724
void ScViewFunc::InsertTableLink( const OUString& rFile,
2725
                                    const OUString& rFilter, const OUString& rOptions,
2726
                                    std::u16string_view rTabName )
2727
0
{
2728
0
    OUString aFilterName = rFilter;
2729
0
    OUString aOpt = rOptions;
2730
0
    ScDocumentLoader aLoader( rFile, aFilterName, aOpt );
2731
0
    if (aLoader.IsError())
2732
0
        return;
2733
2734
0
    ScDocShell* pSrcSh = aLoader.GetDocShell();
2735
0
    ScDocument& rSrcDoc = pSrcSh->GetDocument();
2736
0
    SCTAB nTab = MAXTAB+1;
2737
0
    if (rTabName.empty())                // no name given -> first table
2738
0
        nTab = 0;
2739
0
    else
2740
0
    {
2741
0
        OUString aTemp;
2742
0
        SCTAB nCount = rSrcDoc.GetTableCount();
2743
0
        for (SCTAB i=0; i<nCount; i++)
2744
0
        {
2745
0
            rSrcDoc.GetName( i, aTemp );
2746
0
            if ( aTemp == rTabName )
2747
0
                nTab = i;
2748
0
        }
2749
0
    }
2750
2751
0
    if ( nTab <= MAXTAB )
2752
0
        ImportTables( pSrcSh, 1, &nTab, true,
2753
0
                    GetViewData().CurrentTabForData() );
2754
0
}
2755
2756
//  Copy/link tables from another document
2757
2758
void ScViewFunc::ImportTables( ScDocShell* pSrcShell,
2759
                                SCTAB nCount, const SCTAB* pSrcTabs, bool bLink,SCTAB nTab )
2760
0
{
2761
0
    ScDocument& rSrcDoc = pSrcShell->GetDocument();
2762
2763
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2764
0
    ScDocument& rDoc = pDocSh->GetDocument();
2765
0
    bool bUndo(rDoc.IsUndoEnabled());
2766
2767
0
    bool bError = false;
2768
2769
0
    if (rSrcDoc.GetDrawLayer())
2770
0
        pDocSh->MakeDrawLayer();
2771
2772
0
    if (bUndo)
2773
0
        rDoc.BeginDrawUndo();          // drawing layer must do its own undo actions
2774
2775
0
    SCTAB nInsCount = 0;
2776
0
    SCTAB i;
2777
0
    for( i=0; i<nCount; i++ )
2778
0
    {   // insert sheets first and update all references
2779
0
        OUString aName;
2780
0
        rSrcDoc.GetName( pSrcTabs[i], aName );
2781
0
        rDoc.CreateValidTabName( aName );
2782
0
        if ( !rDoc.InsertTab( nTab+i, aName ) )
2783
0
        {
2784
0
            bError = true;      // total error
2785
0
            break;  // for
2786
0
        }
2787
0
        ++nInsCount;
2788
0
    }
2789
0
    for (i=0; i<nCount && !bError; i++)
2790
0
    {
2791
0
        SCTAB nSrcTab = pSrcTabs[i];
2792
0
        SCTAB nDestTab1=nTab+i;
2793
0
        bool bValid = pDocSh->TransferTab( *pSrcShell, nSrcTab, nDestTab1,
2794
0
            false, false );     // no insert
2795
2796
0
        if (!bValid)
2797
0
        {
2798
0
            bError = true;
2799
0
        }
2800
2801
0
    }
2802
2803
0
    if (bLink)
2804
0
    {
2805
0
        sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
2806
2807
0
        SfxMedium* pMed = pSrcShell->GetMedium();
2808
0
        OUString aFileName = pMed->GetName();
2809
0
        OUString aFilterName;
2810
0
        if (pMed->GetFilter())
2811
0
            aFilterName = pMed->GetFilter()->GetFilterName();
2812
0
        OUString aOptions = ScDocumentLoader::GetOptions(*pMed);
2813
2814
0
        bool bWasThere = rDoc.HasLink( aFileName, aFilterName, aOptions );
2815
2816
0
        sal_uLong nRefresh = 0;
2817
0
        OUString aTabStr;
2818
0
        for (i=0; i<nInsCount; i++)
2819
0
        {
2820
0
            rSrcDoc.GetName( pSrcTabs[i], aTabStr );
2821
0
            rDoc.SetLink( nTab+i, ScLinkMode::NORMAL,
2822
0
                        aFileName, aFilterName, aOptions, aTabStr, nRefresh );
2823
0
        }
2824
2825
0
        if (!bWasThere)         // Insert link only once per source document
2826
0
        {
2827
0
            ScTableLink* pLink = new ScTableLink( *pDocSh, aFileName, aFilterName, aOptions, nRefresh );
2828
0
            pLink->SetInCreate( true );
2829
0
            pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilterName );
2830
0
            pLink->Update();
2831
0
            pLink->SetInCreate( false );
2832
2833
0
            SfxBindings& rBindings = GetViewData().GetBindings();
2834
0
            rBindings.Invalidate( SID_LINKS );
2835
0
        }
2836
0
    }
2837
2838
0
    if (bUndo)
2839
0
    {
2840
0
        pDocSh->GetUndoManager()->AddUndoAction(
2841
0
                std::make_unique<ScUndoImportTab>( *pDocSh, nTab, nCount ) );
2842
0
    }
2843
2844
0
    for (i=0; i<nInsCount; i++)
2845
0
        GetViewData().InsertTab(nTab);
2846
0
    SetTabNo(nTab,true);
2847
0
    pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
2848
0
                                PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
2849
2850
0
    SfxApplication* pSfxApp = SfxGetpApp();
2851
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
2852
0
    pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
2853
2854
0
    pDocSh->PostPaintExtras();
2855
0
    pDocSh->PostPaintGridAll();
2856
0
    pDocSh->SetDocumentModified();
2857
0
}
2858
2859
//  Move/Copy table to another document
2860
2861
void ScViewFunc::MoveTable(sal_uInt16 nDestDocNo, SCTAB nDestTab, bool bCopy,
2862
                           const OUString* pNewTabName, bool bContextMenu,
2863
                           SCTAB nContextMenuSourceTab)
2864
0
{
2865
0
    ScDocument& rDoc       = GetViewData().GetDocument();
2866
0
    ScDocShell* pDocShell  = GetViewData().GetDocShell();
2867
0
    ScDocShell* pDestShell = nullptr;
2868
0
    ScTabViewShell* pDestViewSh = nullptr;
2869
0
    bool bUndo (rDoc.IsUndoEnabled());
2870
0
    bool bRename = pNewTabName && !pNewTabName->isEmpty();
2871
2872
0
    bool bNewDoc = (nDestDocNo == SC_DOC_NEW);
2873
0
    if ( bNewDoc )
2874
0
    {
2875
0
        nDestTab = 0;           // firstly insert
2876
2877
        //  execute without SfxCallMode::RECORD, because already contained in move command
2878
2879
0
        SfxStringItem aItem( SID_FILE_NAME, "private:factory/" + STRING_SCAPP );
2880
0
        SfxStringItem aTarget( SID_TARGETNAME, u"_blank"_ustr );
2881
2882
0
        const SfxPoolItemHolder aResult(GetViewData().GetDispatcher().ExecuteList(
2883
0
            SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON,
2884
0
            { &aItem, &aTarget }));
2885
2886
0
        if (aResult)
2887
0
        {
2888
0
            if ( auto pObjectItem = dynamic_cast<const SfxObjectItem*>(aResult.getItem()) )
2889
0
                pDestShell = dynamic_cast<ScDocShell*>( pObjectItem->GetShell()  );
2890
0
            else if ( auto pViewFrameItem = dynamic_cast<const SfxViewFrameItem*>(aResult.getItem()))
2891
0
            {
2892
0
                SfxViewFrame* pFrm = pViewFrameItem->GetFrame();
2893
0
                if (pFrm)
2894
0
                    pDestShell = dynamic_cast<ScDocShell*>( pFrm->GetObjectShell()  );
2895
0
            }
2896
0
            if (pDestShell)
2897
0
                pDestViewSh = pDestShell->GetBestViewShell();
2898
0
        }
2899
0
    }
2900
0
    else
2901
0
        pDestShell = ScDocShell::GetShellByNum( nDestDocNo );
2902
2903
0
    if (!pDestShell)
2904
0
    {
2905
0
        OSL_FAIL("Destination document not found !!!");
2906
0
        return;
2907
0
    }
2908
2909
0
    ScMarkData& rMark = GetViewData().GetMarkData();
2910
0
    if (bRename && rMark.GetSelectCount() != 1)
2911
0
    {
2912
        // Custom sheet name is provided, but more than one sheet is selected.
2913
        // We don't support this scenario at the moment.
2914
0
        return;
2915
0
    }
2916
2917
0
    ScDocument& rDestDoc = pDestShell->GetDocument();
2918
2919
0
    if (&rDestDoc != &rDoc)
2920
0
    {
2921
0
        if (bNewDoc)
2922
0
        {
2923
0
            while (rDestDoc.GetTableCount() > 1)
2924
0
                rDestDoc.DeleteTab(0);
2925
0
            rDestDoc.RenameTab( 0, u"______42_____"_ustr );
2926
0
        }
2927
2928
0
        SCTAB       nTabCount   = rDoc.GetTableCount();
2929
0
        SCTAB       nTabSelCount = rMark.GetSelectCount();
2930
2931
0
        std::vector<SCTAB> TheTabs;
2932
2933
0
        for(SCTAB i=0; i<nTabCount; ++i)
2934
0
        {
2935
0
            if(rMark.GetTableSelect(i))
2936
0
            {
2937
0
                OUString aTabName;
2938
0
                rDoc.GetName( i, aTabName);
2939
0
                TheTabs.push_back(i);
2940
0
                for(SCTAB j=i+1;j<nTabCount;j++)
2941
0
                {
2942
0
                    if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
2943
0
                    {
2944
0
                        rDoc.GetName( j, aTabName);
2945
0
                        TheTabs.push_back(j);
2946
0
                        i=j;
2947
0
                    }
2948
0
                    else break;
2949
0
                }
2950
0
            }
2951
0
        }
2952
2953
0
        GetFrameWin()->EnterWait();
2954
2955
0
        if (rDoc.GetDrawLayer())
2956
0
            pDestShell->MakeDrawLayer();
2957
2958
0
        if (!bNewDoc && bUndo)
2959
0
            rDestDoc.BeginDrawUndo();      // drawing layer must do its own undo actions
2960
2961
0
        bool bValid = true;
2962
0
        if(nDestTab==SC_TAB_APPEND)
2963
0
            nDestTab=rDestDoc.GetTableCount();
2964
0
        SCTAB nDestTab1=nDestTab;
2965
0
        ScClipParam aParam;
2966
0
        for( size_t j=0; j<TheTabs.size(); ++j, ++nDestTab1 )
2967
0
        {   // insert sheets first and update all references
2968
0
            OUString aName;
2969
0
            if (bRename)
2970
0
                aName = *pNewTabName;
2971
0
            else
2972
0
                rDoc.GetName( TheTabs[j], aName );
2973
2974
0
            rDestDoc.CreateValidTabName( aName );
2975
0
            if ( !rDestDoc.InsertTab( nDestTab1, aName ) )
2976
0
            {
2977
0
                bValid = false;        // total error
2978
0
                break;  // for
2979
0
            }
2980
0
            ScRange aRange( 0, 0, TheTabs[j], rDoc.MaxCol(), rDoc.MaxRow(), TheTabs[j] );
2981
0
            aParam.maRanges.push_back(aRange);
2982
0
        }
2983
0
        rDoc.SetClipParam(aParam);
2984
0
        if ( bValid )
2985
0
        {
2986
0
            nDestTab1 = nDestTab;
2987
0
            for(SCTAB nTab : TheTabs)
2988
0
            {
2989
0
                bValid = pDestShell->TransferTab( *pDocShell, nTab, nDestTab1, false, false );
2990
0
                nDestTab1++;
2991
0
            }
2992
0
        }
2993
0
        if (!bNewDoc && bUndo)
2994
0
        {
2995
0
            OUString sName;
2996
0
            rDestDoc.GetName(nDestTab, sName);
2997
0
            pDestShell->GetUndoManager()->AddUndoAction(
2998
0
                            std::make_unique<ScUndoImportTab>( *pDestShell, nDestTab,
2999
0
                                static_cast<SCTAB>(TheTabs.size())));
3000
3001
0
        }
3002
0
        else
3003
0
        {
3004
0
            pDestShell->GetUndoManager()->Clear();
3005
0
        }
3006
3007
0
        GetFrameWin()->LeaveWait();
3008
3009
0
        if (!bValid)
3010
0
        {
3011
0
            ErrorMessage(STR_TABINSERT_ERROR);
3012
0
            return;
3013
0
        }
3014
3015
0
        if (!bCopy)
3016
0
        {
3017
0
            if(nTabCount!=nTabSelCount)
3018
0
                DeleteTables(TheTabs); // incl. Paint & Undo
3019
0
            else
3020
0
                ErrorMessage(STR_TABREMOVE_ERROR);
3021
0
        }
3022
3023
0
        if (bNewDoc)
3024
0
        {
3025
            //  ChartListenerCollection must be updated before DeleteTab
3026
0
            if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
3027
0
                rDestDoc.UpdateChartListenerCollection();
3028
3029
0
            SCTAB nNumTabsInserted = static_cast<SCTAB>(TheTabs.size());
3030
0
            pDestShell->Broadcast( ScTablesHint( SC_TABS_INSERTED, 0, nNumTabsInserted ) );
3031
3032
0
            rDestDoc.DeleteTab( nNumTabsInserted );   // old first table
3033
0
            pDestShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nNumTabsInserted ) );
3034
3035
0
            if (pDestViewSh)
3036
0
            {
3037
                // Make sure to clear the cached page view after sheet
3038
                // deletion, which still points to the sdr page belonging to
3039
                // the deleted sheet.
3040
0
                SdrView* pSdrView = pDestViewSh->GetScDrawView();
3041
0
                if (pSdrView)
3042
0
                    pSdrView->ClearPageView();
3043
3044
0
                pDestViewSh->TabChanged();      // pages on the drawing layer
3045
0
            }
3046
0
            pDestShell->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
3047
0
                                    PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left |
3048
0
                                    PaintPartFlags::Extras | PaintPartFlags::Size );
3049
            //  PaintPartFlags::Size for outline
3050
0
        }
3051
0
        else
3052
0
        {
3053
0
            pDestShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestTab ) );
3054
0
            pDestShell->PostPaintExtras();
3055
0
            pDestShell->PostPaintGridAll();
3056
0
        }
3057
3058
0
        TheTabs.clear();
3059
3060
0
        pDestShell->SetDocumentModified();
3061
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3062
0
    }
3063
0
    else
3064
0
    {
3065
        // Move or copy within the same document.
3066
0
        SCTAB       nTabCount   = rDoc.GetTableCount();
3067
3068
0
        std::unique_ptr<std::vector<SCTAB>> pSrcTabs(new std::vector<SCTAB>);
3069
0
        std::unique_ptr<std::vector<SCTAB>> pDestTabs(new std::vector<SCTAB>);
3070
0
        std::unique_ptr<std::vector<OUString>> pTabNames(new std::vector<OUString>);
3071
0
        std::unique_ptr<std::vector<OUString>> pDestNames;
3072
0
        pSrcTabs->reserve(nTabCount);
3073
0
        pDestTabs->reserve(nTabCount);
3074
0
        pTabNames->reserve(nTabCount);
3075
0
        OUString aDestName;
3076
3077
0
        if (bContextMenu)
3078
0
        {
3079
0
            OUString aTabName;
3080
0
            rDoc.GetName(nContextMenuSourceTab, aTabName);
3081
0
            pTabNames->push_back(aTabName);
3082
0
        }
3083
0
        else
3084
0
        {
3085
0
            for(SCTAB i=0;i<nTabCount;i++)
3086
0
            {
3087
0
                if(rMark.GetTableSelect(i))
3088
0
                {
3089
0
                    OUString aTabName;
3090
0
                    rDoc.GetName( i, aTabName);
3091
0
                    pTabNames->push_back(aTabName);
3092
3093
0
                    for(SCTAB j=i+1;j<nTabCount;j++)
3094
0
                    {
3095
0
                        if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
3096
0
                        {
3097
0
                            rDoc.GetName( j, aTabName);
3098
0
                            pTabNames->push_back(aTabName);
3099
0
                            i=j;
3100
0
                        }
3101
0
                        else break;
3102
0
                    }
3103
0
                }
3104
0
            }
3105
0
        }
3106
3107
0
        if (bCopy && bUndo)
3108
0
            rDoc.BeginDrawUndo();          // drawing layer must do its own undo actions
3109
3110
0
        rDoc.GetName( nDestTab, aDestName);
3111
0
        SCTAB nDestTab1=nDestTab;
3112
0
        SCTAB nMovTab=0;
3113
0
        for (size_t j = 0, n = pTabNames->size(); j < n; ++j)
3114
0
        {
3115
0
            nTabCount   = rDoc.GetTableCount();
3116
0
            const OUString& rStr = (*pTabNames)[j];
3117
0
            if(!rDoc.GetTable(rStr,nMovTab))
3118
0
            {
3119
0
                nMovTab=nTabCount;
3120
0
            }
3121
0
            if(!rDoc.GetTable(aDestName,nDestTab1))
3122
0
            {
3123
0
                nDestTab1=nTabCount;
3124
0
            }
3125
0
            pDocShell->MoveTable( nMovTab, nDestTab1, bCopy, false );   // Undo is here
3126
3127
            // tdf#43175 - Adjust chart references on every copied sheet
3128
0
            if (bCopy)
3129
0
            {
3130
                // New position of source table after moving
3131
0
                SCTAB nSrcTab = (nDestTab1 <= nMovTab) ? nMovTab + 1 : nMovTab;
3132
                //#i29848# adjust references to data on the copied sheet
3133
0
                ScChartHelper::AdjustRangesOfChartsOnDestinationPage(rDoc, rDestDoc, nSrcTab,
3134
0
                                                                     nDestTab1);
3135
0
            }
3136
3137
0
            if(bCopy && rDoc.IsScenario(nMovTab))
3138
0
            {
3139
0
                OUString aComment;
3140
0
                Color  aColor;
3141
0
                ScScenarioFlags nFlags;
3142
3143
0
                rDoc.GetScenarioData(nMovTab, aComment,aColor, nFlags);
3144
0
                rDoc.SetScenario(nDestTab1,true);
3145
0
                rDoc.SetScenarioData(nDestTab1,aComment,aColor,nFlags);
3146
0
                bool bActive = rDoc.IsActiveScenario(nMovTab );
3147
0
                rDoc.SetActiveScenario( nDestTab1, bActive );
3148
0
                bool bVisible=rDoc.IsVisible(nMovTab);
3149
0
                rDoc.SetVisible(nDestTab1,bVisible );
3150
0
            }
3151
3152
0
            pSrcTabs->push_back(nMovTab);
3153
3154
0
            if(!bCopy)
3155
0
            {
3156
0
                if(!rDoc.GetTable(rStr,nDestTab1))
3157
0
                {
3158
0
                    nDestTab1=nTabCount;
3159
0
                }
3160
0
            }
3161
3162
0
            pDestTabs->push_back(nDestTab1);
3163
0
        }
3164
3165
        // Rename must be done after all sheets have been moved.
3166
0
        if (bRename)
3167
0
        {
3168
0
            pDestNames.reset(new std::vector<OUString>);
3169
0
            size_t n = pDestTabs->size();
3170
0
            pDestNames->reserve(n);
3171
0
            for (size_t j = 0; j < n; ++j)
3172
0
            {
3173
0
                SCTAB nRenameTab = (*pDestTabs)[j];
3174
0
                OUString aTabName = *pNewTabName;
3175
0
                rDoc.CreateValidTabName( aTabName );
3176
0
                pDestNames->push_back(aTabName);
3177
0
                rDoc.RenameTab(nRenameTab, aTabName);
3178
0
            }
3179
0
        }
3180
0
        else
3181
            // No need to keep this around when we are not renaming.
3182
0
            pTabNames.reset();
3183
3184
0
        SCTAB nTab = GetViewData().CurrentTabForData();
3185
3186
0
        if (comphelper::LibreOfficeKit::isActive() && !pSrcTabs->empty())
3187
0
        {
3188
0
            ScModelObj* pModel = pDocShell->GetModel();
3189
0
            SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
3190
0
        }
3191
3192
0
        if (bUndo)
3193
0
        {
3194
0
            if (bCopy)
3195
0
            {
3196
0
                pDocShell->GetUndoManager()->AddUndoAction(
3197
0
                        std::make_unique<ScUndoCopyTab>(
3198
0
                            *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pDestNames)));
3199
0
            }
3200
0
            else
3201
0
            {
3202
0
                pDocShell->GetUndoManager()->AddUndoAction(
3203
0
                        std::make_unique<ScUndoMoveTab>(
3204
0
                            *pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pTabNames), std::move(pDestNames)));
3205
0
            }
3206
0
        }
3207
3208
0
        if (bContextMenu)
3209
0
        {
3210
0
            for (SCTAB i = 0; i < nTabCount; i++)
3211
0
            {
3212
0
                if (rMark.GetTableSelect(i))
3213
0
                    SetTabNo(i, true);
3214
0
            }
3215
0
        }
3216
0
        else
3217
0
        {
3218
0
            SCTAB nNewTab = nDestTab;
3219
0
            if (nNewTab == SC_TAB_APPEND)
3220
0
                nNewTab = rDoc.GetTableCount() - 1;
3221
0
            else if (!bCopy && nTab < nDestTab)
3222
0
                nNewTab--;
3223
3224
0
            SetTabNo(nNewTab, true);
3225
0
        }
3226
0
    }
3227
0
}
3228
3229
void ScViewFunc::ShowTable( const std::vector<OUString>& rNames )
3230
0
{
3231
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
3232
0
    ScDocument& rDoc = pDocSh->GetDocument();
3233
0
    bool bUndo(rDoc.IsUndoEnabled());
3234
3235
0
    std::vector<SCTAB> undoTabs;
3236
0
    SCTAB nPos = 0;
3237
3238
0
    bool bFound(false);
3239
3240
0
    for (const OUString& aName : rNames)
3241
0
    {
3242
0
        if (rDoc.GetTable(aName, nPos))
3243
0
        {
3244
0
            rDoc.SetVisible( nPos, true );
3245
0
            SetTabNo( nPos, true );
3246
0
            SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3247
0
            if (!bFound)
3248
0
                bFound = true;
3249
0
            if (bUndo)
3250
0
                undoTabs.push_back(nPos);
3251
0
        }
3252
0
    }
3253
0
    if (bFound)
3254
0
    {
3255
0
        if (bUndo)
3256
0
        {
3257
0
            pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), true ) );
3258
0
        }
3259
0
        pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
3260
0
        pDocSh->SetDocumentModified();
3261
0
    }
3262
0
}
3263
3264
void ScViewFunc::HideTable( const ScMarkData& rMark, SCTAB nTabToSelect )
3265
0
{
3266
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
3267
0
    ScDocument& rDoc = pDocSh->GetDocument();
3268
0
    bool bUndo(rDoc.IsUndoEnabled());
3269
0
    SCTAB nVisible = 0;
3270
0
    SCTAB nTabCount = rDoc.GetTableCount();
3271
3272
0
    SCTAB nTabSelCount = rMark.GetSelectCount();
3273
3274
    // check to make sure we won't hide all sheets. we need at least one visible at all times.
3275
0
    for ( SCTAB i=0; i < nTabCount && nVisible <= nTabSelCount ; i++ )
3276
0
        if (rDoc.IsVisible(i))
3277
0
            ++nVisible;
3278
3279
0
    if (nVisible <= nTabSelCount)
3280
0
        return;
3281
3282
0
    std::vector<SCTAB> undoTabs;
3283
3284
    // need to take a copy of selectedtabs since it is modified in the loop
3285
0
    const ScMarkData::MarkedTabsType selectedTabs = rMark.GetSelectedTabs();
3286
0
    for (const SCTAB& nTab : selectedTabs)
3287
0
    {
3288
0
        if (rDoc.IsVisible( nTab ))
3289
0
        {
3290
0
            rDoc.SetVisible( nTab, false );
3291
            // Update views
3292
0
            pDocSh->Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
3293
0
            SetTabNo( nTab, true );
3294
            // Store for undo
3295
0
            if (bUndo)
3296
0
                undoTabs.push_back(nTab);
3297
0
        }
3298
0
    }
3299
3300
0
    if (nTabToSelect != -1)
3301
0
        SetTabNo(nTabToSelect);
3302
3303
0
    if (bUndo)
3304
0
    {
3305
0
        pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( *pDocSh, std::move(undoTabs), false ) );
3306
0
    }
3307
3308
    //  Update views
3309
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
3310
0
    pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
3311
0
    pDocSh->SetDocumentModified();
3312
0
}
3313
3314
void ScViewFunc::InsertSpecialChar( const OUString& rStr, const vcl::Font& rFont )
3315
0
{
3316
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
3317
0
    if (!aTester.IsEditable())
3318
0
    {
3319
0
        ErrorMessage(aTester.GetMessageId());
3320
0
        return;
3321
0
    }
3322
3323
0
    const sal_Unicode* pChar    = rStr.getStr();
3324
0
    ScTabViewShell* pViewShell  = GetViewData().GetViewShell();
3325
0
    SvxFontItem     aFontItem( rFont.GetFamilyType(),
3326
0
                               rFont.GetFamilyName(),
3327
0
                               rFont.GetStyleName(),
3328
0
                               rFont.GetPitch(),
3329
0
                               rFont.GetCharSet(),
3330
0
                               ATTR_FONT );
3331
3332
    //  if string contains WEAK characters, set all fonts
3333
0
    SvtScriptType nScript;
3334
0
    ScDocument& rDoc = GetViewData().GetDocument();
3335
0
    if ( rDoc.HasStringWeakCharacters( rStr ) )
3336
0
        nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
3337
0
    else
3338
0
        nScript = rDoc.GetStringScriptType( rStr );
3339
3340
0
    SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, pViewShell->GetPool() );
3341
0
    aSetItem.PutItemForScriptType( nScript, aFontItem );
3342
0
    ApplyUserItemSet( aSetItem.GetItemSet() );
3343
3344
0
    while ( *pChar )
3345
0
        pViewShell->TabKeyInput( KeyEvent( *(pChar++), vcl::KeyCode() ) );
3346
0
}
3347
3348
void ScViewFunc::UpdateLineAttrs( SvxBorderLine&       rLine,
3349
                                  const SvxBorderLine* pDestLine,
3350
                                  const SvxBorderLine* pSrcLine,
3351
                                  bool                 bColor )
3352
0
{
3353
0
    if ( !(pSrcLine && pDestLine) )
3354
0
        return;
3355
3356
0
    if ( bColor )
3357
0
    {
3358
0
        rLine.SetColor      ( pSrcLine->GetColor() );
3359
0
        rLine.SetBorderLineStyle(pDestLine->GetBorderLineStyle());
3360
0
        rLine.SetWidth      ( pDestLine->GetWidth() );
3361
0
    }
3362
0
    else
3363
0
    {
3364
0
        rLine.SetColor      ( pDestLine->GetColor() );
3365
0
        rLine.SetBorderLineStyle(pSrcLine->GetBorderLineStyle());
3366
0
        rLine.SetWidth      ( pSrcLine->GetWidth() );
3367
0
    }
3368
0
}
3369
3370
#define SET_LINE_ATTRIBUTES(LINE,BOXLINE) \
3371
0
    pBoxLine = aBoxItem.Get##LINE();                                \
3372
0
    if ( pBoxLine )                                                 \
3373
0
    {                                                               \
3374
0
        if ( pLine )                                                \
3375
0
        {                                                           \
3376
0
            UpdateLineAttrs( aLine, pBoxLine, pLine, bColorOnly );  \
3377
0
            aBoxItem.SetLine( &aLine, BOXLINE );                    \
3378
0
        }                                                           \
3379
0
        else                                                        \
3380
0
            aBoxItem.SetLine( nullptr, BOXLINE );                      \
3381
0
    }
3382
3383
void ScViewFunc::SetSelectionFrameLines( const SvxBorderLine* pLine,
3384
                                         bool bColorOnly )
3385
0
{
3386
    // Not editable only due to a matrix? Attribute is ok anyhow.
3387
0
    bool bOnlyNotBecauseOfMatrix;
3388
0
    if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
3389
0
    {
3390
0
        ErrorMessage(STR_PROTECTIONERR);
3391
0
        return;
3392
0
    }
3393
3394
0
    ScDocument& rDoc = GetViewData().GetDocument();
3395
0
    ScMarkData aFuncMark( GetViewData().GetMarkData() );       // local copy for UnmarkFiltered
3396
0
    ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
3397
0
    ScDocShell*             pDocSh = GetViewData().GetDocShell();
3398
0
    const ScPatternAttr*    pSelAttrs = GetSelectionPattern();
3399
0
    const SfxItemSet&       rSelItemSet = pSelAttrs->GetItemSet();
3400
3401
0
    const SfxPoolItem*      pBorderAttr = nullptr;
3402
0
    SfxItemState            eItemState = rSelItemSet.GetItemState( ATTR_BORDER, true, &pBorderAttr );
3403
3404
0
    const SfxPoolItem*      pTLBRItem = nullptr;
3405
0
    SfxItemState            eTLBRState = rSelItemSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
3406
3407
0
    const SfxPoolItem*      pBLTRItem = nullptr;
3408
0
    SfxItemState            eBLTRState = rSelItemSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
3409
3410
    // any of the lines visible?
3411
0
    if( !((eItemState != SfxItemState::DEFAULT) || (eTLBRState != SfxItemState::DEFAULT) || (eBLTRState != SfxItemState::DEFAULT)) )
3412
0
        return;
3413
3414
    // none of the lines don't care?
3415
0
    if( (eItemState != SfxItemState::INVALID) && (eTLBRState != SfxItemState::INVALID) && (eBLTRState != SfxItemState::INVALID) )
3416
0
    {
3417
0
        SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aOldSet( *rDoc.GetPool() );
3418
0
        SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *rDoc.GetPool() );
3419
3420
0
        SvxBorderLine           aLine;
3421
3422
0
        if( pBorderAttr )
3423
0
        {
3424
0
            const SvxBorderLine*    pBoxLine = nullptr;
3425
0
            SvxBoxItem      aBoxItem( *static_cast<const SvxBoxItem*>(pBorderAttr) );
3426
0
            SvxBoxInfoItem  aBoxInfoItem( ATTR_BORDER_INNER );
3427
3428
            // here pBoxLine is used
3429
0
            SET_LINE_ATTRIBUTES(Top,SvxBoxItemLine::TOP)
3430
0
            SET_LINE_ATTRIBUTES(Bottom,SvxBoxItemLine::BOTTOM)
3431
0
            SET_LINE_ATTRIBUTES(Left,SvxBoxItemLine::LEFT)
3432
0
            SET_LINE_ATTRIBUTES(Right,SvxBoxItemLine::RIGHT)
3433
3434
0
            aBoxInfoItem.SetLine( aBoxItem.GetTop(), SvxBoxInfoItemLine::HORI );
3435
0
            aBoxInfoItem.SetLine( aBoxItem.GetLeft(), SvxBoxInfoItemLine::VERT );
3436
0
            aBoxInfoItem.ResetFlags(); // set Lines to Valid
3437
3438
0
            aOldSet.Put( *pBorderAttr );
3439
0
            aNewSet.Put( aBoxItem );
3440
0
            aNewSet.Put( aBoxInfoItem );
3441
0
        }
3442
3443
0
        if( pTLBRItem && static_cast<const SvxLineItem*>(pTLBRItem)->GetLine() )
3444
0
        {
3445
0
            SvxLineItem aTLBRItem( *static_cast<const SvxLineItem*>(pTLBRItem) );
3446
0
            UpdateLineAttrs( aLine, aTLBRItem.GetLine(), pLine, bColorOnly );
3447
0
            aTLBRItem.SetLine( &aLine );
3448
0
            aOldSet.Put( *pTLBRItem );
3449
0
            aNewSet.Put( aTLBRItem );
3450
0
        }
3451
3452
0
        if( pBLTRItem && static_cast<const SvxLineItem*>(pBLTRItem)->GetLine() )
3453
0
        {
3454
0
            SvxLineItem aBLTRItem( *static_cast<const SvxLineItem*>(pBLTRItem) );
3455
0
            UpdateLineAttrs( aLine, aBLTRItem.GetLine(), pLine, bColorOnly );
3456
0
            aBLTRItem.SetLine( &aLine );
3457
0
            aOldSet.Put( *pBLTRItem );
3458
0
            aNewSet.Put( aBLTRItem );
3459
0
        }
3460
3461
0
        ApplyAttributes( aNewSet, aOldSet );
3462
0
    }
3463
0
    else // if ( eItemState == SfxItemState::INVALID )
3464
0
    {
3465
0
        aFuncMark.MarkToMulti();
3466
0
        rDoc.ApplySelectionLineStyle( aFuncMark, pLine, bColorOnly );
3467
0
    }
3468
3469
0
    const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
3470
0
    SCCOL nStartCol = aMarkRange.aStart.Col();
3471
0
    SCROW nStartRow = aMarkRange.aStart.Row();
3472
0
    SCTAB nStartTab = aMarkRange.aStart.Tab();
3473
0
    SCCOL nEndCol = aMarkRange.aEnd.Col();
3474
0
    SCROW nEndRow = aMarkRange.aEnd.Row();
3475
0
    SCTAB nEndTab = aMarkRange.aEnd.Tab();
3476
0
    pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
3477
0
                       nEndCol, nEndRow, nEndTab,
3478
0
                       PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
3479
3480
0
    pDocSh->UpdateOle(GetViewData());
3481
0
    pDocSh->SetDocumentModified();
3482
0
}
3483
3484
#undef SET_LINE_ATTRIBUTES
3485
3486
void ScViewFunc::SetValidation( const ScValidationData& rNew )
3487
0
{
3488
0
    ScDocument& rDoc = GetViewData().GetDocument();
3489
0
    sal_uInt32 nIndex = rDoc.AddValidationEntry(rNew);      // for it there is no Undo
3490
0
    SfxUInt32Item aItem( ATTR_VALIDDATA, nIndex );
3491
3492
0
    ApplyAttr( aItem );         // with Paint and Undo...
3493
0
}
3494
3495
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */