Coverage Report

Created: 2025-11-16 09:57

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