Coverage Report

Created: 2025-07-07 10:01

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