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