Coverage Report

Created: 2026-11-06 11:29

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