Coverage Report

Created: 2026-07-10 11:04

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();
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
0
        if ( bCutMode )
1448
0
        {
1449
0
            pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1450
0
            pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
1451
1452
0
            pUndoData.reset(new ScRefUndoData( rDoc ));
1453
0
        }
1454
0
        else if (pClipDoc->GetDBCollection() && !pClipDoc->GetDBCollection()->getNamedDBs().empty())
1455
0
        {
1456
            // A clip document carrying named tables can add a database range to
1457
            // this document during paste. Force the DB-range snapshot so that
1458
            // addition is undoable even when this document had no ranges yet.
1459
            // The general path skips an empty collection.
1460
0
            pUndoData.reset(new ScRefUndoData( rDoc, /*bForceDBSnapshot*/true ));
1461
0
        }
1462
0
    }
1463
1464
0
    const bool bSingleCellBefore = nStartCol == nEndCol &&
1465
0
                                   nStartRow == nEndRow &&
1466
0
                                   nStartTab == nEndTab;
1467
0
    tools::Long nBeforeHint(bSingleCellBefore ? pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)) : -1);
1468
1469
0
    sal_uInt16 nExtFlags = 0;
1470
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1471
0
                                       nEndCol,   nEndRow,   nEndTab );     // content before the change
1472
1473
0
    if (GetViewData().IsActive())
1474
0
    {
1475
0
        DoneBlockMode();
1476
0
        InitOwnBlockMode( aUserRange );
1477
0
    }
1478
0
    rMark.SetMarkArea( aUserRange );
1479
0
    MarkDataChanged();
1480
1481
        //  copy from clipboard
1482
        //  save original data in case of calculation
1483
1484
0
    ScDocumentUniquePtr pMixDoc;
1485
0
    if (nFunction != ScPasteFunc::NONE)
1486
0
    {
1487
0
        bSkipEmptyCells = false;
1488
0
        if ( nFlags & InsertDeleteFlags::CONTENTS )
1489
0
        {
1490
0
            pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1491
0
            pMixDoc->InitUndo( rDoc, nStartTab, nEndTab );
1492
0
            rDoc.CopyToDocument(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
1493
0
                                 InsertDeleteFlags::CONTENTS, false, *pMixDoc);
1494
0
        }
1495
0
    }
1496
1497
    /*  Make draw layer and start drawing undo.
1498
        - Needed before AdjustBlockHeight to track moved drawing objects.
1499
        - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1500
     */
1501
0
    if ( bPasteDraw )
1502
0
        pDocSh->MakeDrawLayer();
1503
0
    if ( bRecord )
1504
0
        rDoc.BeginDrawUndo();
1505
1506
0
    InsertDeleteFlags nNoObjFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1507
0
    if (!bAsLink)
1508
0
    {
1509
        //  copy normally (original range)
1510
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
1511
0
                pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
1512
0
                bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );
1513
1514
        // adapt refs manually in case of transpose
1515
0
        if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
1516
0
            rDoc.UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc.get() );
1517
0
    }
1518
0
    else if (!bTranspose)
1519
0
    {
1520
        //  copy with bAsLink=TRUE
1521
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
1522
0
                                true, true, bIncludeFiltered, bSkipEmptyCells );
1523
0
    }
1524
0
    else
1525
0
    {
1526
        //  copy all content (TransClipDoc contains only formula)
1527
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc.get(), pClipDoc );
1528
0
    }
1529
1530
    // skipped rows and merged cells don't mix
1531
0
    if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1532
0
        rDocFunc.UnmergeCells( aUserRange, false, nullptr );
1533
1534
0
    rDoc.ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true );    // refresh
1535
                                                                                    // new range
1536
1537
0
    if ( pMixDoc )              // calculate with original data?
1538
0
    {
1539
0
        rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
1540
0
    }
1541
0
    pMixDoc.reset();
1542
1543
0
    bool IsRangeWidthChanged = nRangeWidth != GetViewData().GetDocShell()->GetDocument().GetColWidth(nStartCol,nEndCol,nStartTab);
1544
0
    AdjustBlockHeight(true, nullptr, IsRangeWidthChanged );            // update row heights before pasting objects
1545
1546
0
    ::std::vector< OUString > aExcludedChartNames;
1547
0
    SdrPage* pPage = nullptr;
1548
1549
0
    if ( nFlags & InsertDeleteFlags::OBJECTS )
1550
0
    {
1551
0
        ScDrawView* pScDrawView = GetScDrawView();
1552
0
        SdrModel* pModel = ( pScDrawView ? &pScDrawView->GetModel() : nullptr );
1553
0
        pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : nullptr );
1554
0
        if ( pPage )
1555
0
        {
1556
0
            ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
1557
0
        }
1558
1559
        //  Paste the drawing objects after the row heights have been updated.
1560
1561
0
        rDoc.CopyFromClip( aUserRange, aFilteredMark, InsertDeleteFlags::OBJECTS, pRefUndoDoc.get(), pClipDoc,
1562
0
                                true, false, bIncludeFiltered );
1563
0
    }
1564
1565
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1566
0
                                       nEndCol,   nEndRow,   nEndTab );     // content after the change
1567
1568
        //  if necessary, delete autofilter-heads
1569
0
    if (bCutMode)
1570
0
        if (rDoc.RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
1571
0
                                        nClipStartY+nClipSizeY, nStartTab ))
1572
0
        {
1573
0
            pDocSh->PostPaint(
1574
0
                ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
1575
0
                PaintPartFlags::Grid );
1576
0
        }
1577
1578
    //!     remove block-range on RefUndoDoc !!!
1579
1580
0
    if ( bRecord )
1581
0
    {
1582
0
        ScDocumentUniquePtr pRedoDoc;
1583
        // copy redo data after appearance of the first undo
1584
        // don't create Redo-Doc without RefUndoDoc
1585
1586
0
        if (pRefUndoDoc)
1587
0
        {
1588
0
            pRedoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1589
0
            pRedoDoc->InitUndo( rDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
1590
1591
            //      move adapted refs to Redo-Doc
1592
1593
0
            SCTAB nTabCount = rDoc.GetTableCount();
1594
0
            pRedoDoc->AddUndoTab( 0, nTabCount-1 );
1595
0
            rDoc.CopyUpdated( pRefUndoDoc.get(), pRedoDoc.get() );
1596
1597
            //      move old refs to Undo-Doc
1598
1599
            //      not charts?
1600
0
            pUndoDoc->AddUndoTab( 0, nTabCount-1 );
1601
0
            pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, InsertDeleteFlags::ALL );
1602
0
            pRefUndoDoc->CopyToDocument( 0,0,0, pUndoDoc->MaxCol(), pUndoDoc->MaxRow(), nTabCount-1,
1603
0
                                            InsertDeleteFlags::FORMULA, false, *pUndoDoc );
1604
0
            pRefUndoDoc.reset();
1605
0
        }
1606
1607
        //  DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
1608
        //  UndoData for redo is made during first undo
1609
1610
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1611
0
        aOptions.nFunction  = nFunction;
1612
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1613
0
        aOptions.bTranspose = bTranspose;
1614
0
        aOptions.bAsLink    = bAsLink;
1615
0
        aOptions.eMoveMode  = eMoveMode;
1616
1617
0
        std::unique_ptr<SfxUndoAction> pUndo(new ScUndoPaste(
1618
0
            *pDocSh, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1619
0
            aFilteredMark, std::move(pUndoDoc), std::move(pRedoDoc), nFlags | nUndoFlags, std::move(pUndoData),
1620
0
            false, &aOptions ));     // false = Redo data not yet copied
1621
1622
0
        if ( bInsertCells )
1623
0
        {
1624
            //  Merge the paste undo action into the insert action.
1625
            //  Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
1626
1627
0
            pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
1628
0
        }
1629
0
        else
1630
0
            pUndoMgr->AddUndoAction( std::move(pUndo) );
1631
0
        pUndoMgr->LeaveListAction();
1632
0
    }
1633
1634
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1635
0
    if (bColInfo)
1636
0
    {
1637
0
        nPaint |= PaintPartFlags::Top;
1638
0
        nUndoEndCol = rDoc.MaxCol();               // just for drawing !
1639
0
    }
1640
0
    if (bRowInfo)
1641
0
    {
1642
0
        nPaint |= PaintPartFlags::Left;
1643
0
        nUndoEndRow = rDoc.MaxRow();               // just for drawing !
1644
0
    }
1645
1646
0
    tools::Long nMaxWidthAffectedHint = -1;
1647
0
    const bool bSingleCellAfter = nStartCol == nUndoEndCol &&
1648
0
                                  nStartRow == nUndoEndRow &&
1649
0
                                  nStartTab == nEndTab;
1650
0
    if (bSingleCellBefore && bSingleCellAfter)
1651
0
    {
1652
0
        tools::Long nAfterHint(pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)));
1653
0
        nMaxWidthAffectedHint = std::max(nBeforeHint, nAfterHint);
1654
0
    }
1655
1656
0
    pDocSh->PostPaint(
1657
0
        ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1658
0
        nPaint, nExtFlags, nMaxWidthAffectedHint);
1659
    // AdjustBlockHeight has already been called above
1660
1661
0
    aModificator.SetDocumentModified();
1662
0
    PostPasteFromClip(aUserRange, rMark);
1663
1664
0
    if ( nFlags & InsertDeleteFlags::OBJECTS )
1665
0
    {
1666
0
        ScModelObj* pModelObj = pDocSh->GetModel();
1667
0
        if ( pPage && pModelObj )
1668
0
        {
1669
0
            bool bSameDoc = ( rClipParam.getSourceDocID() == rDoc.GetDocumentID() );
1670
0
            const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
1671
0
            ScChartHelper::CreateProtectedChartListenersAndNotify( rDoc, pPage, pModelObj, nStartTab,
1672
0
                rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
1673
0
        }
1674
0
    }
1675
0
    OUString aStartAddress =  aMarkRange.aStart.GetColRowString();
1676
0
    OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
1677
0
    collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"PASTE"_ustr);
1678
0
    return true;
1679
0
}
1680
1681
bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
1682
                                          ScPasteFunc nFunction, bool bSkipEmptyCells,
1683
                                          bool bTranspose, bool bAsLink,
1684
                                          bool bAllowDialogs, InsCellCmd eMoveMode,
1685
                                          InsertDeleteFlags nUndoFlags)
1686
0
{
1687
0
    ScViewData& rViewData = GetViewData();
1688
0
    ScDocument& rDoc = rViewData.GetDocument();
1689
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
1690
0
    ScMarkData aMark(rViewData.GetMarkData());
1691
0
    const ScAddress aCurPos = rViewData.GetCurPos();
1692
0
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
1693
0
    SCCOL nColSize = rClipParam.getPasteColSize();
1694
0
    SCROW nRowSize = rClipParam.getPasteRowSize(*pClipDoc, /*bIncludeFiltered*/false);
1695
1696
0
    if (bTranspose)
1697
0
    {
1698
0
        if (static_cast<SCROW>(aCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(pClipDoc->MaxCol()))
1699
0
        {
1700
0
            ErrorMessage(STR_PASTE_FULL);
1701
0
            return false;
1702
0
        }
1703
1704
0
        ScDocumentUniquePtr pTransClip(new ScDocument(SCDOCMODE_CLIP));
1705
0
        pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink, /*bIncludeFiltered*/false);
1706
0
        pClipDoc = pTransClip.release();
1707
0
        SCCOL nTempColSize = nColSize;
1708
0
        nColSize = static_cast<SCCOL>(nRowSize);
1709
0
        nRowSize = static_cast<SCROW>(nTempColSize);
1710
0
    }
1711
1712
0
    if (!rDoc.ValidCol(aCurPos.Col()+nColSize-1) || !rDoc.ValidRow(aCurPos.Row()+nRowSize-1))
1713
0
    {
1714
0
        ErrorMessage(STR_PASTE_FULL);
1715
0
        return false;
1716
0
    }
1717
1718
    // Determine the first and last selected sheet numbers.
1719
0
    SCTAB nTab1 = aMark.GetFirstSelected();
1720
0
    SCTAB nTab2 = aMark.GetLastSelected();
1721
1722
0
    ScDocShellModificator aModificator(*pDocSh);
1723
1724
    // For multi-selection paste, we don't support cell duplication for larger
1725
    // destination range.  In case the destination is marked, we reset it to
1726
    // the clip size.
1727
0
    ScRange aMarkedRange(aCurPos.Col(), aCurPos.Row(), nTab1,
1728
0
                         aCurPos.Col()+nColSize-1, aCurPos.Row()+nRowSize-1, nTab2);
1729
1730
    // Extend the marked range to account for filtered rows in the destination
1731
    // area.
1732
0
    if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
1733
0
    {
1734
0
        if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize))
1735
0
            return false;
1736
0
    }
1737
1738
0
    bool bAskIfNotEmpty =
1739
0
        bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1740
0
        nFunction == ScPasteFunc::NONE && ScModule::get()->GetInputOptions().GetReplaceCellsWarn();
1741
1742
0
    if (bAskIfNotEmpty)
1743
0
    {
1744
0
        ScRangeList aTestRanges(aMarkedRange);
1745
0
        if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1746
0
            return false;
1747
0
    }
1748
1749
0
    aMark.SetMarkArea(aMarkedRange);
1750
0
    MarkRange(aMarkedRange);
1751
1752
0
    bool bInsertCells = (eMoveMode != INS_NONE);
1753
0
    if (bInsertCells)
1754
0
    {
1755
0
        if (!InsertCells(eMoveMode, rDoc.IsUndoEnabled(), true))
1756
0
            return false;
1757
0
    }
1758
1759
    // TODO: position this call better for performance.
1760
0
    ResetAutoSpellForContentChange();
1761
1762
0
    bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
1763
0
    ScDocumentUniquePtr pUndoDoc;
1764
0
    if (rDoc.IsUndoEnabled())
1765
0
    {
1766
0
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1767
0
        pUndoDoc->InitUndoSelected(rDoc, aMark, false, bRowInfo);
1768
0
        rDoc.CopyToDocument(aMarkedRange, nUndoFlags, false, *pUndoDoc, &aMark);
1769
0
    }
1770
1771
0
    ScDocumentUniquePtr pMixDoc;
1772
0
    if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1773
0
    {
1774
0
        if ( nFlags & InsertDeleteFlags::CONTENTS )
1775
0
        {
1776
0
            pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1777
0
            pMixDoc->InitUndoSelected(rDoc, aMark);
1778
0
            rDoc.CopyToDocument(aMarkedRange, InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1779
0
        }
1780
0
    }
1781
1782
    /*  Make draw layer and start drawing undo.
1783
        - Needed before AdjustBlockHeight to track moved drawing objects.
1784
        - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1785
     */
1786
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1787
0
        pDocSh->MakeDrawLayer();
1788
0
    if (rDoc.IsUndoEnabled())
1789
0
        rDoc.BeginDrawUndo();
1790
1791
0
    InsertDeleteFlags nCopyFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1792
    // in case of transpose, links were added in TransposeClip()
1793
0
    if (bAsLink && bTranspose)
1794
0
        nCopyFlags |= InsertDeleteFlags::FORMULA;
1795
0
    rDoc.CopyMultiRangeFromClip(aCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
1796
0
                                /*bIncludeFiltered*/false, bSkipEmptyCells);
1797
1798
0
    if (pMixDoc)
1799
0
        rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);
1800
1801
0
    AdjustBlockHeight();            // update row heights before pasting objects
1802
1803
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1804
0
    {
1805
        //  Paste the drawing objects after the row heights have been updated.
1806
0
        rDoc.CopyMultiRangeFromClip(aCurPos, aMark, InsertDeleteFlags::OBJECTS, pClipDoc, true,
1807
0
                                    false, /*bIncludeFiltered*/false, true);
1808
0
    }
1809
1810
0
    if (bRowInfo)
1811
0
        pDocSh->PostPaint(aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nTab1, PaintPartFlags::Grid|PaintPartFlags::Left);
1812
0
    else
1813
0
    {
1814
0
        ScRange aTmp = aMarkedRange;
1815
0
        aTmp.aStart.SetTab(nTab1);
1816
0
        aTmp.aEnd.SetTab(nTab1);
1817
0
        pDocSh->PostPaint(aTmp, PaintPartFlags::Grid);
1818
0
    }
1819
1820
0
    if (rDoc.IsUndoEnabled())
1821
0
    {
1822
0
        SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1823
0
        OUString aUndo = ScResId(
1824
0
            pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1825
0
        pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1826
1827
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1828
0
        aOptions.nFunction  = nFunction;
1829
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1830
0
        aOptions.bTranspose = bTranspose;
1831
0
        aOptions.bAsLink    = bAsLink;
1832
0
        aOptions.eMoveMode  = eMoveMode;
1833
1834
0
        std::unique_ptr<ScUndoPaste> pUndo(new ScUndoPaste(*pDocSh,
1835
0
            aMarkedRange, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1836
1837
0
        if (bInsertCells)
1838
0
            pUndoMgr->AddUndoAction(std::make_unique<ScUndoWrapper>(std::move(pUndo)), true);
1839
0
        else
1840
0
            pUndoMgr->AddUndoAction(std::move(pUndo));
1841
1842
0
        pUndoMgr->LeaveListAction();
1843
0
    }
1844
1845
0
    aModificator.SetDocumentModified();
1846
0
    PostPasteFromClip(aMarkedRange, aMark);
1847
0
    return true;
1848
0
}
1849
1850
bool ScViewFunc::PasteFromClipToMultiRanges(
1851
    InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
1852
    bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
1853
    InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
1854
0
{
1855
0
    if (bTranspose)
1856
0
    {
1857
        // We don't allow transpose for this yet.
1858
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1859
0
        return false;
1860
0
    }
1861
1862
0
    if (eMoveMode != INS_NONE)
1863
0
    {
1864
        // We don't allow insertion mode either.  Too complicated.
1865
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1866
0
        return false;
1867
0
    }
1868
1869
0
    ScViewData& rViewData = GetViewData();
1870
0
    ScClipParam& rClipParam = pClipDoc->GetClipParam();
1871
0
    if (rClipParam.mbCutMode)
1872
0
    {
1873
        // No cut and paste with this, please.
1874
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1875
0
        return false;
1876
0
    }
1877
1878
0
    const ScAddress aCurPos = rViewData.GetCurPos();
1879
0
    ScDocument& rDoc = rViewData.GetDocument();
1880
1881
0
    ScRange aSrcRange = rClipParam.getWholeRange();
1882
0
    SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
1883
0
    SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
1884
1885
0
    if (!rDoc.ValidCol(aCurPos.Col()+nColSize-1) || !rDoc.ValidRow(aCurPos.Row()+nRowSize-1))
1886
0
    {
1887
0
        ErrorMessage(STR_PASTE_FULL);
1888
0
        return false;
1889
0
    }
1890
1891
0
    ScMarkData aMark(rViewData.GetMarkData());
1892
1893
0
    ScRangeList aRanges;
1894
0
    aMark.MarkToSimple();
1895
0
    aMark.FillRangeListWithMarks(&aRanges, false);
1896
0
    if (!ScClipUtil::CheckDestRanges(rDoc, nColSize, nRowSize, aMark, aRanges))
1897
0
    {
1898
0
        ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1899
0
        return false;
1900
0
    }
1901
1902
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
1903
1904
0
    ScDocShellModificator aModificator(*pDocSh);
1905
1906
0
    bool bAskIfNotEmpty =
1907
0
        bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1908
0
        nFunction == ScPasteFunc::NONE && ScModule::get()->GetInputOptions().GetReplaceCellsWarn();
1909
1910
0
    if (bAskIfNotEmpty)
1911
0
    {
1912
0
        if (!checkDestRangeForOverwrite(nFlags, aRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1913
0
            return false;
1914
0
    }
1915
1916
    // TODO: position this call better for performance.
1917
0
    ResetAutoSpellForContentChange();
1918
1919
0
    ScDocumentUniquePtr pUndoDoc;
1920
0
    if (rDoc.IsUndoEnabled())
1921
0
    {
1922
0
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1923
0
        pUndoDoc->InitUndoSelected(rDoc, aMark);
1924
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1925
0
        {
1926
0
            rDoc.CopyToDocument(
1927
0
                aRanges[i], nUndoFlags, false, *pUndoDoc, &aMark);
1928
0
        }
1929
0
    }
1930
1931
0
    ScDocumentUniquePtr pMixDoc;
1932
0
    if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1933
0
    {
1934
0
        if (nFlags & InsertDeleteFlags::CONTENTS)
1935
0
        {
1936
0
            pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1937
0
            pMixDoc->InitUndoSelected(rDoc, aMark);
1938
0
            for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1939
0
            {
1940
0
                rDoc.CopyToDocument(
1941
0
                    aRanges[i], InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1942
0
            }
1943
0
        }
1944
0
    }
1945
1946
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1947
0
        pDocSh->MakeDrawLayer();
1948
0
    if (rDoc.IsUndoEnabled())
1949
0
        rDoc.BeginDrawUndo();
1950
1951
    // First, paste everything but the drawing objects.
1952
0
    for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1953
0
    {
1954
0
        rDoc.CopyFromClip(
1955
0
            aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
1956
0
            false, false, true, bSkipEmptyCells);
1957
0
    }
1958
1959
0
    if (pMixDoc)
1960
0
    {
1961
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1962
0
            rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
1963
0
    }
1964
1965
0
    AdjustBlockHeight();            // update row heights before pasting objects
1966
1967
    // Then paste the objects.
1968
0
    if (nFlags & InsertDeleteFlags::OBJECTS)
1969
0
    {
1970
0
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1971
0
        {
1972
0
            rDoc.CopyFromClip(
1973
0
                aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
1974
0
                false, false, true, bSkipEmptyCells);
1975
0
        }
1976
0
    }
1977
1978
    // Refresh the range that includes all pasted ranges.  We only need to
1979
    // refresh the current sheet.
1980
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1981
0
    bool bRowInfo = (aSrcRange.aStart.Col()==0 &&  aSrcRange.aEnd.Col()==pClipDoc->MaxCol());
1982
0
    if (bRowInfo)
1983
0
        nPaint |= PaintPartFlags::Left;
1984
0
    pDocSh->PostPaint(aRanges, nPaint);
1985
1986
0
    if (rDoc.IsUndoEnabled())
1987
0
    {
1988
0
        SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1989
0
        OUString aUndo = ScResId(
1990
0
            pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1991
0
        pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1992
1993
0
        ScUndoPasteOptions aOptions;            // store options for repeat
1994
0
        aOptions.nFunction  = nFunction;
1995
0
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
1996
0
        aOptions.bTranspose = bTranspose;
1997
0
        aOptions.bAsLink    = bAsLink;
1998
0
        aOptions.eMoveMode  = eMoveMode;
1999
2000
2001
0
        pUndoMgr->AddUndoAction(
2002
0
            std::make_unique<ScUndoPaste>(
2003
0
                *pDocSh, aRanges, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
2004
0
        pUndoMgr->LeaveListAction();
2005
0
    }
2006
2007
0
    aModificator.SetDocumentModified();
2008
0
    PostPasteFromClip(aRanges, aMark);
2009
2010
0
    return false;
2011
0
}
2012
2013
void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
2014
0
{
2015
0
    ScViewData& rViewData = GetViewData();
2016
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
2017
0
    pDocSh->UpdateOle(rViewData);
2018
2019
0
    SelectionChanged(true);
2020
2021
0
    ScModelObj* pModelObj = pDocSh->GetModel();
2022
2023
0
    ScRangeList aChangeRanges;
2024
0
    for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
2025
0
    {
2026
0
        const ScRange& r = rPasteRanges[i];
2027
0
        for (const auto& rTab : rMark)
2028
0
        {
2029
0
            ScRange aChangeRange(r);
2030
0
            aChangeRange.aStart.SetTab(rTab);
2031
0
            aChangeRange.aEnd.SetTab(rTab);
2032
0
            aChangeRanges.push_back(aChangeRange);
2033
0
        }
2034
0
    }
2035
2036
0
    if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
2037
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"paste"_ustr);
2038
0
    else if (pModelObj)
2039
0
        HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
2040
2041
0
    pDocSh->ResolveSpilledOutputs();
2042
0
}
2043
2044
//      D R A G   A N D   D R O P
2045
2046
//  inside the doc
2047
2048
bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
2049
                                bool bCut )
2050
0
{
2051
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2052
0
    HideAllCursors();
2053
2054
0
    ResetAutoSpellForContentChange();
2055
2056
0
    bool bSuccess = true;
2057
0
    SCTAB nDestTab = rDestPos.Tab();
2058
0
    const ScMarkData& rMark = GetViewData().GetMarkData();
2059
0
    if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
2060
0
    {
2061
        //  moving within one table and several tables selected -> apply to all selected tables
2062
2063
0
        OUString aUndo = ScResId( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
2064
0
        pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
2065
2066
        //  collect ranges of consecutive selected tables
2067
2068
0
        ScRange aLocalSource = rSource;
2069
0
        ScAddress aLocalDest = rDestPos;
2070
0
        SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
2071
0
        SCTAB nStartTab = 0;
2072
0
        while ( nStartTab < nTabCount && bSuccess )
2073
0
        {
2074
0
            while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
2075
0
                ++nStartTab;
2076
0
            if ( nStartTab < nTabCount )
2077
0
            {
2078
0
                SCTAB nEndTab = nStartTab;
2079
0
                while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
2080
0
                    ++nEndTab;
2081
2082
0
                aLocalSource.aStart.SetTab( nStartTab );
2083
0
                aLocalSource.aEnd.SetTab( nEndTab );
2084
0
                aLocalDest.SetTab( nStartTab );
2085
2086
0
                bSuccess = pDocSh->GetDocFunc().MoveBlock(
2087
0
                                aLocalSource, aLocalDest, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
2088
2089
0
                nStartTab = nEndTab + 1;
2090
0
            }
2091
0
        }
2092
2093
0
        pDocSh->GetUndoManager()->LeaveListAction();
2094
0
    }
2095
0
    else
2096
0
    {
2097
        //  move the block as specified
2098
0
        bSuccess = pDocSh->GetDocFunc().MoveBlock(
2099
0
                                rSource, rDestPos, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
2100
0
    }
2101
2102
0
    ShowAllCursors();
2103
0
    if (bSuccess)
2104
0
    {
2105
        //   mark destination range
2106
0
        ScAddress aDestEnd(
2107
0
                    rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
2108
0
                    rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
2109
0
                    nDestTab );
2110
2111
0
        bool bIncludeFiltered = bCut;
2112
0
        if ( !bIncludeFiltered )
2113
0
        {
2114
            // find number of non-filtered rows
2115
0
            SCROW nPastedCount = pDocSh->GetDocument().CountNonFilteredRows(
2116
0
                rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
2117
2118
0
            if ( nPastedCount == 0 )
2119
0
                nPastedCount = 1;
2120
0
            aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
2121
0
        }
2122
2123
0
        MarkRange( ScRange( rDestPos, aDestEnd ), false );          //! sal_False ???
2124
2125
0
        pDocSh->UpdateOle(GetViewData());
2126
0
        SelectionChanged();
2127
0
    }
2128
0
    return bSuccess;
2129
0
}
2130
2131
//  link inside the doc
2132
2133
bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos )
2134
0
{
2135
    //  check overlapping
2136
2137
0
    if ( rSource.aStart.Tab() == rDestPos.Tab() )
2138
0
    {
2139
0
        SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
2140
0
        SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
2141
2142
0
        if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
2143
0
             rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
2144
0
        {
2145
0
            return false;
2146
0
        }
2147
0
    }
2148
2149
    //  run with paste
2150
2151
0
    ScDocument& rDoc = GetViewData().GetDocument();
2152
0
    ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
2153
0
    rDoc.CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
2154
0
                        rSource.aEnd.Col(), rSource.aEnd.Row(),
2155
0
                        rSource.aStart.Tab(), pClipDoc.get() );
2156
2157
    //  mark destination area (set cursor, no marks)
2158
2159
0
    if ( GetViewData().CurrentTabForData() != rDestPos.Tab() )
2160
0
        SetTabNo( rDestPos.Tab() );
2161
2162
0
    MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
2163
2164
    //  Paste
2165
2166
0
    PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(), ScPasteFunc::NONE, false, false, true );       // as a link
2167
2168
0
    return true;
2169
0
}
2170
2171
void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
2172
                                  SCROW nStartRow , SCCOL nStartCol ,
2173
                                  SCROW nEndRow , SCCOL nEndCol ,
2174
                                  std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
2175
                                  sal_uInt16 aColLength )
2176
0
{
2177
0
    ScDocument& rDoc = GetViewData().GetDocument();
2178
0
    ScDocShell* pDocSh = GetViewData().GetDocShell();
2179
0
    ScMarkData& rMark = GetViewData().GetMarkData();
2180
0
    ScDocShellModificator aModificator( *pDocSh );
2181
0
    SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
2182
2183
0
    const bool bRecord( rDoc.IsUndoEnabled());
2184
0
    ScDocumentUniquePtr pUndoDoc;
2185
0
    ScDocumentUniquePtr pRedoDoc;
2186
0
    std::unique_ptr<ScRefUndoData> pUndoData;
2187
0
    SCTAB nTab = GetViewData().CurrentTabForData();
2188
0
    SCTAB nStartTab = nTab;
2189
0
    SCTAB nEndTab = nTab;
2190
2191
0
    {
2192
0
            ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2193
0
            if ( pChangeTrack )
2194
0
                    pChangeTrack->ResetLastCut();   // no more cut-mode
2195
0
    }
2196
0
    ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
2197
0
    bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
2198
0
    bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
2199
0
    SCCOL nUndoEndCol = nStartCol+aColLength-1;
2200
0
    SCROW nUndoEndRow = nCurrentRow;
2201
2202
0
    if ( bRecord )
2203
0
    {
2204
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2205
0
        pUndoDoc->InitUndoSelected( rDoc , rMark , bColInfo , bRowInfo );
2206
0
        rDoc.CopyToDocument( aUserRange , InsertDeleteFlags::VALUE , false, *pUndoDoc );
2207
0
    }
2208
0
    sal_uInt16 nExtFlags = 0;
2209
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
2210
0
    rDoc.BeginDrawUndo();
2211
2212
0
    for(sal_uInt16 i = 0; i < aColLength; i++)
2213
0
    {
2214
0
        if (rEdits[i] != nullptr)
2215
0
        {
2216
0
            OUString aFieldName = rEdits[i]->m_xEdit->get_text();
2217
0
            rDoc.SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
2218
0
        }
2219
0
    }
2220
0
    pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );  // content after the change
2221
0
    std::unique_ptr<SfxUndoAction> pUndo( new ScUndoDataForm( *pDocSh,
2222
0
                                               nStartCol, nCurrentRow, nStartTab,
2223
0
                                               nUndoEndCol, nUndoEndRow, nEndTab, rMark,
2224
0
                                               std::move(pUndoDoc), std::move(pRedoDoc),
2225
0
                                               std::move(pUndoData) ) );
2226
0
    pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
2227
2228
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
2229
0
    if (bColInfo)
2230
0
    {
2231
0
            nPaint |= PaintPartFlags::Top;
2232
0
            nUndoEndCol = rDoc.MaxCol();                           // just for drawing !
2233
0
    }
2234
0
    if (bRowInfo)
2235
0
    {
2236
0
            nPaint |= PaintPartFlags::Left;
2237
0
            nUndoEndRow = rDoc.MaxRow();                           // just for drawing !
2238
0
    }
2239
2240
0
    pDocSh->PostPaint(
2241
0
        ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
2242
0
        nPaint, nExtFlags);
2243
0
    pDocSh->UpdateOle(GetViewData());
2244
0
}
2245
2246
void ScViewFunc::SheetViewChanged()
2247
0
{
2248
    // Invalidate the sheet view selector for all views connected to this document
2249
0
    ScTabViewShell* pThisViewShell = GetViewData().GetViewShell();
2250
0
    if (pThisViewShell)
2251
0
    {
2252
0
        ViewShellDocId nDocID = pThisViewShell->GetDocId();
2253
0
        SfxViewShell* pViewShell = SfxViewShell::GetFirst();
2254
0
        while (pViewShell)
2255
0
        {
2256
0
            ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
2257
0
            if (pTabViewShell && pTabViewShell->GetDocId() == nDocID)
2258
0
            {
2259
0
                SfxBindings& rBindings = pTabViewShell->GetViewFrame().GetBindings();
2260
0
                rBindings.Invalidate(FID_SELECT_SHEET_VIEW);
2261
0
            }
2262
0
            pViewShell = SfxViewShell::GetNext(*pViewShell);
2263
0
        }
2264
0
    }
2265
0
}
2266
2267
void ScViewFunc::MakeNewSheetView()
2268
0
{
2269
    // Convert to default view, if we are in sheet view.
2270
0
    SCTAB nTab = GetViewData().GetDefaultViewTab();
2271
2272
0
    auto [nSheetViewID, nSheetViewTab] = GetViewData().GetDocShell()->GetDocFunc().InsertSheetView(nTab, true);
2273
0
    if (nSheetViewID == sc::InvalidSheetViewID)
2274
0
    {
2275
0
        SAL_WARN("sc", "Sheet view couldn't be created");
2276
0
        return;
2277
0
    }
2278
2279
0
    SetTabNo(nSheetViewTab);
2280
2281
0
    SheetViewChanged();
2282
0
}
2283
2284
void ScViewFunc::RemoveCurrentSheetView()
2285
0
{
2286
0
    sc::SheetViewID nSheetViewID = GetViewData().GetSheetViewID();
2287
0
    if (nSheetViewID == sc::DefaultSheetViewID)
2288
0
        return;
2289
2290
0
    ScDocument& rDocument = GetViewData().GetDocument();
2291
0
    SCTAB nDefaultTab = GetViewData().GetDefaultViewTab();
2292
2293
0
    auto pSheetManager = rDocument.GetSheetViewManager(nDefaultTab);
2294
0
    if (!pSheetManager)
2295
0
        return;
2296
2297
0
    SCTAB nSheetViewTab = rDocument.GetSheetViewNumber(nDefaultTab, nSheetViewID);
2298
2299
    // Switch back to the default tab before deleting
2300
0
    SetTabNo(nDefaultTab);
2301
2302
    // Last sheet view tab is the deleted one, so reset
2303
0
    GetViewData().ClearLastSheetViewTab(nDefaultTab);
2304
2305
    // DeleteTable also removes the sheet view from the manager
2306
0
    GetViewData().GetDocFunc().DeleteTable(nSheetViewTab, true);
2307
2308
0
    SheetViewChanged();
2309
0
}
2310
2311
void ScViewFunc::ExitSheetView()
2312
0
{
2313
0
    SelectSheetView(sc::DefaultSheetViewID);
2314
0
}
2315
2316
void ScViewFunc::SelectSheetView(sc::SheetViewID nSelectSheetViewID)
2317
0
{
2318
0
    if (nSelectSheetViewID == GetViewData().GetSheetViewID())
2319
0
        return;
2320
2321
0
    ScDocument& rDocument = GetViewData().GetDocument();
2322
0
    SCTAB nDefaultTab = GetViewData().GetDefaultViewTab();
2323
2324
0
    if (nSelectSheetViewID == sc::DefaultSheetViewID)
2325
0
    {
2326
0
        SetTabNo(nDefaultTab);
2327
0
    }
2328
0
    else
2329
0
    {
2330
0
        SCTAB nSheetViewTab = rDocument.GetSheetViewNumber(nDefaultTab, nSelectSheetViewID);
2331
0
        if (ValidTab(nSheetViewTab))
2332
0
            SetTabNo(nSheetViewTab);
2333
0
    }
2334
0
    SheetViewChanged();
2335
0
}
2336
2337
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */