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