Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/view/viewfun3.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <scitems.hxx>
21
#include <svx/svdpage.hxx>
22
#include <sfx2/docfile.hxx>
23
#include <comphelper/classids.hxx>
24
#include <comphelper/lok.hxx>
25
#include <sot/formats.hxx>
26
#include <sot/storage.hxx>
27
#include <vcl/graph.hxx>
28
#include <vcl/svapp.hxx>
29
#include <vcl/weld/MessageDialog.hxx>
30
#include <vcl/weld/weld.hxx>
31
#include <tools/urlobj.hxx>
32
#include <sot/exchange.hxx>
33
#include <memory>
34
#include <vcl/uitest/logger.hxx>
35
#include <vcl/uitest/eventdescription.hxx>
36
#include <vcl/TypeSerializer.hxx>
37
#include <osl/diagnose.h>
38
39
#include <attrib.hxx>
40
#include <patattr.hxx>
41
#include <dociter.hxx>
42
#include <viewfunc.hxx>
43
#include <tabvwsh.hxx>
44
#include <docsh.hxx>
45
#include <docfunc.hxx>
46
#include <undoblk.hxx>
47
#include <refundo.hxx>
48
#include <globstr.hrc>
49
#include <scresid.hxx>
50
#include <global.hxx>
51
#include <transobj.hxx>
52
#include <drwtrans.hxx>
53
#include <chgtrack.hxx>
54
#include <waitoff.hxx>
55
#include <scmod.hxx>
56
#include <inputopt.hxx>
57
#include <warnbox.hxx>
58
#include <drwlayer.hxx>
59
#include <editable.hxx>
60
#include <docuno.hxx>
61
#include <clipparam.hxx>
62
#include <formulacell.hxx>
63
#include <undodat.hxx>
64
#include <drawview.hxx>
65
#include <cliputil.hxx>
66
#include <clipoptions.hxx>
67
#include <gridwin.hxx>
68
#include <SheetViewManager.hxx>
69
#include <uiitems.hxx>
70
#include <com/sun/star/util/XCloneable.hpp>
71
#include <sfx2/lokhelper.hxx>
72
#include <sc.hrc>
73
#include <sfx2/bindings.hxx>
74
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
75
76
using namespace com::sun::star;
77
78
namespace {
79
80
void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& action)
81
0
{
82
0
    EventDescription aDescription;
83
0
    aDescription.aID = "grid_window";
84
0
    aDescription.aAction = action;
85
0
    aDescription.aParameters = std::move(aParameters);
86
0
    aDescription.aParent = "MainWindow";
87
0
    aDescription.aKeyWord = "ScGridWinUIObject";
88
89
0
    UITestLogger::getInstance().logEvent(aDescription);
90
0
}
91
92
/// Result of scanning a selection for matrix formula overlap.
93
struct MatrixOverlapInfo
94
{
95
    ScRangeList maOriginMatrixRanges; ///< Full matrix ranges whose origin IS in the selection
96
    ScRangeList maNonOriginRanges;    ///< Non-origin matrix ranges (origin - top left cell - NOT in selection)
97
98
0
    bool hasNonOriginMatrices() const { return !maNonOriginRanges.empty(); }
99
};
100
101
/// Scan the selection for ALL matrix formula cells and classify them.
102
/// The selection range (rRange) is NOT modified.
103
/// Matrices whose origin IS in the selection are collected in maOriginMatrixRanges.
104
/// Matrices whose origin is NOT in the selection are collected in maNonOriginRanges.
105
MatrixOverlapInfo lcl_DetectMatrixOverlap(ScDocument& rDoc, const ScRange& rRange)
106
0
{
107
0
    MatrixOverlapInfo aInfo;
108
0
    std::vector<ScRange> aAllMatrices;
109
110
0
    auto isKnownMatrix = [&aAllMatrices](const ScRange& rMat) {
111
0
        return std::find(aAllMatrices.begin(), aAllMatrices.end(), rMat) != aAllMatrices.end();
112
0
    };
113
114
0
    auto isInsideKnownMatrix = [&aAllMatrices](const ScAddress& rPos) {
115
0
        return std::any_of(aAllMatrices.begin(), aAllMatrices.end(), [&rPos](const auto& rMat) {
116
0
            return rMat.Contains(rPos);
117
0
        });
118
0
    };
119
120
    // Single pass: scan the original selection for matrix cells.
121
0
    for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
122
0
    {
123
0
        for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
124
0
        {
125
0
            ScAddress aPos(nCol, nRow, rRange.aStart.Tab());
126
0
            if (isInsideKnownMatrix(aPos))
127
0
                continue;
128
129
0
            ScFormulaCell* pFC = rDoc.GetFormulaCell(aPos);
130
0
            if (!pFC || pFC->GetMatrixFlag() == ScMatrixMode::NONE)
131
0
                continue;
132
133
0
            ScRange aMatRange;
134
0
            if (!rDoc.GetMatrixFormulaRange(aPos, aMatRange))
135
0
                continue;
136
137
0
            if (isKnownMatrix(aMatRange))
138
0
                continue;
139
140
0
            aAllMatrices.push_back(aMatRange);
141
0
        }
142
0
    }
143
144
    // Categorise each matrix: origin in selection vs. not.
145
    // Matrices fully contained by the selection need no special handling —
146
    // normal copy/paste already works (HasSelectedBlockMatrixFragment would
147
    // have returned false for these).  See tdf#100582.
148
0
    for (const auto& rMat : aAllMatrices)
149
0
    {
150
0
        if (rRange.Contains(rMat))
151
0
            continue;
152
153
0
        if (rRange.Contains(rMat.aStart))
154
0
            aInfo.maOriginMatrixRanges.push_back(rMat);
155
0
        else
156
0
            aInfo.maNonOriginRanges.push_back(rMat);
157
0
    }
158
159
0
    return aInfo;
160
0
}
161
162
/// For non-origin matrix overlap, try to narrow the clip doc's maRanges to a
163
/// single sub-range that excludes the matrix intersection.  This is only
164
/// attempted for a single non-origin matrix where the geometric subtraction
165
/// yields exactly one rectangle.  For multiple matrices or complex geometry,
166
/// maRanges is left unchanged and paste-time handles it via a temp doc.
167
void lcl_NarrowClipRangesForNonOrigin(ScDocument* pClipDoc,
168
                                      const ScRange& rOriginalRange,
169
                                      const ScRangeList& rMatrixRanges)
170
0
{
171
    // Narrowing optimisation: only for a single non-origin matrix.
172
    // Multiple matrices produce complex shapes — let paste-time handle it.
173
0
    if (rMatrixRanges.size() != 1)
174
0
        return;
175
176
0
    ScRangeList aSubRanges = rOriginalRange.Subtract(rMatrixRanges[0]);
177
178
    // For a single sub-range, the normal single-range paste handles it.
179
    // For 0 or 2+ sub-ranges, keep the original range — paste-time will
180
    // use the temp doc fallback (clear matrix intersections, bSkipEmpty).
181
0
    ScClipParam& rStoredParam = pClipDoc->GetClipParam();
182
0
    if (aSubRanges.size() == 1)
183
0
        rStoredParam.maRanges = std::move(aSubRanges);
184
0
}
185
186
}
187
188
//  GlobalName of writer-DocShell from comphelper/classids.hxx
189
190
//      C U T
191
192
void ScViewFunc::CutToClip()
193
0
{
194
0
    UpdateInputLine();
195
196
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestView(this);
197
0
    if (!aTester.IsEditable())                  // selection editable?
198
0
    {
199
0
        ErrorMessage( aTester.GetMessageId() );
200
0
        return;
201
0
    }
202
203
0
    ScRange aRange;                             // delete this range
204
0
    if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
205
0
    {
206
0
        ScDocument& rDoc = GetViewData().GetDocument();
207
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
208
0
        ScMarkData& rMark = GetViewData().GetMarkData();
209
0
        const bool bRecord(rDoc.IsUndoEnabled());                  // Undo/Redo
210
211
0
        ScDocShellModificator aModificator( *pDocSh );
212
213
0
        if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )          // mark the range if not marked yet
214
0
        {
215
0
            DoneBlockMode();
216
0
            InitOwnBlockMode( aRange );
217
0
            rMark.SetMarkArea( aRange );
218
0
            MarkDataChanged();
219
0
        }
220
221
0
        CopyToClip( nullptr, true, false, true/*bIncludeObjects*/ );           // copy to clipboard
222
223
0
        ScAddress aOldEnd( aRange.aEnd );       //  combined cells in this range?
224
0
        rDoc.ExtendMerge( aRange, true );
225
226
0
        ScDocumentUniquePtr pUndoDoc;
227
0
        if ( bRecord )
228
0
        {
229
0
            pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
230
0
            pUndoDoc->InitUndoSelected( rDoc, rMark );
231
            // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
232
0
            ScRange aCopyRange = aRange;
233
0
            aCopyRange.aStart.SetTab(0);
234
0
            aCopyRange.aEnd.SetTab(rDoc.GetTableCount()-1);
235
0
            rDoc.CopyToDocument( aCopyRange, (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc );
236
0
            rDoc.BeginDrawUndo();
237
0
        }
238
239
0
        sal_uInt16 nExtFlags = 0;
240
0
        pDocSh->UpdatePaintExt( nExtFlags, aRange );
241
242
0
        rMark.MarkToMulti();
243
0
        rDoc.DeleteSelection( InsertDeleteFlags::ALL, rMark );
244
0
        rDoc.DeleteObjectsInSelection( rMark );
245
0
        rMark.MarkToSimple();
246
247
0
        if ( !AdjustRowHeight( aRange.aStart.Row(), aRange.aEnd.Row(), true ) )
248
0
            pDocSh->PostPaint( aRange, PaintPartFlags::Grid, nExtFlags );
249
250
0
        if ( bRecord )                          // Draw-Undo now available
251
0
            pDocSh->GetUndoManager()->AddUndoAction(
252
0
                std::make_unique<ScUndoCut>( *pDocSh, aRange, aOldEnd, rMark, std::move(pUndoDoc) ) );
253
254
0
        aModificator.SetDocumentModified();
255
0
        pDocSh->UpdateOle(GetViewData());
256
257
0
        CellContentChanged();
258
259
0
        OUString aStartAddress =  aRange.aStart.GetColRowString();
260
0
        OUString aEndAddress = aRange.aEnd.GetColRowString();
261
262
0
        collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"CUT"_ustr);
263
0
    }
264
0
    else
265
0
        ErrorMessage( STR_NOMULTISELECT );
266
0
}
267
268
//      C O P Y
269
270
bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
271
0
{
272
0
    ScRange aRange;
273
0
    ScMarkType eMarkType = GetViewData().GetSimpleArea( aRange );
274
0
    ScMarkData& rMark = GetViewData().GetMarkData();
275
0
    bool bDone = false;
276
277
0
    if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
278
0
    {
279
0
       ScRangeList aRangeList( aRange );
280
0
       bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
281
0
    }
282
0
    else if (eMarkType == SC_MARK_MULTI)
283
0
    {
284
0
        ScRangeList aRangeList;
285
0
        rMark.MarkToSimple();
286
0
        rMark.FillRangeListWithMarks(&aRangeList, false);
287
0
        bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
288
0
    }
289
0
    else
290
0
    {
291
0
        if (!bApi)
292
0
            ErrorMessage(STR_NOMULTISELECT);
293
0
    }
294
0
    if( !bCut ){
295
0
        OUString aStartAddress =  aRange.aStart.GetColRowString();
296
0
        OUString aEndAddress = aRange.aEnd.GetColRowString();
297
0
        collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"COPY"_ustr);
298
0
    }
299
0
    return bDone;
300
0
}
301
302
// Copy the content of the Range into clipboard.
303
bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
304
0
{
305
0
    if ( rRanges.empty() )
306
0
        return false;
307
0
    if ( bStopEdit )
308
0
        UpdateInputLine();
309
310
0
    bool bDone;
311
0
    if (rRanges.size() > 1) // isMultiRange
312
0
        bDone = CopyToClipMultiRange(pClipDoc, rRanges, bCut, bApi, bIncludeObjects);
313
0
    else
314
0
        bDone = CopyToClipSingleRange(pClipDoc, rRanges, bCut, bIncludeObjects);
315
316
0
    return bDone;
317
0
}
318
319
bool ScViewFunc::CopyToClipSingleRange( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bIncludeObjects )
320
0
{
321
0
    ScRange aRange = rRanges[0];
322
0
    ScDocument& rDoc = GetViewData().GetDocument();
323
0
    ScMarkData& rMark = GetViewData().GetMarkData();
324
325
    // Check for partial matrix overlap (fragment).  Fully-contained
326
    // matrices are fine — only fragments need special handling.
327
0
    bool bHasFragment = rDoc.HasSelectedBlockMatrixFragment(
328
0
            aRange.aStart.Col(), aRange.aStart.Row(),
329
0
            aRange.aEnd.Col(), aRange.aEnd.Row(), rMark);
330
331
0
    MatrixOverlapInfo aMatInfo;
332
0
    ScRange aCopyRange = aRange;
333
334
0
    if (bHasFragment)
335
0
    {
336
        // Classify each partial overlap as origin-in-selection vs. not.
337
0
        aMatInfo = lcl_DetectMatrixOverlap(rDoc, aRange);
338
339
        // Expand the internal copy range to include origin matrices
340
        // so their formulas end up in the clip doc.
341
0
        for (size_t i = 0; i < aMatInfo.maOriginMatrixRanges.size(); ++i)
342
0
            aCopyRange.ExtendTo(aMatInfo.maOriginMatrixRanges[i]);
343
0
    }
344
345
0
    ScClipParam aClipParam( aCopyRange, bCut );
346
347
0
    if (bHasFragment)
348
0
    {
349
0
        aClipParam.maOriginalRange = aRange;
350
0
        aClipParam.maMatrixRanges = aMatInfo.maNonOriginRanges;
351
0
        aClipParam.maOriginMatrixRanges = aMatInfo.maOriginMatrixRanges;
352
0
    }
353
354
0
    std::shared_ptr<ScDocument> pSysClipDoc;
355
0
    if ( !pClipDoc )                                    // no clip doc specified
356
0
    {
357
        // Create one (deleted by ScTransferObj), and copy into system.
358
0
        pSysClipDoc = std::make_shared<ScDocument>( SCDOCMODE_CLIP );
359
0
        pClipDoc = pSysClipDoc.get();
360
0
    }
361
0
    if ( !bCut )
362
0
    {
363
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
364
0
        if ( pChangeTrack )
365
0
            pChangeTrack->ResetLastCut();
366
0
    }
367
368
0
    if ( pSysClipDoc && bIncludeObjects )
369
0
    {
370
0
        bool bAnyOle = rDoc.HasOLEObjectsInArea( aCopyRange );
371
        // Update ScGlobal::xDrawClipDocShellRef.
372
0
        ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle, pSysClipDoc ) );
373
0
    }
374
375
    // is this necessary?, will setting the doc id upset the
376
    // following paste operation with range? would be nicer to just set this always
377
    // and lose the 'if' above
378
0
    aClipParam.setSourceDocID( rDoc.GetDocumentID() );
379
380
0
    if (ScDocShell* pObjectShell = rDoc.GetDocumentShell())
381
0
    {
382
        // Copy document properties from pObjectShell to pClipDoc (to its clip options, as it has no object shell).
383
0
        uno::Reference<util::XCloneable> xCloneable(pObjectShell->getDocProperties(), uno::UNO_QUERY_THROW);
384
0
        std::unique_ptr<ScClipOptions> pOptions(new ScClipOptions);
385
0
        pOptions->m_xDocumentProperties.set(xCloneable->createClone(), uno::UNO_QUERY);
386
0
        pClipDoc->SetClipOptions(std::move(pOptions));
387
0
    }
388
389
0
    rDoc.CopyToClip( aClipParam, pClipDoc, &rMark, false, bIncludeObjects );
390
391
0
    if (bHasFragment)
392
0
    {
393
        // Reset maRanges in the clip doc to the original selection so that
394
        // marching ants (UpdateCopySourceOverlay) show only what the user selected.
395
0
        pClipDoc->GetClipParam().maRanges = ScRangeList( aRange );
396
0
    }
397
398
0
    if (ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer())
399
0
    {
400
0
        ScClipParam& rClipDocClipParam = pClipDoc->GetClipParam();
401
0
        ScRangeListVector& rRangesVector = rClipDocClipParam.maProtectedChartRangesVector;
402
0
        SCTAB nTabCount = pClipDoc->GetTableCount();
403
0
        for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
404
0
        {
405
0
            SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
406
0
            if ( pPage )
407
0
            {
408
0
                ScChartHelper::FillProtectedChartRangesVector( rRangesVector, rDoc, pPage );
409
0
            }
410
0
        }
411
0
    }
412
413
0
    if ( pSysClipDoc )
414
0
    {
415
0
        ScDrawLayer::SetGlobalDrawPersist(nullptr);
416
0
        ScGlobal::SetClipDocName( rDoc.GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
417
0
    }
418
0
    pClipDoc->ExtendMerge( aCopyRange, true );
419
420
0
    if (bHasFragment && aMatInfo.hasNonOriginMatrices())
421
0
        lcl_NarrowClipRangesForNonOrigin(pClipDoc, aRange, aMatInfo.maNonOriginRanges);
422
423
0
    if ( pSysClipDoc )
424
0
    {
425
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
426
0
        TransferableObjectDescriptor aObjDesc;
427
0
        pDocSh->FillTransferableObjectDescriptor( aObjDesc );
428
0
        aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
429
        // maSize is set in ScTransferObj ctor
430
431
0
        rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( pSysClipDoc, std::move(aObjDesc) ));
432
0
        if ( ScGlobal::xDrawClipDocShellRef.is() )
433
0
        {
434
0
            SfxObjectShellRef aPersistRef(ScGlobal::xDrawClipDocShellRef);
435
0
            pTransferObj->SetDrawPersist( aPersistRef );// keep persist for ole objects alive
436
0
        }
437
0
        pTransferObj->CopyToClipboard( GetActiveWin() );
438
0
    }
439
440
0
    return true;
441
0
}
442
443
bool ScViewFunc::CopyToClipMultiRange( const ScDocument* pInputClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects )
444
0
{
445
0
    if (bCut)
446
0
    {
447
        // We don't support cutting of multi-selections.
448
0
        if (!bApi)
449
0
            ErrorMessage(STR_NOMULTISELECT);
450
0
        return false;
451
0
    }
452
0
    if (pInputClipDoc)
453
0
    {
454
        // TODO: What's this for?
455
0
        if (!bApi)
456
0
            ErrorMessage(STR_NOMULTISELECT);
457
0
        return false;
458
0
    }
459
460
0
    ScClipParam aClipParam( rRanges[0], bCut );
461
0
    aClipParam.maRanges = rRanges;
462
0
    ScDocument& rDoc = GetViewData().GetDocument();
463
0
    ScMarkData& rMark = GetViewData().GetMarkData();
464
0
    bool bDone = false;
465
0
    bool bSuccess = false;
466
0
    aClipParam.mbCutMode = false;
467
468
0
    do
469
0
    {
470
0
        ScDocumentUniquePtr pDocClip(new ScDocument(SCDOCMODE_CLIP));
471
472
        // Check for geometrical feasibility of the ranges.
473
0
        bool bValidRanges = true;
474
0
        ScRange const * p = &aClipParam.maRanges.front();
475
0
        SCCOL nPrevColDelta = 0;
476
0
        SCROW nPrevRowDelta = 0;
477
0
        SCCOL nPrevCol = p->aStart.Col();
478
0
        SCROW nPrevRow = p->aStart.Row();
479
0
        SCCOL nPrevColSize = p->aEnd.Col() - p->aStart.Col() + 1;
480
0
        SCROW nPrevRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
481
0
        for ( size_t i = 1; i < aClipParam.maRanges.size(); ++i )
482
0
        {
483
0
            p = &aClipParam.maRanges[i];
484
485
            // Multi-range copy has no origin-matrix expansion logic,
486
            // so block copies that include matrix fragments.
487
0
            if ( rDoc.HasSelectedBlockMatrixFragment(
488
0
                p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark) )
489
0
            {
490
0
                if (!bApi)
491
0
                    ErrorMessage(STR_MATRIXFRAGMENTERR);
492
0
                return false;
493
0
            }
494
495
0
            SCCOL nColDelta = p->aStart.Col() - nPrevCol;
496
0
            SCROW nRowDelta = p->aStart.Row() - nPrevRow;
497
498
0
            if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
499
0
            {
500
0
                bValidRanges = false;
501
0
                break;
502
0
            }
503
504
0
            if (aClipParam.meDirection == ScClipParam::Unspecified)
505
0
            {
506
0
                if (nColDelta)
507
0
                    aClipParam.meDirection = ScClipParam::Column;
508
0
                if (nRowDelta)
509
0
                    aClipParam.meDirection = ScClipParam::Row;
510
0
            }
511
512
0
            SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
513
0
            SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
514
515
0
            if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
516
0
            {
517
                // column-oriented ranges must have identical row size.
518
0
                bValidRanges = false;
519
0
                break;
520
0
            }
521
0
            if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
522
0
            {
523
                // likewise, row-oriented ranges must have identical
524
                // column size.
525
0
                bValidRanges = false;
526
0
                break;
527
0
            }
528
529
0
            nPrevCol = p->aStart.Col();
530
0
            nPrevRow = p->aStart.Row();
531
0
            nPrevColDelta = nColDelta;
532
0
            nPrevRowDelta = nRowDelta;
533
0
            nPrevColSize  = nColSize;
534
0
            nPrevRowSize  = nRowSize;
535
0
        }
536
0
        if (!bValidRanges)
537
0
            break;
538
0
        rDoc.CopyToClip(aClipParam, pDocClip.get(), &rMark, false, bIncludeObjects );
539
540
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
541
0
        if ( pChangeTrack )
542
0
            pChangeTrack->ResetLastCut();   // no more cut-mode
543
544
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
545
0
        TransferableObjectDescriptor aObjDesc;
546
0
        pDocSh->FillTransferableObjectDescriptor( aObjDesc );
547
0
        aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
548
        // maSize is set in ScTransferObj ctor
549
550
0
        rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( std::move(pDocClip), std::move(aObjDesc) ));
551
0
        if ( ScGlobal::xDrawClipDocShellRef.is() )
552
0
        {
553
0
            SfxObjectShellRef aPersistRef(ScGlobal::xDrawClipDocShellRef);
554
0
            pTransferObj->SetDrawPersist( aPersistRef );    // keep persist for ole objects alive
555
0
        }
556
0
        pTransferObj->CopyToClipboard( GetActiveWin() );    // system clipboard
557
558
0
        bSuccess = true;
559
0
    }
560
0
    while (false);
561
562
0
    if (!bSuccess && !bApi)
563
0
        ErrorMessage(STR_NOMULTISELECT);
564
565
0
    bDone = bSuccess;
566
567
0
    return bDone;
568
0
}
569
570
rtl::Reference<ScTransferObj> ScViewFunc::CopyToTransferable()
571
0
{
572
0
    ScRange aRange;
573
0
    auto eMarkType = GetViewData().GetSimpleArea( aRange );
574
0
    if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
575
0
    {
576
0
        ScDocument& rDoc = GetViewData().GetDocument();
577
0
        ScMarkData& rMark = GetViewData().GetMarkData();
578
579
0
        bool bHasFragment = rDoc.HasSelectedBlockMatrixFragment(
580
0
                aRange.aStart.Col(), aRange.aStart.Row(),
581
0
                aRange.aEnd.Col(), aRange.aEnd.Row(), rMark);
582
583
0
        MatrixOverlapInfo aMatInfo;
584
0
        ScRange aCopyRange = aRange;
585
586
0
        if (bHasFragment)
587
0
        {
588
0
            aMatInfo = lcl_DetectMatrixOverlap(rDoc, aRange);
589
0
            for (size_t i = 0; i < aMatInfo.maOriginMatrixRanges.size(); ++i)
590
0
                aCopyRange.ExtendTo(aMatInfo.maOriginMatrixRanges[i]);
591
0
        }
592
593
0
        ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));    // create one (deleted by ScTransferObj)
594
595
0
        bool bAnyOle = rDoc.HasOLEObjectsInArea( aCopyRange, &rMark );
596
0
        ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
597
598
0
        ScClipParam aClipParam(aCopyRange, false);
599
600
0
        if (bHasFragment)
601
0
        {
602
0
            aClipParam.maOriginalRange = aRange;
603
0
            aClipParam.maMatrixRanges = aMatInfo.maNonOriginRanges;
604
0
            aClipParam.maOriginMatrixRanges = aMatInfo.maOriginMatrixRanges;
605
0
        }
606
607
0
        rDoc.CopyToClip(aClipParam, pClipDoc.get(), &rMark, false, true);
608
609
0
        if (bHasFragment)
610
0
            pClipDoc->GetClipParam().maRanges = ScRangeList( aRange );
611
612
0
        ScDrawLayer::SetGlobalDrawPersist(nullptr);
613
0
        pClipDoc->ExtendMerge( aCopyRange, true );
614
615
0
        if (bHasFragment && aMatInfo.hasNonOriginMatrices())
616
0
            lcl_NarrowClipRangesForNonOrigin(pClipDoc.get(), aRange, aMatInfo.maNonOriginRanges);
617
618
0
        ScDocShell* pDocSh = GetViewData().GetDocShell();
619
0
        TransferableObjectDescriptor aObjDesc;
620
0
        pDocSh->FillTransferableObjectDescriptor( aObjDesc );
621
0
        aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
622
0
        return new ScTransferObj( std::move(pClipDoc), std::move(aObjDesc) );
623
0
    }
624
0
    else if (eMarkType == SC_MARK_MULTI)
625
0
    {
626
0
        ScDocumentUniquePtr pClipDoc(new ScDocument(SCDOCMODE_CLIP));
627
        // This takes care of the input line and calls CopyToClipMultiRange() for us.
628
0
        CopyToClip(pClipDoc.get(), aRange, /*bCut=*/false, /*bApi=*/true);
629
0
        TransferableObjectDescriptor aObjDesc;
630
0
        return new ScTransferObj(std::move(pClipDoc), std::move(aObjDesc));
631
0
    }
632
633
0
    return nullptr;
634
0
}
635
636
//      P A S T E
637
638
void ScViewFunc::PasteDraw()
639
0
{
640
0
    ScViewData& rViewData = GetViewData();
641
0
    SCCOL nPosX = rViewData.GetCurX();
642
0
    SCROW nPosY = rViewData.GetCurY();
643
0
    vcl::Window* pWin = GetActiveWin();
644
0
    Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY,
645
0
                                     rViewData.GetActivePart() ) );
646
0
    const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewData.GetActiveWin()));
647
0
    if (pDrawClip)
648
0
    {
649
0
        const OUString& aSrcShellID = pDrawClip->GetShellID();
650
0
        OUString aDestShellID = SfxObjectShell::CreateShellID(rViewData.GetDocShell());
651
0
        PasteDraw(aPos, pDrawClip->GetModel(), false, aSrcShellID, aDestShellID);
652
0
    }
653
0
}
654
655
void ScViewFunc::PasteFromSystem(bool useSavedPrefs)
656
0
{
657
0
    UpdateInputLine();
658
659
0
    vcl::Window* pWin = GetActiveWin();
660
0
    css::uno::Reference<css::datatransfer::XTransferable2> xTransferable2(ScTabViewShell::GetClipData(pWin));
661
0
    const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(xTransferable2);
662
    // keep a reference in case the clipboard is changed during PasteFromClip
663
0
    const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(xTransferable2);
664
0
    if (pOwnClip)
665
0
    {
666
0
        PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
667
0
                        ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
668
0
                        true );     // allow warning dialog
669
0
    }
670
0
    else if (pDrawClip)
671
0
        PasteDraw();
672
0
    else
673
0
    {
674
0
        TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
675
676
0
        {
677
0
            SotClipboardFormatId nBiff12= SotExchange::RegisterFormatName(u"Biff12"_ustr);
678
0
            SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr);
679
0
            SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr);
680
681
0
            SotClipboardFormatId nFormat; // output param for GetExchangeAction
682
0
            sal_uInt8 nEventAction;      // output param for GetExchangeAction
683
684
0
            uno::Reference<css::datatransfer::XTransferable> xTransferable( aDataHelper.GetXTransferable() );
685
0
            sal_uInt8 nAction = SotExchange::GetExchangeAction(
686
0
                                    aDataHelper.GetDataFlavorExVector(),
687
0
                                    SotExchangeDest::SCDOC_FREE_AREA,
688
0
                                    EXCHG_IN_ACTION_COPY,
689
0
                                    EXCHG_IN_ACTION_DEFAULT,
690
0
                                    nFormat, nEventAction, SotClipboardFormatId::NONE,
691
0
                                    &xTransferable );
692
693
0
            if ( nAction != EXCHG_INOUT_ACTION_NONE )
694
0
            {
695
0
                switch( nAction )
696
0
                {
697
0
                case EXCHG_OUT_ACTION_INSERT_SVXB:
698
0
                case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
699
0
                case EXCHG_OUT_ACTION_INSERT_BITMAP:
700
0
                case EXCHG_OUT_ACTION_INSERT_GRAPH:
701
                    // SotClipboardFormatId::BITMAP
702
                    // SotClipboardFormatId::PNG
703
                    // SotClipboardFormatId::GDIMETAFILE
704
                    // SotClipboardFormatId::SVXB
705
0
                    PasteFromSystem(nFormat);
706
0
                    break;
707
0
                default:
708
0
                    nAction = EXCHG_INOUT_ACTION_NONE;
709
0
                }
710
0
            }
711
712
0
            if ( nAction == EXCHG_INOUT_ACTION_NONE )
713
0
            {
714
                //  first SvDraw-model, then drawing
715
                //  (only one drawing is allowed)
716
717
0
                if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
718
0
                {
719
                    // special case for tables from drawing
720
0
                    if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
721
0
                    {
722
0
                        PasteFromSystem( SotClipboardFormatId::RTF );
723
0
                    }
724
0
                    else if( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
725
0
                    {
726
0
                        PasteFromSystem( SotClipboardFormatId::RICHTEXT );
727
0
                    }
728
0
                    else
729
0
                    {
730
0
                        PasteFromSystem( SotClipboardFormatId::DRAWING );
731
0
                    }
732
0
                }
733
0
                else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
734
0
                {
735
                    //  If it's a Writer object, insert RTF instead of OLE
736
737
                    //  Else, if the class id is all-zero, and SYLK is available,
738
                    //  it probably is spreadsheet cells that have been put
739
                    //  on the clipboard by OOo, so use the SYLK. (fdo#31077)
740
741
0
                    bool bDoRtf = false;
742
0
                    TransferableObjectDescriptor aObjDesc;
743
0
                    if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
744
0
                    {
745
0
                        bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
746
0
                                     aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
747
0
                                   && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
748
0
                    }
749
0
                    if ( bDoRtf )
750
0
                        PasteFromSystem( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT );
751
0
                    else if ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
752
0
                              && aDataHelper.HasFormat( SotClipboardFormatId::SYLK ))
753
0
                        PasteFromSystem( SotClipboardFormatId::SYLK );
754
0
                    else
755
0
                        PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE );
756
0
                }
757
0
                else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
758
0
                    PasteFromSystem( SotClipboardFormatId::LINK_SOURCE );
759
                    // the following format can not affect scenario from #89579#
760
0
                else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
761
0
                    PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE );
762
                    // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
763
0
                else if (aDataHelper.HasFormat(nBiff12))      // before xxx_OLE formats
764
0
                    PasteFromSystem(nBiff12);
765
0
                else if (aDataHelper.HasFormat(nBiff8))
766
0
                    PasteFromSystem(nBiff8);
767
0
                else if (aDataHelper.HasFormat(nBiff5))
768
0
                    PasteFromSystem(nBiff5);
769
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
770
0
                    PasteFromSystem(SotClipboardFormatId::RTF);
771
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
772
0
                    PasteFromSystem(SotClipboardFormatId::RICHTEXT);
773
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
774
0
                    PasteFromSystem(SotClipboardFormatId::HTML, false, useSavedPrefs);
775
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
776
0
                    PasteFromSystem(SotClipboardFormatId::BITMAP);
777
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
778
0
                    PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE);
779
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
780
0
                    PasteFromSystem(SotClipboardFormatId::SYLK);
781
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
782
0
                    PasteFromSystem(SotClipboardFormatId::STRING_TSVC);
783
0
                else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
784
0
                    PasteFromSystem(SotClipboardFormatId::STRING);
785
                // xxx_OLE formats come last, like in SotExchange tables
786
0
                else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
787
0
                    PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE );
788
0
                else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
789
0
                    PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
790
0
            }
791
0
        }
792
0
    }
793
    //  no exception-> SID_PASTE has FastCall-flag from idl
794
    //  will be called in case of empty clipboard (#42531#)
795
0
}
796
797
void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
798
0
{
799
0
    if (auto pOwnClip = dynamic_cast<ScTransferObj*>(rxTransferable.get()))
800
0
    {
801
0
        PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
802
0
                        ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
803
0
                        true );     // allow warning dialog
804
0
    }
805
0
    else if (auto pDrawClip = dynamic_cast<ScDrawTransferObj*>(rxTransferable.get()))
806
0
    {
807
0
        ScViewData& rViewData = GetViewData();
808
0
        SCCOL nPosX = rViewData.GetCurX();
809
0
        SCROW nPosY = rViewData.GetCurY();
810
0
        vcl::Window* pWin = GetActiveWin();
811
0
        Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY, rViewData.GetActivePart() ) );
812
0
        PasteDraw(
813
0
            aPos, pDrawClip->GetModel(), false,
814
0
            pDrawClip->GetShellID(), SfxObjectShell::CreateShellID(rViewData.GetDocShell()));
815
0
    }
816
0
    else
817
0
    {
818
0
            TransferableDataHelper aDataHelper( rxTransferable );
819
0
            SotClipboardFormatId nBiff12 = SotExchange::RegisterFormatName(u"Biff12"_ustr);
820
0
            SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr);
821
0
            SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr);
822
0
            SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
823
                //  first SvDraw-model, then drawing
824
                //  (only one drawing is allowed)
825
826
0
            if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
827
0
                nFormatId = SotClipboardFormatId::DRAWING;
828
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::SVXB ))
829
0
                nFormatId = SotClipboardFormatId::SVXB;
830
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
831
0
            {
832
                //  If it's a Writer object, insert RTF instead of OLE
833
0
                bool bDoRtf = false;
834
0
                TransferableObjectDescriptor aObjDesc;
835
0
                if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
836
0
                {
837
0
                    bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
838
0
                                 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
839
0
                               && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ));
840
0
                }
841
0
                if ( bDoRtf )
842
0
                    nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
843
0
                else
844
0
                    nFormatId = SotClipboardFormatId::EMBED_SOURCE;
845
0
            }
846
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
847
0
                nFormatId = SotClipboardFormatId::LINK_SOURCE;
848
            // the following format can not affect scenario from #89579#
849
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
850
0
                nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
851
            // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
852
0
            else if (aDataHelper.HasFormat(nBiff12))      // before xxx_OLE formats
853
0
                nFormatId = nBiff12;
854
0
            else if (aDataHelper.HasFormat(nBiff8))
855
0
                nFormatId = nBiff8;
856
0
            else if (aDataHelper.HasFormat(nBiff5))
857
0
                nFormatId = nBiff5;
858
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
859
0
                nFormatId = SotClipboardFormatId::RTF;
860
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
861
0
                nFormatId = SotClipboardFormatId::RICHTEXT;
862
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
863
0
                nFormatId = SotClipboardFormatId::HTML;
864
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
865
0
                nFormatId = SotClipboardFormatId::HTML_SIMPLE;
866
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
867
0
                nFormatId = SotClipboardFormatId::SYLK;
868
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
869
0
                nFormatId = SotClipboardFormatId::STRING_TSVC;
870
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
871
0
                nFormatId = SotClipboardFormatId::STRING;
872
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::GDIMETAFILE))
873
0
                nFormatId = SotClipboardFormatId::GDIMETAFILE;
874
0
            else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
875
0
                nFormatId = SotClipboardFormatId::BITMAP;
876
            // xxx_OLE formats come last, like in SotExchange tables
877
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
878
0
                nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
879
0
            else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
880
0
                nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
881
0
            else
882
0
                return;
883
884
0
            PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
885
0
                GetViewData().GetCurX(), GetViewData().GetCurY(), nullptr );
886
0
    }
887
0
}
888
889
bool ScViewFunc::PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi, bool useSavedPrefs )
890
0
{
891
0
    UpdateInputLine();
892
893
0
    bool bRet = true;
894
0
    vcl::Window* pWin = GetActiveWin();
895
    // keep a reference in case the clipboard is changed during PasteFromClip
896
0
    const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
897
0
    if ( nFormatId == SotClipboardFormatId::NONE && pOwnClip )
898
0
    {
899
0
        PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
900
0
                        ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
901
0
                        !bApi );        // allow warning dialog
902
0
    }
903
0
    else
904
0
    {
905
0
        TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
906
0
        if ( !aDataHelper.GetTransferable().is() )
907
0
            return false;
908
909
0
        SCCOL nPosX = 0;
910
0
        SCROW nPosY = 0;
911
912
0
        ScViewData& rViewData = GetViewData();
913
0
        ScRange aRange;
914
0
        if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
915
0
        {
916
0
            nPosX = aRange.aStart.Col();
917
0
            nPosY = aRange.aStart.Row();
918
0
        }
919
0
        else
920
0
        {
921
0
            nPosX = rViewData.GetCurX();
922
0
            nPosY = rViewData.GetCurY();
923
0
        }
924
925
0
        bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
926
0
                                nPosX, nPosY,
927
0
                                nullptr, false, !bApi, useSavedPrefs );       // allow warning dialog
928
929
0
        if ( !bRet && !bApi )
930
0
        {
931
0
            ErrorMessage(STR_PASTE_ERROR);
932
0
        }
933
0
        else if (comphelper::LibreOfficeKit::isActive())
934
0
        {
935
0
            ScTabViewShell* pTabViewShell = rViewData.GetViewShell();
936
0
            pTabViewShell->OnLOKSetWidthOrHeight(rViewData.GetCurX(), true);
937
0
            pTabViewShell->OnLOKSetWidthOrHeight(rViewData.GetCurY(), false);
938
939
0
            ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pTabViewShell, true /* bColumns */, true /* bRows */,
940
0
                true /* bSizes */, false /* bHidden */, false /* bFiltered */, false /* bGroups */, rViewData.CurrentTabForData());
941
0
        }
942
0
    }
943
0
    return bRet;
944
0
}
945
946
//      P A S T E
947
948
bool ScViewFunc::PasteOnDrawObjectLinked(
949
    const uno::Reference<datatransfer::XTransferable>& rxTransferable,
950
    SdrObject& rHitObj)
951
0
{
952
0
    TransferableDataHelper aDataHelper( rxTransferable );
953
954
0
    if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
955
0
    {
956
0
        if (ScDrawView* pScDrawView = GetScDrawView())
957
0
            if (std::unique_ptr<SvStream> xStm = aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB ) )
958
0
            {
959
0
                Graphic aGraphic;
960
0
                TypeSerializer aSerializer(*xStm);
961
0
                aSerializer.readGraphic(aGraphic);
962
963
0
                const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
964
965
0
                if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, u""_ustr ))
966
0
                {
967
0
                    return true;
968
0
                }
969
0
            }
970
0
    }
971
0
    else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
972
0
    {
973
0
        GDIMetaFile aMtf;
974
0
        ScDrawView* pScDrawView = GetScDrawView();
975
976
0
        if( pScDrawView && aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
977
0
        {
978
0
            const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
979
980
0
            if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, u""_ustr ))
981
0
            {
982
0
                return true;
983
0
            }
984
0
        }
985
0
    }
986
0
    else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) || aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
987
0
    {
988
0
        Bitmap aBmp;
989
0
        ScDrawView* pScDrawView = GetScDrawView();
990
991
0
        if (pScDrawView && aDataHelper.GetBitmap(SotClipboardFormatId::BITMAP, aBmp))
992
0
        {
993
0
            const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
994
995
0
            if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmp), aBeginUndo, u""_ustr ))
996
0
            {
997
0
                return true;
998
0
            }
999
0
        }
1000
0
    }
1001
1002
0
    return false;
1003
0
}
1004
1005
static bool lcl_SelHasAttrib( const ScDocument& rDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1006
                        const ScMarkData& rTabSelection, HasAttrFlags nMask )
1007
0
{
1008
0
    return std::any_of(rTabSelection.begin(), rTabSelection.end(),
1009
0
        [&](const SCTAB& rTab) { return rDoc.HasAttrib( nCol1, nRow1, rTab, nCol2, nRow2, rTab, nMask ); });
1010
0
}
1011
1012
//  paste into sheet:
1013
1014
//  internal paste
1015
1016
namespace {
1017
1018
bool checkDestRangeForOverwrite(InsertDeleteFlags nFlags, const ScRangeList& rDestRanges,
1019
                                const ScDocument& rDoc, const ScMarkData& rMark,
1020
                                weld::Window* pParentWnd)
1021
0
{
1022
0
    bool bIsEmpty = true;
1023
0
    size_t nRangeSize = rDestRanges.size();
1024
1025
0
    for (const auto& rTab : rMark)
1026
0
    {
1027
0
        for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
1028
0
        {
1029
0
            const ScRange& rRange = rDestRanges[i];
1030
            // tdf#158110 - check if just the ADDNOTES flag is present without any other content
1031
0
            if ((nFlags & InsertDeleteFlags::ADDNOTES) == InsertDeleteFlags::ADDNOTES
1032
0
                && (nFlags & (InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE))
1033
0
                       == InsertDeleteFlags::NONE)
1034
0
                bIsEmpty = rDoc.IsNotesBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
1035
0
                                                  rRange.aEnd.Col(), rRange.aEnd.Row(), rTab);
1036
0
            else
1037
0
                bIsEmpty = rDoc.IsBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
1038
0
                                             rRange.aEnd.Col(), rRange.aEnd.Row(), rTab);
1039
0
        }
1040
0
        if (!bIsEmpty)
1041
0
            break;
1042
0
    }
1043
1044
0
    if (!bIsEmpty)
1045
0
    {
1046
0
        ScReplaceWarnBox aBox(pParentWnd);
1047
0
        if (aBox.run() != RET_YES)
1048
0
        {
1049
            //  changing the configuration is within the ScReplaceWarnBox
1050
0
            return false;
1051
0
        }
1052
0
    }
1053
0
    return true;
1054
0
}
1055
1056
}
1057
1058
bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
1059
                                ScPasteFunc nFunction, bool bSkipEmptyCells,
1060
                                bool bTranspose, bool bAsLink,
1061
                                InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
1062
                                bool bAllowDialogs )
1063
0
{
1064
0
    if (!pClipDoc)
1065
0
    {
1066
0
        OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
1067
0
        return false;
1068
0
    }
1069
1070
0
    if (GetViewData().SelectionForbidsPaste(pClipDoc))
1071
0
        return false;
1072
1073
    //  undo: save all or no content
1074
0
    InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE;
1075
0
    if (nFlags & InsertDeleteFlags::CONTENTS)
1076
0
        nContFlags |= InsertDeleteFlags::CONTENTS;
1077
0
    if (nFlags & InsertDeleteFlags::ATTRIB)
1078
0
        nContFlags |= InsertDeleteFlags::ATTRIB;
1079
    // move attributes to undo without copying them from clip to doc
1080
0
    InsertDeleteFlags nUndoFlags = nContFlags;
1081
0
    if (nUndoExtraFlags & InsertDeleteFlags::ATTRIB)
1082
0
        nUndoFlags |= InsertDeleteFlags::ATTRIB;
1083
    // do not copy note captions into undo document
1084
0
    nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
1085
1086
0
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
1087
0
    if (rClipParam.isMultiRange())
1088
0
    {
1089
        // Source data is multi-range.
1090
0
        return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose,
1091
0
                                        bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
1092
0
    }
1093
1094
0
    ScMarkData& rMark = GetViewData().GetMarkData();
1095
0
    if (rMark.IsMultiMarked())
1096
0
    {
1097
        // Source data is single-range but destination is multi-range.
1098
0
        return PasteFromClipToMultiRanges(
1099
0
            nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
1100
0
            eMoveMode, nUndoFlags);
1101
0
    }
1102
1103
0
    bool bCutMode = pClipDoc->IsCutMode();      // if transposing, take from original clipdoc
1104
0
    bool bIncludeFiltered = bCutMode;
1105
1106
    // paste drawing: also if InsertDeleteFlags::NOTE is set (to create drawing layer for note captions)
1107
0
    bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (InsertDeleteFlags::OBJECTS|InsertDeleteFlags::NOTE) ) );
1108
1109
0
    ScDocShellRef aTransShellRef;   // for objects in xTransClip - must remain valid as long as xTransClip
1110
0
    ScDocument* pOrigClipDoc = nullptr;
1111
0
    ScDocumentUniquePtr xTransClip;
1112
0
    if ( bTranspose )
1113
0
    {
1114
0
        SCCOL nX;
1115
0
        SCROW nY;
1116
        // include filtered rows until TransposeClip can skip them
1117
0
        pClipDoc->GetClipArea( nX, nY, true );
1118
0
        if ( nY > static_cast<sal_Int32>(pClipDoc->MaxCol()) )                      // too many lines for transpose
1119
0
        {
1120
0
            ErrorMessage(STR_PASTE_FULL);
1121
0
            return false;
1122
0
        }
1123
0
        pOrigClipDoc = pClipDoc;        // refs
1124
1125
0
        if ( bPasteDraw )
1126
0
        {
1127
0
            aTransShellRef = new ScDocShell;        // DocShell needs a Ref immediately
1128
0
            aTransShellRef->DoInitNew();
1129
0
        }
1130
0
        ScDrawLayer::SetGlobalDrawPersist( aTransShellRef.get() );
1131
1132
0
        xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
1133
0
        pClipDoc->TransposeClip(xTransClip.get(), nFlags, bAsLink, bIncludeFiltered);
1134
0
        pClipDoc = xTransClip.get();
1135
1136
0
        ScDrawLayer::SetGlobalDrawPersist(nullptr);
1137
0
    }
1138
1139
    // TODO: position this call better for performance.
1140
0
    ResetAutoSpellForContentChange();
1141
1142
0
    SCCOL nStartCol;
1143
0
    SCROW nStartRow;
1144
0
    SCTAB nStartTab;
1145
0
    SCCOL nEndCol;
1146
0
    SCROW nEndRow;
1147
0
    SCTAB nEndTab;
1148
0
    SCCOL nClipSizeX;
1149
0
    SCROW nClipSizeY;
1150
0
    pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, true );      // size in clipboard doc
1151
1152
    //  size in target doc: include filtered rows only if CutMode is set
1153
0
    SCCOL nDestSizeX;
1154
0
    SCROW nDestSizeY;
1155
0
    pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
1156
1157
0
    ScDocument& rDoc = GetViewData().GetDocument();
1158
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
1159
0
    SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1160
0
    const bool bRecord(rDoc.IsUndoEnabled());
1161
1162
0
    ScDocShellModificator aModificator( *pDocSh );
1163
1164
0
    ScRange aMarkRange;
1165
0
    ScMarkData aFilteredMark( rMark);   // local copy for all modifications
1166
0
    ScMarkType eMarkType = GetViewData().GetSimpleArea( aMarkRange, aFilteredMark);
1167
0
    bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
1168
0
    bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
1169
0
            (bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));
1170
1171
0
    if (!bNoPaste)
1172
0
    {
1173
0
        if (!rMark.IsMarked())
1174
0
        {
1175
            // Create a selection with clipboard row count and check that for
1176
            // filtered.
1177
0
            nStartCol = GetViewData().GetCurX();
1178
0
            nStartRow = GetViewData().GetCurY();
1179
0
            nStartTab = GetViewData().CurrentTabForData();
1180
0
            nEndCol = nStartCol + nDestSizeX;
1181
0
            nEndRow = nStartRow + nDestSizeY;
1182
0
            nEndTab = nStartTab;
1183
0
            aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1184
0
            if (ScViewUtil::HasFiltered(aMarkRange, rDoc))
1185
0
            {
1186
0
                bMarkIsFiltered = true;
1187
                // Fit to clipboard's row count unfiltered rows. If there is no
1188
                // fit assume that pasting is not possible. Note that nDestSizeY is
1189
                // size-1 (difference).
1190
0
                if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1191
0
                    bNoPaste = true;
1192
0
            }
1193
0
            aFilteredMark.SetMarkArea( aMarkRange);
1194
0
        }
1195
0
        else
1196
0
        {
1197
            // Expand the marked area when the destination area is larger than the
1198
            // current selection, to get the undo do the right thing. (i#106711)
1199
0
            ScRange aRange = aFilteredMark.GetMarkArea();
1200
0
            if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
1201
0
            {
1202
0
                aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
1203
0
                aFilteredMark.SetMarkArea(aRange);
1204
0
            }
1205
0
        }
1206
0
    }
1207
1208
0
    if (bNoPaste)
1209
0
    {
1210
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1211
0
        return false;
1212
0
    }
1213
1214
0
    SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
1215
0
    ScRangeList aRangeList;
1216
0
    if (bMarkIsFiltered)
1217
0
    {
1218
0
        ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1219
0
        aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
1220
0
        nUnfilteredRows = 0;
1221
0
        size_t ListSize = aRangeList.size();
1222
0
        for ( size_t i = 0; i < ListSize; ++i )
1223
0
        {
1224
0
            ScRange & r = aRangeList[i];
1225
0
            nUnfilteredRows += r.aEnd.Row() - r.aStart.Row() + 1;
1226
0
        }
1227
#if 0
1228
        /* This isn't needed but could be a desired restriction. */
1229
        // For filtered, destination rows have to be an exact multiple of
1230
        // source rows. Note that nDestSizeY is size-1 (difference), so
1231
        // nDestSizeY==0 fits always.
1232
        if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
1233
        {
1234
            /* FIXME: this should be a more descriptive error message then. */
1235
            ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1236
            return false;
1237
        }
1238
#endif
1239
0
    }
1240
1241
    // Also for a filtered selection the area is used, for undo et al.
1242
0
    if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
1243
0
    {
1244
0
        aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1245
0
        SCCOL nBlockAddX = nEndCol-nStartCol;
1246
0
        SCROW nBlockAddY = nEndRow-nStartRow;
1247
1248
        // request, if the selection is greater than one row/column, but smaller
1249
        // as the Clipboard (then inserting is done beyond the selection)
1250
1251
        //  ClipSize is not size, but difference
1252
0
        if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
1253
0
             ( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
1254
0
             ( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
1255
0
        {
1256
0
            ScWaitCursorOff aWaitOff( GetFrameWin() );
1257
0
            OUString aMessage = ScResId( STR_PASTE_BIGGER );
1258
1259
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
1260
0
                                                           VclMessageType::Question, VclButtonsType::YesNo,
1261
0
                                                           aMessage));
1262
0
            xQueryBox->set_default_response(RET_NO);
1263
0
            if (xQueryBox->run() != RET_YES)
1264
0
            {
1265
0
                return false;
1266
0
            }
1267
0
        }
1268
1269
0
        if (nBlockAddX <= nDestSizeX)
1270
0
            nEndCol = nStartCol + nDestSizeX;
1271
1272
0
        if (nBlockAddY <= nDestSizeY)
1273
0
        {
1274
0
            nEndRow = nStartRow + nDestSizeY;
1275
0
            if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
1276
0
            {
1277
                // Same as above if nothing was marked: re-fit selection to
1278
                // unfiltered rows. Extending the selection actually may
1279
                // introduce filtered rows where there weren't any before, so
1280
                // we also need to test for that.
1281
0
                aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1282
0
                if (bMarkIsFiltered || ScViewUtil::HasFiltered(aMarkRange, rDoc))
1283
0
                {
1284
0
                    bMarkIsFiltered = true;
1285
                    // Worst case: all rows up to the end of the sheet are filtered.
1286
0
                    if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1287
0
                    {
1288
0
                        ErrorMessage(STR_PASTE_FULL);
1289
0
                        return false;
1290
0
                    }
1291
0
                }
1292
0
                aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1293
0
                aFilteredMark.SetMarkArea( aMarkRange);
1294
0
                if (bMarkIsFiltered)
1295
0
                {
1296
0
                    ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1297
0
                    aFilteredMark.FillRangeListWithMarks( &aRangeList, true);
1298
0
                }
1299
0
            }
1300
0
        }
1301
0
    }
1302
0
    else
1303
0
    {
1304
0
        nStartCol = GetViewData().GetCurX();
1305
0
        nStartRow = GetViewData().GetCurY();
1306
0
        nStartTab = GetViewData().CurrentTabForData();
1307
0
        nEndCol = nStartCol + nDestSizeX;
1308
0
        nEndRow = nStartRow + nDestSizeY;
1309
0
        nEndTab = nStartTab;
1310
0
    }
1311
1312
0
    bool bOffLimits = !rDoc.ValidCol(nEndCol) || !rDoc.ValidRow(nEndRow);
1313
1314
    //  target-range, as displayed:
1315
0
    ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
1316
0
    tools::Long nRangeWidth = GetViewData().GetDocShell()->GetDocument().GetColWidth(nStartCol,nEndCol,nStartTab);
1317
1318
    //  should lines be inserted?
1319
    //  ( too large nEndCol/nEndRow are detected below)
1320
0
    bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
1321
0
    if ( bInsertCells )
1322
0
    {
1323
        //  Instead of EnterListAction, the paste undo action is merged into the
1324
        //  insert action, so Repeat can insert the right cells
1325
1326
0
        MarkRange( aUserRange );            // set through CopyFromClip
1327
1328
        // CutMode is reset on insertion of cols/rows but needed again on cell move
1329
0
        bool bCut = pClipDoc->IsCutMode();
1330
0
        if (!InsertCells( eMoveMode, bRecord, true ))   // is inserting possible?
1331
0
        {
1332
0
            return false;
1333
            //  #i21036# EnterListAction isn't used, and InsertCells doesn't insert
1334
            //  its undo action on failure, so no undo handling is needed here
1335
0
        }
1336
0
        if ( bCut )
1337
0
            pClipDoc->SetCutMode( bCut );
1338
0
    }
1339
0
    else if (!bOffLimits)
1340
0
    {
1341
0
        bool bAskIfNotEmpty = bAllowDialogs &&
1342
0
                                ( nFlags & InsertDeleteFlags::CONTENTS ) &&
1343
0
                                nFunction == ScPasteFunc::NONE &&
1344
0
                                ScModule::get()->GetInputOptions().GetReplaceCellsWarn();
1345
0
        if ( bAskIfNotEmpty )
1346
0
        {
1347
0
            ScRangeList aTestRanges(aUserRange);
1348
0
            if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aFilteredMark, GetViewData().GetDialogParent()))
1349
0
                return false;
1350
0
        }
1351
0
    }
1352
1353
0
    SCCOL nClipStartX;                      // enlarge clipboard-range
1354
0
    SCROW nClipStartY;
1355
0
    pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1356
0
    SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
1357
0
    SCROW nUndoEndRow = nClipStartY + nClipSizeY;   // end of source area in clipboard document
1358
0
    bool bClipOver = false;
1359
    // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
1360
    // The same end column/row can be used for all calls because the clip doc doesn't contain
1361
    // content outside the clip area.
1362
0
    for (SCTAB nClipTab=0; nClipTab < pClipDoc->GetTableCount(); nClipTab++)
1363
0
        if ( pClipDoc->HasTable(nClipTab) )
1364
0
            if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab ) )
1365
0
                bClipOver = true;
1366
0
    nUndoEndCol -= nClipStartX + nClipSizeX;
1367
0
    nUndoEndRow -= nClipStartY + nClipSizeY;        // now contains only the difference added by ExtendMerge
1368
0
    nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
1369
0
    nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
1370
1371
0
    if (nUndoEndCol>pClipDoc->MaxCol() || nUndoEndRow>pClipDoc->MaxRow())
1372
0
    {
1373
0
        ErrorMessage(STR_PASTE_FULL);
1374
0
        return false;
1375
0
    }
1376
1377
0
    rDoc.ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark );
1378
1379
        //  check cell-protection
1380
1381
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow);
1382
0
    if (!aTester.IsEditable())
1383
0
    {
1384
0
        ErrorMessage(aTester.GetMessageId());
1385
0
        return false;
1386
0
    }
1387
1388
        //! check overlapping
1389
        //! just check truly intersection !!!!!!!
1390
1391
0
    ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
1392
0
    if ( bRecord )
1393
0
    {
1394
0
        OUString aUndo = ScResId( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
1395
0
        pUndoMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
1396
0
    }
1397
1398
0
    if (bClipOver)
1399
0
        if (lcl_SelHasAttrib( rDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HasAttrFlags::Overlapped ))
1400
0
        {       // "Cell merge not possible if cells already merged"
1401
0
            ScDocAttrIterator aIter( rDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
1402
0
            const ScPatternAttr* pPattern = nullptr;
1403
0
            SCCOL nCol = -1;
1404
0
            SCROW nRow1 = -1;
1405
0
            SCROW nRow2 = -1;
1406
0
            while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != nullptr )
1407
0
            {
1408
0
                const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
1409
0
                const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
1410
0
                if (rMergeFlag.IsMerged() || rMergeFlagAttr.IsOverlapped())
1411
0
                {
1412
0
                    ScRange aRange(nCol, nRow1, nStartTab);
1413
0
                    rDoc.ExtendOverlapped(aRange);
1414
0
                    rDoc.ExtendMerge(aRange, true);
1415
0
                    rDocFunc.UnmergeCells(aRange, bRecord, nullptr /*TODO: should pass combined UndoDoc if bRecord*/);
1416
0
                }
1417
0
            }
1418
0
        }
1419
1420
0
    if ( !bCutMode )
1421
0
    {
1422
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1423
0
        if ( pChangeTrack )
1424
0
            pChangeTrack->ResetLastCut();   // no more cut-mode
1425
0
    }
1426
1427
0
    bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
1428
0
    bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
1429
1430
0
    ScDocumentUniquePtr pUndoDoc;
1431
0
    std::unique_ptr<ScDocument> pRefUndoDoc;
1432
0
    std::unique_ptr<ScRefUndoData> pUndoData;
1433
1434
0
    if ( bRecord )
1435
0
    {
1436
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1437
0
        pUndoDoc->InitUndoSelected( rDoc, aFilteredMark, bColInfo, bRowInfo );
1438
1439
        // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
1440
0
        SCTAB nTabCount = rDoc.GetTableCount();
1441
0
        rDoc.CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
1442
0
                              nUndoFlags, false, *pUndoDoc );
1443
1444
0
        if ( bCutMode )
1445
0
        {
1446
0
            pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1447
0
            pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
1448
1449
0
            pUndoData.reset(new ScRefUndoData( rDoc ));
1450
0
        }
1451
0
    }
1452
1453
0
    const bool bSingleCellBefore = nStartCol == nEndCol &&
1454
0
                                   nStartRow == nEndRow &&
1455
0
                                   nStartTab == nEndTab;
1456
0
    tools::Long nBeforeHint(bSingleCellBefore ? pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)) : -1);
1457
1458
0
    sal_uInt16 nExtFlags = 0;
1459
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1460
0
                                       nEndCol,   nEndRow,   nEndTab );     // content before the change
1461
1462
0
    if (GetViewData().IsActive())
1463
0
    {
1464
0
        DoneBlockMode();
1465
0
        InitOwnBlockMode( aUserRange );
1466
0
    }
1467
0
    rMark.SetMarkArea( aUserRange );
1468
0
    MarkDataChanged();
1469
1470
        //  copy from clipboard
1471
        //  save original data in case of calculation
1472
1473
0
    ScDocumentUniquePtr pMixDoc;
1474
0
    if (nFunction != ScPasteFunc::NONE)
1475
0
    {
1476
0
        bSkipEmptyCells = false;
1477
0
        if ( nFlags & InsertDeleteFlags::CONTENTS )
1478
0
        {
1479
0
            pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1480
0
            pMixDoc->InitUndo( rDoc, nStartTab, nEndTab );
1481
0
            rDoc.CopyToDocument(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
1482
0
                                 InsertDeleteFlags::CONTENTS, false, *pMixDoc);
1483
0
        }
1484
0
    }
1485
1486
    /*  Make draw layer and start drawing undo.
1487
        - Needed before AdjustBlockHeight to track moved drawing objects.
1488
        - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1489
     */
1490
0
    if ( bPasteDraw )
1491
0
        pDocSh->MakeDrawLayer();
1492
0
    if ( bRecord )
1493
0
        rDoc.BeginDrawUndo();
1494
1495
0
    InsertDeleteFlags nNoObjFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1496
0
    if (!bAsLink)
1497
0
    {
1498
        //  copy normally (original range)
1499
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
1500
0
                pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
1501
0
                bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );
1502
1503
        // adapt refs manually in case of transpose
1504
0
        if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
1505
0
            rDoc.UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc.get() );
1506
0
    }
1507
0
    else if (!bTranspose)
1508
0
    {
1509
        //  copy with bAsLink=TRUE
1510
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
1511
0
                                true, true, bIncludeFiltered, bSkipEmptyCells );
1512
0
    }
1513
0
    else
1514
0
    {
1515
        //  copy all content (TransClipDoc contains only formula)
1516
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc.get(), pClipDoc );
1517
0
    }
1518
1519
    // skipped rows and merged cells don't mix
1520
0
    if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1521
0
        rDocFunc.UnmergeCells( aUserRange, false, nullptr );
1522
1523
0
    rDoc.ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true );    // refresh
1524
                                                                                    // new range
1525
1526
0
    if ( pMixDoc )              // calculate with original data?
1527
0
    {
1528
0
        rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
1529
0
    }
1530
0
    pMixDoc.reset();
1531
1532
0
    bool IsRangeWidthChanged = nRangeWidth != GetViewData().GetDocShell()->GetDocument().GetColWidth(nStartCol,nEndCol,nStartTab);
1533
0
    AdjustBlockHeight(true, nullptr, IsRangeWidthChanged );            // update row heights before pasting objects
1534
1535
0
    ::std::vector< OUString > aExcludedChartNames;
1536
0
    SdrPage* pPage = nullptr;
1537
1538
0
    if ( nFlags & InsertDeleteFlags::OBJECTS )
1539
0
    {
1540
0
        ScDrawView* pScDrawView = GetScDrawView();
1541
0
        SdrModel* pModel = ( pScDrawView ? &pScDrawView->GetModel() : nullptr );
1542
0
        pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : nullptr );
1543
0
        if ( pPage )
1544
0
        {
1545
0
            ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
1546
0
        }
1547
1548
        //  Paste the drawing objects after the row heights have been updated.
1549
1550
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, InsertDeleteFlags::OBJECTS, pRefUndoDoc.get(), pClipDoc,
1551
0
                                true, false, bIncludeFiltered );
1552
0
    }
1553
1554
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1555
0
                                       nEndCol,   nEndRow,   nEndTab );     // content after the change
1556
1557
        //  if necessary, delete autofilter-heads
1558
0
    if (bCutMode)
1559
0
        if (rDoc.RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
1560
0
                                        nClipStartY+nClipSizeY, nStartTab ))
1561
0
        {
1562
0
            pDocSh->PostPaint(
1563
0
                ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
1564
0
                PaintPartFlags::Grid );
1565
0
        }
1566
1567
    //!     remove block-range on RefUndoDoc !!!
1568
1569
0
    if ( bRecord )
1570
0
    {
1571
0
        ScDocumentUniquePtr pRedoDoc;
1572
        // copy redo data after appearance of the first undo
1573
        // don't create Redo-Doc without RefUndoDoc
1574
1575
0
        if (pRefUndoDoc)
1576
0
        {
1577
0
            pRedoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1578
0
            pRedoDoc->InitUndo( rDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
1579
1580
            //      move adapted refs to Redo-Doc
1581
1582
0
            SCTAB nTabCount = rDoc.GetTableCount();
1583
0
            pRedoDoc->AddUndoTab( 0, nTabCount-1 );
1584
0
            rDoc.CopyUpdated( pRefUndoDoc.get(), pRedoDoc.get() );
1585
1586
            //      move old refs to Undo-Doc
1587
1588
            //      not charts?
1589
0
            pUndoDoc->AddUndoTab( 0, nTabCount-1 );
1590
0
            pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, InsertDeleteFlags::ALL );
1591
0
            pRefUndoDoc->CopyToDocument( 0,0,0, pUndoDoc->MaxCol(), pUndoDoc->MaxRow(), nTabCount-1,
1592
0
                                            InsertDeleteFlags::FORMULA, false, *pUndoDoc );
1593
0
            pRefUndoDoc.reset();
1594
0
        }
1595
1596
        //  DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
1597
        //  UndoData for redo is made during first undo
1598
1599
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1600
0
        aOptions.nFunction  = nFunction;
1601
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1602
0
        aOptions.bTranspose = bTranspose;
1603
0
        aOptions.bAsLink    = bAsLink;
1604
0
        aOptions.eMoveMode  = eMoveMode;
1605
1606
0
        std::unique_ptr<SfxUndoAction> pUndo(new ScUndoPaste(
1607
0
            *pDocSh, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1608
0
            aFilteredMark, std::move(pUndoDoc), std::move(pRedoDoc), nFlags | nUndoFlags, std::move(pUndoData),
1609
0
            false, &aOptions ));     // false = Redo data not yet copied
1610
1611
0
        if ( bInsertCells )
1612
0
        {
1613
            //  Merge the paste undo action into the insert action.
1614
            //  Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
1615
1616
0
            pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
1617
0
        }
1618
0
        else
1619
0
            pUndoMgr->AddUndoAction( std::move(pUndo) );
1620
0
        pUndoMgr->LeaveListAction();
1621
0
    }
1622
1623
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1624
0
    if (bColInfo)
1625
0
    {
1626
0
        nPaint |= PaintPartFlags::Top;
1627
0
        nUndoEndCol = rDoc.MaxCol();               // just for drawing !
1628
0
    }
1629
0
    if (bRowInfo)
1630
0
    {
1631
0
        nPaint |= PaintPartFlags::Left;
1632
0
        nUndoEndRow = rDoc.MaxRow();               // just for drawing !
1633
0
    }
1634
1635
0
    tools::Long nMaxWidthAffectedHint = -1;
1636
0
    const bool bSingleCellAfter = nStartCol == nUndoEndCol &&
1637
0
                                  nStartRow == nUndoEndRow &&
1638
0
                                  nStartTab == nEndTab;
1639
0
    if (bSingleCellBefore && bSingleCellAfter)
1640
0
    {
1641
0
        tools::Long nAfterHint(pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)));
1642
0
        nMaxWidthAffectedHint = std::max(nBeforeHint, nAfterHint);
1643
0
    }
1644
1645
0
    pDocSh->PostPaint(
1646
0
        ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1647
0
        nPaint, nExtFlags, nMaxWidthAffectedHint);
1648
    // AdjustBlockHeight has already been called above
1649
1650
0
    aModificator.SetDocumentModified();
1651
0
    PostPasteFromClip(aUserRange, rMark);
1652
1653
0
    if ( nFlags & InsertDeleteFlags::OBJECTS )
1654
0
    {
1655
0
        ScModelObj* pModelObj = pDocSh->GetModel();
1656
0
        if ( pPage && pModelObj )
1657
0
        {
1658
0
            bool bSameDoc = ( rClipParam.getSourceDocID() == rDoc.GetDocumentID() );
1659
0
            const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
1660
0
            ScChartHelper::CreateProtectedChartListenersAndNotify( rDoc, pPage, pModelObj, nStartTab,
1661
0
                rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
1662
0
        }
1663
0
    }
1664
0
    OUString aStartAddress =  aMarkRange.aStart.GetColRowString();
1665
0
    OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
1666
0
    collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"PASTE"_ustr);
1667
0
    return true;
1668
0
}
1669
1670
bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
1671
                                          ScPasteFunc nFunction, bool bSkipEmptyCells,
1672
                                          bool bTranspose, bool bAsLink,
1673
                                          bool bAllowDialogs, InsCellCmd eMoveMode,
1674
                                          InsertDeleteFlags nUndoFlags)
1675
0
{
1676
0
    ScViewData& rViewData = GetViewData();
1677
0
    ScDocument& rDoc = rViewData.GetDocument();
1678
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
1679
0
    ScMarkData aMark(rViewData.GetMarkData());
1680
0
    const ScAddress aCurPos = rViewData.GetCurPos();
1681
0
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
1682
0
    SCCOL nColSize = rClipParam.getPasteColSize();
1683
0
    SCROW nRowSize = rClipParam.getPasteRowSize(*pClipDoc, /*bIncludeFiltered*/false);
1684
1685
0
    if (bTranspose)
1686
0
    {
1687
0
        if (static_cast<SCROW>(aCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(pClipDoc->MaxCol()))
1688
0
        {
1689
0
            ErrorMessage(STR_PASTE_FULL);
1690
0
            return false;
1691
0
        }
1692
1693
0
        ScDocumentUniquePtr pTransClip(new ScDocument(SCDOCMODE_CLIP));
1694
0
        pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink, /*bIncludeFiltered*/false);
1695
0
        pClipDoc = pTransClip.release();
1696
0
        SCCOL nTempColSize = nColSize;
1697
0
        nColSize = static_cast<SCCOL>(nRowSize);
1698
0
        nRowSize = static_cast<SCROW>(nTempColSize);
1699
0
    }
1700
1701
0
    if (!rDoc.ValidCol(aCurPos.Col()+nColSize-1) || !rDoc.ValidRow(aCurPos.Row()+nRowSize-1))
1702
0
    {
1703
0
        ErrorMessage(STR_PASTE_FULL);
1704
0
        return false;
1705
0
    }
1706
1707
    // Determine the first and last selected sheet numbers.
1708
0
    SCTAB nTab1 = aMark.GetFirstSelected();
1709
0
    SCTAB nTab2 = aMark.GetLastSelected();
1710
1711
0
    ScDocShellModificator aModificator(*pDocSh);
1712
1713
    // For multi-selection paste, we don't support cell duplication for larger
1714
    // destination range.  In case the destination is marked, we reset it to
1715
    // the clip size.
1716
0
    ScRange aMarkedRange(aCurPos.Col(), aCurPos.Row(), nTab1,
1717
0
                         aCurPos.Col()+nColSize-1, aCurPos.Row()+nRowSize-1, nTab2);
1718
1719
    // Extend the marked range to account for filtered rows in the destination
1720
    // area.
1721
0
    if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
1722
0
    {
1723
0
        if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize))
1724
0
            return false;
1725
0
    }
1726
1727
0
    bool bAskIfNotEmpty =
1728
0
        bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1729
0
        nFunction == ScPasteFunc::NONE && ScModule::get()->GetInputOptions().GetReplaceCellsWarn();
1730
1731
0
    if (bAskIfNotEmpty)
1732
0
    {
1733
0
        ScRangeList aTestRanges(aMarkedRange);
1734
0
        if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1735
0
            return false;
1736
0
    }
1737
1738
0
    aMark.SetMarkArea(aMarkedRange);
1739
0
    MarkRange(aMarkedRange);
1740
1741
0
    bool bInsertCells = (eMoveMode != INS_NONE);
1742
0
    if (bInsertCells)
1743
0
    {
1744
0
        if (!InsertCells(eMoveMode, rDoc.IsUndoEnabled(), true))
1745
0
            return false;
1746
0
    }
1747
1748
    // TODO: position this call better for performance.
1749
0
    ResetAutoSpellForContentChange();
1750
1751
0
    bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
1752
0
    ScDocumentUniquePtr pUndoDoc;
1753
0
    if (rDoc.IsUndoEnabled())
1754
0
    {
1755
0
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1756
0
        pUndoDoc->InitUndoSelected(rDoc, aMark, false, bRowInfo);
1757
0
        rDoc.CopyToDocument(aMarkedRange, nUndoFlags, false, *pUndoDoc, &aMark);
1758
0
    }
1759
1760
0
    ScDocumentUniquePtr pMixDoc;
1761
0
    if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1762
0
    {
1763
0
        if ( nFlags & InsertDeleteFlags::CONTENTS )
1764
0
        {
1765
0
            pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1766
0
            pMixDoc->InitUndoSelected(rDoc, aMark);
1767
0
            rDoc.CopyToDocument(aMarkedRange, InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1768
0
        }
1769
0
    }
1770
1771
    /*  Make draw layer and start drawing undo.
1772
        - Needed before AdjustBlockHeight to track moved drawing objects.
1773
        - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1774
     */
1775
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1776
0
        pDocSh->MakeDrawLayer();
1777
0
    if (rDoc.IsUndoEnabled())
1778
0
        rDoc.BeginDrawUndo();
1779
1780
0
    InsertDeleteFlags nCopyFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1781
    // in case of transpose, links were added in TransposeClip()
1782
0
    if (bAsLink && bTranspose)
1783
0
        nCopyFlags |= InsertDeleteFlags::FORMULA;
1784
0
    rDoc.CopyMultiRangeFromClip(aCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
1785
0
                                /*bIncludeFiltered*/false, bSkipEmptyCells);
1786
1787
0
    if (pMixDoc)
1788
0
        rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);
1789
1790
0
    AdjustBlockHeight();            // update row heights before pasting objects
1791
1792
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1793
0
    {
1794
        //  Paste the drawing objects after the row heights have been updated.
1795
0
        rDoc.CopyMultiRangeFromClip(aCurPos, aMark, InsertDeleteFlags::OBJECTS, pClipDoc, true,
1796
0
                                    false, /*bIncludeFiltered*/false, true);
1797
0
    }
1798
1799
0
    if (bRowInfo)
1800
0
        pDocSh->PostPaint(aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nTab1, PaintPartFlags::Grid|PaintPartFlags::Left);
1801
0
    else
1802
0
    {
1803
0
        ScRange aTmp = aMarkedRange;
1804
0
        aTmp.aStart.SetTab(nTab1);
1805
0
        aTmp.aEnd.SetTab(nTab1);
1806
0
        pDocSh->PostPaint(aTmp, PaintPartFlags::Grid);
1807
0
    }
1808
1809
0
    if (rDoc.IsUndoEnabled())
1810
0
    {
1811
0
        SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1812
0
        OUString aUndo = ScResId(
1813
0
            pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1814
0
        pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1815
1816
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1817
0
        aOptions.nFunction  = nFunction;
1818
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1819
0
        aOptions.bTranspose = bTranspose;
1820
0
        aOptions.bAsLink    = bAsLink;
1821
0
        aOptions.eMoveMode  = eMoveMode;
1822
1823
0
        std::unique_ptr<ScUndoPaste> pUndo(new ScUndoPaste(*pDocSh,
1824
0
            aMarkedRange, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1825
1826
0
        if (bInsertCells)
1827
0
            pUndoMgr->AddUndoAction(std::make_unique<ScUndoWrapper>(std::move(pUndo)), true);
1828
0
        else
1829
0
            pUndoMgr->AddUndoAction(std::move(pUndo));
1830
1831
0
        pUndoMgr->LeaveListAction();
1832
0
    }
1833
1834
0
    aModificator.SetDocumentModified();
1835
0
    PostPasteFromClip(aMarkedRange, aMark);
1836
0
    return true;
1837
0
}
1838
1839
bool ScViewFunc::PasteFromClipToMultiRanges(
1840
    InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
1841
    bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
1842
    InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
1843
0
{
1844
0
    if (bTranspose)
1845
0
    {
1846
        // We don't allow transpose for this yet.
1847
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1848
0
        return false;
1849
0
    }
1850
1851
0
    if (eMoveMode != INS_NONE)
1852
0
    {
1853
        // We don't allow insertion mode either.  Too complicated.
1854
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1855
0
        return false;
1856
0
    }
1857
1858
0
    ScViewData& rViewData = GetViewData();
1859
0
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
1860
0
    if (rClipParam.mbCutMode)
1861
0
    {
1862
        // No cut and paste with this, please.
1863
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1864
0
        return false;
1865
0
    }
1866
1867
0
    const ScAddress aCurPos = rViewData.GetCurPos();
1868
0
    ScDocument& rDoc = rViewData.GetDocument();
1869
1870
0
    ScRange aSrcRange = rClipParam.getWholeRange();
1871
0
    SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
1872
0
    SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
1873
1874
0
    if (!rDoc.ValidCol(aCurPos.Col()+nColSize-1) || !rDoc.ValidRow(aCurPos.Row()+nRowSize-1))
1875
0
    {
1876
0
        ErrorMessage(STR_PASTE_FULL);
1877
0
        return false;
1878
0
    }
1879
1880
0
    ScMarkData aMark(rViewData.GetMarkData());
1881
1882
0
    ScRangeList aRanges;
1883
0
    aMark.MarkToSimple();
1884
0
    aMark.FillRangeListWithMarks(&aRanges, false);
1885
0
    if (!ScClipUtil::CheckDestRanges(rDoc, nColSize, nRowSize, aMark, aRanges))
1886
0
    {
1887
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1888
0
        return false;
1889
0
    }
1890
1891
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
1892
1893
0
    ScDocShellModificator aModificator(*pDocSh);
1894
1895
0
    bool bAskIfNotEmpty =
1896
0
        bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1897
0
        nFunction == ScPasteFunc::NONE && ScModule::get()->GetInputOptions().GetReplaceCellsWarn();
1898
1899
0
    if (bAskIfNotEmpty)
1900
0
    {
1901
0
        if (!checkDestRangeForOverwrite(nFlags, aRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1902
0
            return false;
1903
0
    }
1904
1905
    // TODO: position this call better for performance.
1906
0
    ResetAutoSpellForContentChange();
1907
1908
0
    ScDocumentUniquePtr pUndoDoc;
1909
0
    if (rDoc.IsUndoEnabled())
1910
0
    {
1911
0
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1912
0
        pUndoDoc->InitUndoSelected(rDoc, aMark);
1913
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1914
0
        {
1915
0
            rDoc.CopyToDocument(
1916
0
                aRanges[i], nUndoFlags, false, *pUndoDoc, &aMark);
1917
0
        }
1918
0
    }
1919
1920
0
    ScDocumentUniquePtr pMixDoc;
1921
0
    if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1922
0
    {
1923
0
        if (nFlags & InsertDeleteFlags::CONTENTS)
1924
0
        {
1925
0
            pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1926
0
            pMixDoc->InitUndoSelected(rDoc, aMark);
1927
0
            for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1928
0
            {
1929
0
                rDoc.CopyToDocument(
1930
0
                    aRanges[i], InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1931
0
            }
1932
0
        }
1933
0
    }
1934
1935
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1936
0
        pDocSh->MakeDrawLayer();
1937
0
    if (rDoc.IsUndoEnabled())
1938
0
        rDoc.BeginDrawUndo();
1939
1940
    // First, paste everything but the drawing objects.
1941
0
    for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1942
0
    {
1943
0
        rDoc.CopyFromClip(
1944
0
            aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
1945
0
            false, false, true, bSkipEmptyCells);
1946
0
    }
1947
1948
0
    if (pMixDoc)
1949
0
    {
1950
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1951
0
            rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
1952
0
    }
1953
1954
0
    AdjustBlockHeight();            // update row heights before pasting objects
1955
1956
    // Then paste the objects.
1957
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1958
0
    {
1959
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1960
0
        {
1961
0
            rDoc.CopyFromClip(
1962
0
                aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
1963
0
                false, false, true, bSkipEmptyCells);
1964
0
        }
1965
0
    }
1966
1967
    // Refresh the range that includes all pasted ranges.  We only need to
1968
    // refresh the current sheet.
1969
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1970
0
    bool bRowInfo = (aSrcRange.aStart.Col()==0 &&  aSrcRange.aEnd.Col()==pClipDoc->MaxCol());
1971
0
    if (bRowInfo)
1972
0
        nPaint |= PaintPartFlags::Left;
1973
0
    pDocSh->PostPaint(aRanges, nPaint);
1974
1975
0
    if (rDoc.IsUndoEnabled())
1976
0
    {
1977
0
        SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1978
0
        OUString aUndo = ScResId(
1979
0
            pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1980
0
        pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1981
1982
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1983
0
        aOptions.nFunction  = nFunction;
1984
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1985
0
        aOptions.bTranspose = bTranspose;
1986
0
        aOptions.bAsLink    = bAsLink;
1987
0
        aOptions.eMoveMode  = eMoveMode;
1988
1989
1990
0
        pUndoMgr->AddUndoAction(
1991
0
            std::make_unique<ScUndoPaste>(
1992
0
                *pDocSh, aRanges, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1993
0
        pUndoMgr->LeaveListAction();
1994
0
    }
1995
1996
0
    aModificator.SetDocumentModified();
1997
0
    PostPasteFromClip(aRanges, aMark);
1998
1999
0
    return false;
2000
0
}
2001
2002
void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
2003
0
{
2004
0
    ScViewData& rViewData = GetViewData();
2005
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
2006
0
    pDocSh->UpdateOle(rViewData);
2007
2008
0
    SelectionChanged(true);
2009
2010
0
    ScModelObj* pModelObj = pDocSh->GetModel();
2011
2012
0
    ScRangeList aChangeRanges;
2013
0
    for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
2014
0
    {
2015
0
        const ScRange& r = rPasteRanges[i];
2016
0
        for (const auto& rTab : rMark)
2017
0
        {
2018
0
            ScRange aChangeRange(r);
2019
0
            aChangeRange.aStart.SetTab(rTab);
2020
0
            aChangeRange.aEnd.SetTab(rTab);
2021
0
            aChangeRanges.push_back(aChangeRange);
2022
0
        }
2023
0
    }
2024
2025
0
    if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
2026
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"paste"_ustr);
2027
0
    else if (pModelObj)
2028
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
2029
0
}
2030
2031
//      D R A G   A N D   D R O P
2032
2033
//  inside the doc
2034
2035
bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
2036
                                bool bCut )
2037
0
{
2038
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2039
0
    HideAllCursors();
2040
2041
0
    ResetAutoSpellForContentChange();
2042
2043
0
    bool bSuccess = true;
2044
0
    SCTAB nDestTab = rDestPos.Tab();
2045
0
    const ScMarkData& rMark = GetViewData().GetMarkData();
2046
0
    if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
2047
0
    {
2048
        //  moving within one table and several tables selected -> apply to all selected tables
2049
2050
0
        OUString aUndo = ScResId( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
2051
0
        pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
2052
2053
        //  collect ranges of consecutive selected tables
2054
2055
0
        ScRange aLocalSource = rSource;
2056
0
        ScAddress aLocalDest = rDestPos;
2057
0
        SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
2058
0
        SCTAB nStartTab = 0;
2059
0
        while ( nStartTab < nTabCount && bSuccess )
2060
0
        {
2061
0
            while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
2062
0
                ++nStartTab;
2063
0
            if ( nStartTab < nTabCount )
2064
0
            {
2065
0
                SCTAB nEndTab = nStartTab;
2066
0
                while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
2067
0
                    ++nEndTab;
2068
2069
0
                aLocalSource.aStart.SetTab( nStartTab );
2070
0
                aLocalSource.aEnd.SetTab( nEndTab );
2071
0
                aLocalDest.SetTab( nStartTab );
2072
2073
0
                bSuccess = pDocSh->GetDocFunc().MoveBlock(
2074
0
                                aLocalSource, aLocalDest, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
2075
2076
0
                nStartTab = nEndTab + 1;
2077
0
            }
2078
0
        }
2079
2080
0
        pDocSh->GetUndoManager()->LeaveListAction();
2081
0
    }
2082
0
    else
2083
0
    {
2084
        //  move the block as specified
2085
0
        bSuccess = pDocSh->GetDocFunc().MoveBlock(
2086
0
                                rSource, rDestPos, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
2087
0
    }
2088
2089
0
    ShowAllCursors();
2090
0
    if (bSuccess)
2091
0
    {
2092
        //   mark destination range
2093
0
        ScAddress aDestEnd(
2094
0
                    rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
2095
0
                    rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
2096
0
                    nDestTab );
2097
2098
0
        bool bIncludeFiltered = bCut;
2099
0
        if ( !bIncludeFiltered )
2100
0
        {
2101
            // find number of non-filtered rows
2102
0
            SCROW nPastedCount = pDocSh->GetDocument().CountNonFilteredRows(
2103
0
                rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
2104
2105
0
            if ( nPastedCount == 0 )
2106
0
                nPastedCount = 1;
2107
0
            aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
2108
0
        }
2109
2110
0
        MarkRange( ScRange( rDestPos, aDestEnd ), false );          //! sal_False ???
2111
2112
0
        pDocSh->UpdateOle(GetViewData());
2113
0
        SelectionChanged();
2114
0
    }
2115
0
    return bSuccess;
2116
0
}
2117
2118
//  link inside the doc
2119
2120
bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos )
2121
0
{
2122
    //  check overlapping
2123
2124
0
    if ( rSource.aStart.Tab() == rDestPos.Tab() )
2125
0
    {
2126
0
        SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
2127
0
        SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
2128
2129
0
        if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
2130
0
             rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
2131
0
        {
2132
0
            return false;
2133
0
        }
2134
0
    }
2135
2136
    //  run with paste
2137
2138
0
    ScDocument& rDoc = GetViewData().GetDocument();
2139
0
    ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
2140
0
    rDoc.CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
2141
0
                        rSource.aEnd.Col(), rSource.aEnd.Row(),
2142
0
                        rSource.aStart.Tab(), pClipDoc.get() );
2143
2144
    //  mark destination area (set cursor, no marks)
2145
2146
0
    if ( GetViewData().CurrentTabForData() != rDestPos.Tab() )
2147
0
        SetTabNo( rDestPos.Tab() );
2148
2149
0
    MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
2150
2151
    //  Paste
2152
2153
0
    PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(), ScPasteFunc::NONE, false, false, true );       // as a link
2154
2155
0
    return true;
2156
0
}
2157
2158
void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
2159
                                  SCROW nStartRow , SCCOL nStartCol ,
2160
                                  SCROW nEndRow , SCCOL nEndCol ,
2161
                                  std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
2162
                                  sal_uInt16 aColLength )
2163
0
{
2164
0
    ScDocument& rDoc = GetViewData().GetDocument();
2165
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2166
0
    ScMarkData& rMark = GetViewData().GetMarkData();
2167
0
    ScDocShellModificator aModificator( *pDocSh );
2168
0
    SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
2169
2170
0
    const bool bRecord( rDoc.IsUndoEnabled());
2171
0
    ScDocumentUniquePtr pUndoDoc;
2172
0
    ScDocumentUniquePtr pRedoDoc;
2173
0
    std::unique_ptr<ScRefUndoData> pUndoData;
2174
0
    SCTAB nTab = GetViewData().CurrentTabForData();
2175
0
    SCTAB nStartTab = nTab;
2176
0
    SCTAB nEndTab = nTab;
2177
2178
0
    {
2179
0
            ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2180
0
            if ( pChangeTrack )
2181
0
                    pChangeTrack->ResetLastCut();   // no more cut-mode
2182
0
    }
2183
0
    ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
2184
0
    bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
2185
0
    bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
2186
0
    SCCOL nUndoEndCol = nStartCol+aColLength-1;
2187
0
    SCROW nUndoEndRow = nCurrentRow;
2188
2189
0
    if ( bRecord )
2190
0
    {
2191
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2192
0
        pUndoDoc->InitUndoSelected( rDoc , rMark , bColInfo , bRowInfo );
2193
0
        rDoc.CopyToDocument( aUserRange , InsertDeleteFlags::VALUE , false, *pUndoDoc );
2194
0
    }
2195
0
    sal_uInt16 nExtFlags = 0;
2196
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
2197
0
    rDoc.BeginDrawUndo();
2198
2199
0
    for(sal_uInt16 i = 0; i < aColLength; i++)
2200
0
    {
2201
0
        if (rEdits[i] != nullptr)
2202
0
        {
2203
0
            OUString aFieldName = rEdits[i]->m_xEdit->get_text();
2204
0
            rDoc.SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
2205
0
        }
2206
0
    }
2207
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );  // content after the change
2208
0
    std::unique_ptr<SfxUndoAction> pUndo( new ScUndoDataForm( *pDocSh,
2209
0
                                               nStartCol, nCurrentRow, nStartTab,
2210
0
                                               nUndoEndCol, nUndoEndRow, nEndTab, rMark,
2211
0
                                               std::move(pUndoDoc), std::move(pRedoDoc),
2212
0
                                               std::move(pUndoData) ) );
2213
0
    pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
2214
2215
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
2216
0
    if (bColInfo)
2217
0
    {
2218
0
            nPaint |= PaintPartFlags::Top;
2219
0
            nUndoEndCol = rDoc.MaxCol();                           // just for drawing !
2220
0
    }
2221
0
    if (bRowInfo)
2222
0
    {
2223
0
            nPaint |= PaintPartFlags::Left;
2224
0
            nUndoEndRow = rDoc.MaxRow();                           // just for drawing !
2225
0
    }
2226
2227
0
    pDocSh->PostPaint(
2228
0
        ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
2229
0
        nPaint, nExtFlags);
2230
0
    pDocSh->UpdateOle(GetViewData());
2231
0
}
2232
2233
void ScViewFunc::SheetViewChanged()
2234
0
{
2235
0
    ScViewData& rViewData = GetViewData();
2236
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
2237
0
    ScDocument& rDocument = rViewData.GetDocument();
2238
0
    pDocSh->PostPaint(0, 0, 0, rDocument.MaxCol(), rDocument.MaxRow(), MAXTAB, PaintPartFlags::All);
2239
2240
0
    if (ScTabViewShell* pViewShell = GetViewData().GetViewShell())
2241
0
    {
2242
0
        ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(pViewShell->GetCurrentDocument());
2243
0
        SfxLokHelper::notifyViewRenderState(pViewShell, pModel);
2244
0
        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, "all"_ostr);
2245
0
        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY, "all"_ostr);
2246
0
    }
2247
0
    SfxBindings& rBindings = rViewData.GetBindings();
2248
0
    rBindings.Invalidate(FID_CURRENT_SHEET_VIEW);
2249
0
}
2250
2251
void ScViewFunc::MakeNewSheetView()
2252
0
{
2253
0
    SCTAB nTab = GetViewData().GetTabNumber();
2254
0
    ScDocument& rDocument = GetViewData().GetDocument();
2255
2256
0
    auto[nSheetViewID, nSheetViewTab] = rDocument.CreateNewSheetView(nTab);
2257
2258
0
    if (nSheetViewID == sc::InvalidSheetViewID)
2259
0
    {
2260
0
        SAL_WARN("sc", "Sheet view couldn't be created");
2261
0
        return;
2262
0
    }
2263
2264
0
    GetViewData().SetSheetViewID(nSheetViewID);
2265
2266
0
    GetViewData().GetDocShell()->Broadcast(ScTablesHint(SC_TAB_INSERTED, nSheetViewTab));
2267
0
    SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScTablesChanged));
2268
2269
    // Need to make sure we return to the main sheet, to make sure we are not at a different location after inserting
2270
0
    SetTabNo(nTab);
2271
2272
0
    SheetViewChanged();
2273
0
}
2274
2275
void ScViewFunc::RemoveCurrentSheetView()
2276
0
{
2277
0
    sc::SheetViewID nSheetViewID = GetViewData().GetSheetViewID();
2278
0
    if (nSheetViewID == sc::DefaultSheetViewID)
2279
0
        return;
2280
2281
0
    ScDocument& rDocument = GetViewData().GetDocument();
2282
0
    SCTAB nTab = GetViewData().GetTabNumber();
2283
0
    if (rDocument.IsSheetViewHolder(nTab))
2284
0
        return;
2285
2286
0
    auto pSheetManager = rDocument.GetSheetViewManager(nTab);
2287
0
    if (!pSheetManager)
2288
0
        return;
2289
2290
0
    GetViewData().SetSheetViewID(sc::DefaultSheetViewID);
2291
2292
0
    SCTAB nSheetViewTab = rDocument.GetSheetViewNumber(nTab, nSheetViewID);
2293
0
    pSheetManager->remove(nSheetViewID);
2294
2295
0
    GetViewData().GetDocFunc().DeleteTable(nSheetViewTab, true);
2296
2297
0
    SheetViewChanged();
2298
0
}
2299
2300
void ScViewFunc::SwitchSheetView(sc::SwitchSheetViewDirection eDirection)
2301
0
{
2302
0
    ScDocument& rDocument = GetViewData().GetDocument();
2303
0
    SCTAB nTab = GetViewData().GetTabNumber();
2304
0
    auto pSheetManager = rDocument.GetSheetViewManager(nTab);
2305
0
    sc::SheetViewID nSheetViewID = GetViewData().GetSheetViewID();
2306
2307
0
    sc::SheetViewID nSwitchSheetViewID = eDirection == sc::SwitchSheetViewDirection::Next
2308
0
                                            ? pSheetManager->getNextSheetView(nSheetViewID)
2309
0
                                            : pSheetManager->getPreviousSheetView(nSheetViewID);
2310
0
    SelectSheetView(nSwitchSheetViewID);
2311
0
}
2312
2313
void ScViewFunc::ExitSheetView()
2314
0
{
2315
0
    SelectSheetView(sc::DefaultSheetViewID);
2316
0
}
2317
2318
void ScViewFunc::SelectSheetView(sc::SheetViewID nSelectSheetViewID)
2319
0
{
2320
0
    SCTAB nTab = GetViewData().GetTabNumber();
2321
2322
0
    if (GetViewData().GetDocument().IsSheetViewHolder(nTab))
2323
0
        return;
2324
2325
0
    sc::SheetViewID nSheetViewID = GetViewData().GetSheetViewID();
2326
0
    if (nSheetViewID == nSelectSheetViewID)
2327
0
        return;
2328
2329
0
    GetViewData().SetSheetViewID(nSelectSheetViewID);
2330
2331
0
    SheetViewChanged();
2332
0
}
2333
2334
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */