problem pasting to calc an image copied from firefox (windows)
[LibreOffice.git] / sc / source / ui / view / viewfun3.cxx
blob96c1a36e3f78af752d9fc372c59f9923751023c2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
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>
68 using namespace com::sun::star;
70 namespace {
72 void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& action)
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";
81 UITestLogger::getInstance().logEvent(aDescription);
86 // GlobalName of writer-DocShell from comphelper/classids.hxx
88 // C U T
90 void ScViewFunc::CutToClip()
92 UpdateInputLine();
94 ScEditableTester aTester( this );
95 if (!aTester.IsEditable()) // selection editable?
97 ErrorMessage( aTester.GetMessageId() );
98 return;
101 ScRange aRange; // delete this range
102 if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
104 ScDocument& rDoc = GetViewData().GetDocument();
105 ScDocShell* pDocSh = GetViewData().GetDocShell();
106 ScMarkData& rMark = GetViewData().GetMarkData();
107 const bool bRecord(rDoc.IsUndoEnabled()); // Undo/Redo
109 ScDocShellModificator aModificator( *pDocSh );
111 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) // mark the range if not marked yet
113 DoneBlockMode();
114 InitOwnBlockMode();
115 rMark.SetMarkArea( aRange );
116 MarkDataChanged();
119 CopyToClip( nullptr, true, false, true/*bIncludeObjects*/ ); // copy to clipboard
121 ScAddress aOldEnd( aRange.aEnd ); // combined cells in this range?
122 rDoc.ExtendMerge( aRange, true );
124 ScDocumentUniquePtr pUndoDoc;
125 if ( bRecord )
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();
137 sal_uInt16 nExtFlags = 0;
138 pDocSh->UpdatePaintExt( nExtFlags, aRange );
140 rMark.MarkToMulti();
141 rDoc.DeleteSelection( InsertDeleteFlags::ALL, rMark );
142 rDoc.DeleteObjectsInSelection( rMark );
143 rMark.MarkToSimple();
145 if ( !AdjustRowHeight( aRange.aStart.Row(), aRange.aEnd.Row(), true ) )
146 pDocSh->PostPaint( aRange, PaintPartFlags::Grid, nExtFlags );
148 if ( bRecord ) // Draw-Undo now available
149 pDocSh->GetUndoManager()->AddUndoAction(
150 std::make_unique<ScUndoCut>( pDocSh, aRange, aOldEnd, rMark, std::move(pUndoDoc) ) );
152 aModificator.SetDocumentModified();
153 pDocSh->UpdateOle(GetViewData());
155 CellContentChanged();
157 OUString aStartAddress = aRange.aStart.GetColRowString();
158 OUString aEndAddress = aRange.aEnd.GetColRowString();
160 collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "CUT");
162 else
163 ErrorMessage( STR_NOMULTISELECT );
166 // C O P Y
168 bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
170 ScRange aRange;
171 ScMarkType eMarkType = GetViewData().GetSimpleArea( aRange );
172 ScMarkData& rMark = GetViewData().GetMarkData();
173 bool bDone = false;
175 if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
177 ScRangeList aRangeList( aRange );
178 bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
180 else if (eMarkType == SC_MARK_MULTI)
182 ScRangeList aRangeList;
183 rMark.MarkToSimple();
184 rMark.FillRangeListWithMarks(&aRangeList, false);
185 bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
187 else
189 if (!bApi)
190 ErrorMessage(STR_NOMULTISELECT);
192 if( !bCut ){
193 OUString aStartAddress = aRange.aStart.GetColRowString();
194 OUString aEndAddress = aRange.aEnd.GetColRowString();
195 collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "COPY");
197 return bDone;
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 )
203 if ( rRanges.empty() )
204 return false;
205 if ( bStopEdit )
206 UpdateInputLine();
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);
214 return bDone;
217 bool ScViewFunc::CopyToClipSingleRange( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bIncludeObjects )
219 ScRange aRange = rRanges[0];
220 ScClipParam aClipParam( aRange, bCut );
221 aClipParam.maRanges = rRanges;
222 ScDocument& rDoc = GetViewData().GetDocument();
223 ScMarkData& rMark = GetViewData().GetMarkData();
225 if (rDoc.HasSelectedBlockMatrixFragment( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rMark ) )
226 return false;
228 bool bSysClip = false;
229 if ( !pClipDoc ) // no clip doc specified
231 // Create one (deleted by ScTransferObj).
232 pClipDoc = new ScDocument( SCDOCMODE_CLIP );
233 bSysClip = true; // and copy into system
235 if ( !bCut )
237 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
238 if ( pChangeTrack )
239 pChangeTrack->ResetLastCut();
242 if ( bSysClip && bIncludeObjects )
244 bool bAnyOle = rDoc.HasOLEObjectsInArea( aRange );
245 // Update ScGlobal::xDrawClipDocShellRef.
246 ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
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() );
254 if (SfxObjectShell* pObjectShell = rDoc.GetDocumentShell())
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));
264 rDoc.CopyToClip( aClipParam, pClipDoc, &rMark, false, bIncludeObjects );
265 if (ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer())
267 ScClipParam& rClipDocClipParam = pClipDoc->GetClipParam();
268 ScRangeListVector& rRangesVector = rClipDocClipParam.maProtectedChartRangesVector;
269 SCTAB nTabCount = pClipDoc->GetTableCount();
270 for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
272 SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
273 if ( pPage )
275 ScChartHelper::FillProtectedChartRangesVector( rRangesVector, rDoc, pPage );
280 if ( bSysClip )
282 ScDrawLayer::SetGlobalDrawPersist(nullptr);
283 ScGlobal::SetClipDocName( rDoc.GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
285 pClipDoc->ExtendMerge( aRange, true );
287 if ( bSysClip )
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
295 rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( ScDocumentUniquePtr(pClipDoc), aObjDesc ));
296 if ( ScGlobal::xDrawClipDocShellRef.is() )
298 SfxObjectShellRef aPersistRef( ScGlobal::xDrawClipDocShellRef.get() );
299 pTransferObj->SetDrawPersist( aPersistRef );// keep persist for ole objects alive
301 pTransferObj->CopyToClipboard( GetActiveWin() );
304 return true;
307 bool ScViewFunc::CopyToClipMultiRange( const ScDocument* pInputClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects )
309 if (bCut)
311 // We don't support cutting of multi-selections.
312 if (!bApi)
313 ErrorMessage(STR_NOMULTISELECT);
314 return false;
316 if (pInputClipDoc)
318 // TODO: What's this for?
319 if (!bApi)
320 ErrorMessage(STR_NOMULTISELECT);
321 return false;
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;
334 ScDocumentUniquePtr pDocClip(new ScDocument(SCDOCMODE_CLIP));
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 )
347 p = &aClipParam.maRanges[i];
348 if ( rDoc.HasSelectedBlockMatrixFragment(
349 p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark) )
351 if (!bApi)
352 ErrorMessage(STR_MATRIXFRAGMENTERR);
353 return false;
356 SCCOL nColDelta = p->aStart.Col() - nPrevCol;
357 SCROW nRowDelta = p->aStart.Row() - nPrevRow;
359 if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
361 bValidRanges = false;
362 break;
365 if (aClipParam.meDirection == ScClipParam::Unspecified)
367 if (nColDelta)
368 aClipParam.meDirection = ScClipParam::Column;
369 if (nRowDelta)
370 aClipParam.meDirection = ScClipParam::Row;
373 SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
374 SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
376 if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
378 // column-oriented ranges must have identical row size.
379 bValidRanges = false;
380 break;
382 if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
384 // likewise, row-oriented ranges must have identical
385 // column size.
386 bValidRanges = false;
387 break;
390 nPrevCol = p->aStart.Col();
391 nPrevRow = p->aStart.Row();
392 nPrevColDelta = nColDelta;
393 nPrevRowDelta = nRowDelta;
394 nPrevColSize = nColSize;
395 nPrevRowSize = nRowSize;
397 if (!bValidRanges)
398 break;
399 rDoc.CopyToClip(aClipParam, pDocClip.get(), &rMark, false, bIncludeObjects );
401 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
402 if ( pChangeTrack )
403 pChangeTrack->ResetLastCut(); // no more cut-mode
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
411 rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( std::move(pDocClip), aObjDesc ));
412 if ( ScGlobal::xDrawClipDocShellRef.is() )
414 SfxObjectShellRef aPersistRef( ScGlobal::xDrawClipDocShellRef.get() );
415 pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
417 pTransferObj->CopyToClipboard( GetActiveWin() ); // system clipboard
419 bSuccess = true;
421 while (false);
423 if (!bSuccess && !bApi)
424 ErrorMessage(STR_NOMULTISELECT);
426 bDone = bSuccess;
428 return bDone;
431 rtl::Reference<ScTransferObj> ScViewFunc::CopyToTransferable()
433 ScRange aRange;
434 if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
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 ) )
443 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP )); // create one (deleted by ScTransferObj)
445 bool bAnyOle = rDoc.HasOLEObjectsInArea( aRange, &rMark );
446 ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
448 ScClipParam aClipParam(aRange, false);
449 rDoc.CopyToClip(aClipParam, pClipDoc.get(), &rMark, false, true);
451 ScDrawLayer::SetGlobalDrawPersist(nullptr);
452 pClipDoc->ExtendMerge( aRange, true );
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 );
462 return nullptr;
465 // P A S T E
467 void ScViewFunc::PasteDraw()
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)
478 const OUString& aSrcShellID = pDrawClip->GetShellID();
479 OUString aDestShellID = SfxObjectShell::CreateShellID(rViewData.GetDocShell());
480 PasteDraw(aPos, pDrawClip->GetModel(), false, aSrcShellID, aDestShellID);
484 void ScViewFunc::PasteFromSystem()
486 UpdateInputLine();
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)
495 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
496 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
497 true ); // allow warning dialog
499 else if (pDrawClip)
500 PasteDraw();
501 else
503 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
506 SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName("Biff8");
507 SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName("Biff5");
509 SotClipboardFormatId nFormat; // output param for GetExchangeAction
510 sal_uInt8 nEventAction; // output param for GetExchangeAction
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 );
521 if ( nAction != EXCHG_INOUT_ACTION_NONE )
523 switch( nAction )
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;
540 if ( nAction == EXCHG_INOUT_ACTION_NONE )
542 // first SvDraw-model, then drawing
543 // (only one drawing is allowed)
545 if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
547 // special case for tables from drawing
548 if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
550 PasteFromSystem( SotClipboardFormatId::RTF );
552 else if( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
554 PasteFromSystem( SotClipboardFormatId::RICHTEXT );
556 else
558 PasteFromSystem( SotClipboardFormatId::DRAWING );
561 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
563 // If it's a Writer object, insert RTF instead of OLE
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)
569 bool bDoRtf = false;
570 TransferableObjectDescriptor aObjDesc;
571 if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
573 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
574 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
575 && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
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 );
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::BITMAP))
602 PasteFromSystem(SotClipboardFormatId::BITMAP);
603 else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
604 PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE);
605 else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
606 PasteFromSystem(SotClipboardFormatId::SYLK);
607 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
608 PasteFromSystem(SotClipboardFormatId::STRING_TSVC);
609 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
610 PasteFromSystem(SotClipboardFormatId::STRING);
611 // xxx_OLE formats come last, like in SotExchange tables
612 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
613 PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE );
614 else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
615 PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
619 // no exception-> SID_PASTE has FastCall-flag from idl
620 // will be called in case of empty clipboard (#42531#)
623 void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
625 uno::Reference<lang::XUnoTunnel> xTunnel( rxTransferable, uno::UNO_QUERY );
627 if (auto pOwnClip = comphelper::getFromUnoTunnel<ScTransferObj>(xTunnel))
629 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
630 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
631 true ); // allow warning dialog
633 else if (auto pDrawClip = comphelper::getFromUnoTunnel<ScDrawTransferObj>(xTunnel))
635 ScViewData& rViewData = GetViewData();
636 SCCOL nPosX = rViewData.GetCurX();
637 SCROW nPosY = rViewData.GetCurY();
638 vcl::Window* pWin = GetActiveWin();
639 Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY, rViewData.GetActivePart() ) );
640 PasteDraw(
641 aPos, pDrawClip->GetModel(), false,
642 pDrawClip->GetShellID(), SfxObjectShell::CreateShellID(rViewData.GetDocShell()));
644 else
646 TransferableDataHelper aDataHelper( rxTransferable );
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)
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 ))
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 ) )
664 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
665 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
666 && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ));
668 if ( bDoRtf )
669 nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
670 else
671 nFormatId = SotClipboardFormatId::EMBED_SOURCE;
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;
709 PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
710 GetViewData().GetCurX(), GetViewData().GetCurY(), nullptr );
714 bool ScViewFunc::PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi )
716 UpdateInputLine();
718 bool bRet = true;
719 vcl::Window* pWin = GetActiveWin();
720 // keep a reference in case the clipboard is changed during PasteFromClip
721 const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
722 if ( nFormatId == SotClipboardFormatId::NONE && pOwnClip )
724 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
725 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
726 !bApi ); // allow warning dialog
728 else
730 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
731 if ( !aDataHelper.GetTransferable().is() )
732 return false;
734 SCCOL nPosX = 0;
735 SCROW nPosY = 0;
737 ScViewData& rViewData = GetViewData();
738 ScRange aRange;
739 if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
741 nPosX = aRange.aStart.Col();
742 nPosY = aRange.aStart.Row();
744 else
746 nPosX = rViewData.GetCurX();
747 nPosY = rViewData.GetCurY();
750 bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
751 nPosX, nPosY,
752 nullptr, false, !bApi ); // allow warning dialog
754 if ( !bRet && !bApi )
756 ErrorMessage(STR_PASTE_ERROR);
758 else if (comphelper::LibreOfficeKit::isActive())
760 SfxViewShell* pViewShell = rViewData.GetViewShell();
761 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, true /* bColumns */, true /* bRows */,
762 true /* bSizes */, false /* bHidden */, false /* bFiltered */, false /* bGroups */, rViewData.GetTabNo());
765 return bRet;
768 // P A S T E
770 bool ScViewFunc::PasteOnDrawObjectLinked(
771 const uno::Reference<datatransfer::XTransferable>& rxTransferable,
772 SdrObject& rHitObj)
774 TransferableDataHelper aDataHelper( rxTransferable );
776 if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
778 tools::SvRef<SotTempStream> xStm;
779 ScDrawView* pScDrawView = GetScDrawView();
781 if( pScDrawView && aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) )
783 Graphic aGraphic;
784 TypeSerializer aSerializer(*xStm);
785 aSerializer.readGraphic(aGraphic);
787 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
789 if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, "" ))
791 return true;
795 else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
797 GDIMetaFile aMtf;
798 ScDrawView* pScDrawView = GetScDrawView();
800 if( pScDrawView && aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
802 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
804 if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, "" ))
806 return true;
810 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) || aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
812 BitmapEx aBmpEx;
813 ScDrawView* pScDrawView = GetScDrawView();
815 if( pScDrawView && aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ) )
817 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
819 if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmpEx), aBeginUndo, "" ))
821 return true;
826 return false;
829 static bool lcl_SelHasAttrib( const ScDocument& rDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
830 const ScMarkData& rTabSelection, HasAttrFlags nMask )
832 return std::any_of(rTabSelection.begin(), rTabSelection.end(),
833 [&](const SCTAB& rTab) { return rDoc.HasAttrib( nCol1, nRow1, rTab, nCol2, nRow2, rTab, nMask ); });
836 // paste into sheet:
838 // internal paste
840 namespace {
842 bool checkDestRangeForOverwrite(const ScRangeList& rDestRanges, const ScDocument& rDoc, const ScMarkData& rMark, weld::Window* pParentWnd)
844 bool bIsEmpty = true;
845 size_t nRangeSize = rDestRanges.size();
846 for (const auto& rTab : rMark)
848 for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
850 const ScRange& rRange = rDestRanges[i];
851 bIsEmpty = rDoc.IsBlockEmpty(
852 rTab, rRange.aStart.Col(), rRange.aStart.Row(),
853 rRange.aEnd.Col(), rRange.aEnd.Row());
855 if (!bIsEmpty)
856 break;
859 if (!bIsEmpty)
861 ScReplaceWarnBox aBox(pParentWnd);
862 if (aBox.run() != RET_YES)
864 // changing the configuration is within the ScReplaceWarnBox
865 return false;
868 return true;
873 bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
874 ScPasteFunc nFunction, bool bSkipEmptyCells,
875 bool bTranspose, bool bAsLink,
876 InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
877 bool bAllowDialogs )
879 if (!pClipDoc)
881 OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
882 return false;
885 if (GetViewData().SelectionForbidsPaste(pClipDoc))
886 return false;
888 // undo: save all or no content
889 InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE;
890 if (nFlags & InsertDeleteFlags::CONTENTS)
891 nContFlags |= InsertDeleteFlags::CONTENTS;
892 if (nFlags & InsertDeleteFlags::ATTRIB)
893 nContFlags |= InsertDeleteFlags::ATTRIB;
894 // move attributes to undo without copying them from clip to doc
895 InsertDeleteFlags nUndoFlags = nContFlags;
896 if (nUndoExtraFlags & InsertDeleteFlags::ATTRIB)
897 nUndoFlags |= InsertDeleteFlags::ATTRIB;
898 // do not copy note captions into undo document
899 nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
901 ScClipParam& rClipParam = pClipDoc->GetClipParam();
902 if (rClipParam.isMultiRange())
904 // Source data is multi-range.
905 return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, false, bTranspose,
906 bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
909 ScMarkData& rMark = GetViewData().GetMarkData();
910 if (rMark.IsMultiMarked())
912 // Source data is single-range but destination is multi-range.
913 return PasteFromClipToMultiRanges(
914 nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
915 eMoveMode, nUndoFlags);
918 bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc
919 bool bIncludeFiltered = bCutMode;
921 // paste drawing: also if InsertDeleteFlags::NOTE is set (to create drawing layer for note captions)
922 bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (InsertDeleteFlags::OBJECTS|InsertDeleteFlags::NOTE) ) );
924 ScDocShellRef aTransShellRef; // for objects in xTransClip - must remain valid as long as xTransClip
925 ScDocument* pOrigClipDoc = nullptr;
926 ScDocumentUniquePtr xTransClip;
927 if ( bTranspose )
929 SCCOL nX;
930 SCROW nY;
931 // include filtered rows until TransposeClip can skip them
932 pClipDoc->GetClipArea( nX, nY, true );
933 if ( nY > static_cast<sal_Int32>(pClipDoc->MaxCol()) ) // too many lines for transpose
935 ErrorMessage(STR_PASTE_FULL);
936 return false;
938 pOrigClipDoc = pClipDoc; // refs
940 if ( bPasteDraw )
942 aTransShellRef = new ScDocShell; // DocShell needs a Ref immediately
943 aTransShellRef->DoInitNew();
945 ScDrawLayer::SetGlobalDrawPersist( aTransShellRef.get() );
947 xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
948 pClipDoc->TransposeClip(xTransClip.get(), nFlags, bAsLink, bIncludeFiltered);
949 pClipDoc = xTransClip.get();
951 ScDrawLayer::SetGlobalDrawPersist(nullptr);
954 // TODO: position this call better for performance.
955 ResetAutoSpellForContentChange();
957 SCCOL nStartCol;
958 SCROW nStartRow;
959 SCTAB nStartTab;
960 SCCOL nEndCol;
961 SCROW nEndRow;
962 SCTAB nEndTab;
963 SCCOL nClipSizeX;
964 SCROW nClipSizeY;
965 pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, true ); // size in clipboard doc
967 // size in target doc: include filtered rows only if CutMode is set
968 SCCOL nDestSizeX;
969 SCROW nDestSizeY;
970 pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
972 ScDocument& rDoc = GetViewData().GetDocument();
973 ScDocShell* pDocSh = GetViewData().GetDocShell();
974 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
975 const bool bRecord(rDoc.IsUndoEnabled());
977 ScDocShellModificator aModificator( *pDocSh );
979 ScRange aMarkRange;
980 ScMarkData aFilteredMark( rMark); // local copy for all modifications
981 ScMarkType eMarkType = GetViewData().GetSimpleArea( aMarkRange, aFilteredMark);
982 bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
983 bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
984 (bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));
986 if (!bNoPaste)
988 if (!rMark.IsMarked())
990 // Create a selection with clipboard row count and check that for
991 // filtered.
992 nStartCol = GetViewData().GetCurX();
993 nStartRow = GetViewData().GetCurY();
994 nStartTab = GetViewData().GetTabNo();
995 nEndCol = nStartCol + nDestSizeX;
996 nEndRow = nStartRow + nDestSizeY;
997 nEndTab = nStartTab;
998 aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
999 if (ScViewUtil::HasFiltered(aMarkRange, rDoc))
1001 bMarkIsFiltered = true;
1002 // Fit to clipboard's row count unfiltered rows. If there is no
1003 // fit assume that pasting is not possible. Note that nDestSizeY is
1004 // size-1 (difference).
1005 if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1006 bNoPaste = true;
1008 aFilteredMark.SetMarkArea( aMarkRange);
1010 else
1012 // Expand the marked area when the destination area is larger than the
1013 // current selection, to get the undo do the right thing. (i#106711)
1014 ScRange aRange;
1015 aFilteredMark.GetMarkArea( aRange );
1016 if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
1018 aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
1019 aFilteredMark.SetMarkArea(aRange);
1024 if (bNoPaste)
1026 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1027 return false;
1030 SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
1031 ScRangeList aRangeList;
1032 if (bMarkIsFiltered)
1034 ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1035 aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
1036 nUnfilteredRows = 0;
1037 size_t ListSize = aRangeList.size();
1038 for ( size_t i = 0; i < ListSize; ++i )
1040 ScRange & r = aRangeList[i];
1041 nUnfilteredRows += r.aEnd.Row() - r.aStart.Row() + 1;
1043 #if 0
1044 /* This isn't needed but could be a desired restriction. */
1045 // For filtered, destination rows have to be an exact multiple of
1046 // source rows. Note that nDestSizeY is size-1 (difference), so
1047 // nDestSizeY==0 fits always.
1048 if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
1050 /* FIXME: this should be a more descriptive error message then. */
1051 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1052 return false;
1054 #endif
1057 // Also for a filtered selection the area is used, for undo et al.
1058 if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
1060 aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1061 SCCOL nBlockAddX = nEndCol-nStartCol;
1062 SCROW nBlockAddY = nEndRow-nStartRow;
1064 // request, if the selection is greater than one row/column, but smaller
1065 // as the Clipboard (then inserting is done beyond the selection)
1067 // ClipSize is not size, but difference
1068 if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
1069 ( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
1070 ( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
1072 ScWaitCursorOff aWaitOff( GetFrameWin() );
1073 OUString aMessage = ScResId( STR_PASTE_BIGGER );
1075 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
1076 VclMessageType::Question, VclButtonsType::YesNo,
1077 aMessage));
1078 xQueryBox->set_default_response(RET_NO);
1079 if (xQueryBox->run() != RET_YES)
1081 return false;
1085 if (nBlockAddX <= nDestSizeX)
1086 nEndCol = nStartCol + nDestSizeX;
1088 if (nBlockAddY <= nDestSizeY)
1090 nEndRow = nStartRow + nDestSizeY;
1091 if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
1093 // Same as above if nothing was marked: re-fit selection to
1094 // unfiltered rows. Extending the selection actually may
1095 // introduce filtered rows where there weren't any before, so
1096 // we also need to test for that.
1097 aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1098 if (bMarkIsFiltered || ScViewUtil::HasFiltered(aMarkRange, rDoc))
1100 bMarkIsFiltered = true;
1101 // Worst case: all rows up to the end of the sheet are filtered.
1102 if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1104 ErrorMessage(STR_PASTE_FULL);
1105 return false;
1108 aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1109 aFilteredMark.SetMarkArea( aMarkRange);
1110 if (bMarkIsFiltered)
1112 ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1113 aFilteredMark.FillRangeListWithMarks( &aRangeList, true);
1118 else
1120 nStartCol = GetViewData().GetCurX();
1121 nStartRow = GetViewData().GetCurY();
1122 nStartTab = GetViewData().GetTabNo();
1123 nEndCol = nStartCol + nDestSizeX;
1124 nEndRow = nStartRow + nDestSizeY;
1125 nEndTab = nStartTab;
1128 bool bOffLimits = !rDoc.ValidCol(nEndCol) || !rDoc.ValidRow(nEndRow);
1130 // target-range, as displayed:
1131 ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
1133 // should lines be inserted?
1134 // ( too large nEndCol/nEndRow are detected below)
1135 bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
1136 if ( bInsertCells )
1138 // Instead of EnterListAction, the paste undo action is merged into the
1139 // insert action, so Repeat can insert the right cells
1141 MarkRange( aUserRange ); // set through CopyFromClip
1143 // CutMode is reset on insertion of cols/rows but needed again on cell move
1144 bool bCut = pClipDoc->IsCutMode();
1145 if (!InsertCells( eMoveMode, bRecord, true )) // is inserting possible?
1147 return false;
1148 // #i21036# EnterListAction isn't used, and InsertCells doesn't insert
1149 // its undo action on failure, so no undo handling is needed here
1151 if ( bCut )
1152 pClipDoc->SetCutMode( bCut );
1154 else if (!bOffLimits)
1156 bool bAskIfNotEmpty = bAllowDialogs &&
1157 ( nFlags & InsertDeleteFlags::CONTENTS ) &&
1158 nFunction == ScPasteFunc::NONE &&
1159 SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1160 if ( bAskIfNotEmpty )
1162 ScRangeList aTestRanges(aUserRange);
1163 if (!checkDestRangeForOverwrite(aTestRanges, rDoc, aFilteredMark, GetViewData().GetDialogParent()))
1164 return false;
1168 SCCOL nClipStartX; // enlarge clipboard-range
1169 SCROW nClipStartY;
1170 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1171 SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
1172 SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document
1173 bool bClipOver = false;
1174 // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
1175 // The same end column/row can be used for all calls because the clip doc doesn't contain
1176 // content outside the clip area.
1177 for (SCTAB nClipTab=0; nClipTab < pClipDoc->GetTableCount(); nClipTab++)
1178 if ( pClipDoc->HasTable(nClipTab) )
1179 if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab ) )
1180 bClipOver = true;
1181 nUndoEndCol -= nClipStartX + nClipSizeX;
1182 nUndoEndRow -= nClipStartY + nClipSizeY; // now contains only the difference added by ExtendMerge
1183 nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
1184 nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
1186 if (nUndoEndCol>pClipDoc->MaxCol() || nUndoEndRow>pClipDoc->MaxRow())
1188 ErrorMessage(STR_PASTE_FULL);
1189 return false;
1192 rDoc.ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark );
1194 // check cell-protection
1196 ScEditableTester aTester( rDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
1197 if (!aTester.IsEditable())
1199 ErrorMessage(aTester.GetMessageId());
1200 return false;
1203 //! check overlapping
1204 //! just check truly intersection !!!!!!!
1206 ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
1207 if ( bRecord )
1209 OUString aUndo = ScResId( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
1210 pUndoMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
1213 if (bClipOver)
1214 if (lcl_SelHasAttrib( rDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HasAttrFlags::Overlapped ))
1215 { // "Cell merge not possible if cells already merged"
1216 ScDocAttrIterator aIter( rDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
1217 const ScPatternAttr* pPattern = nullptr;
1218 SCCOL nCol = -1;
1219 SCROW nRow1 = -1;
1220 SCROW nRow2 = -1;
1221 while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != nullptr )
1223 const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
1224 const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
1225 if (rMergeFlag.IsMerged() || rMergeFlagAttr.IsOverlapped())
1227 ScRange aRange(nCol, nRow1, nStartTab);
1228 rDoc.ExtendOverlapped(aRange);
1229 rDoc.ExtendMerge(aRange, true);
1230 rDocFunc.UnmergeCells(aRange, bRecord, nullptr /*TODO: should pass combined UndoDoc if bRecord*/);
1235 if ( !bCutMode )
1237 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1238 if ( pChangeTrack )
1239 pChangeTrack->ResetLastCut(); // no more cut-mode
1242 bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
1243 bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
1245 ScDocumentUniquePtr pUndoDoc;
1246 std::unique_ptr<ScDocument> pRefUndoDoc;
1247 std::unique_ptr<ScRefUndoData> pUndoData;
1249 if ( bRecord )
1251 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1252 pUndoDoc->InitUndoSelected( rDoc, aFilteredMark, bColInfo, bRowInfo );
1254 // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
1255 SCTAB nTabCount = rDoc.GetTableCount();
1256 rDoc.CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
1257 nUndoFlags, false, *pUndoDoc );
1259 if ( bCutMode )
1261 pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1262 pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
1264 pUndoData.reset(new ScRefUndoData( &rDoc ));
1268 sal_uInt16 nExtFlags = 0;
1269 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1270 nEndCol, nEndRow, nEndTab ); // content before the change
1272 if (GetViewData().IsActive())
1274 DoneBlockMode();
1275 InitOwnBlockMode();
1277 rMark.SetMarkArea( aUserRange );
1278 MarkDataChanged();
1280 // copy from clipboard
1281 // save original data in case of calculation
1283 ScDocumentUniquePtr pMixDoc;
1284 if (nFunction != ScPasteFunc::NONE)
1286 bSkipEmptyCells = false;
1287 if ( nFlags & InsertDeleteFlags::CONTENTS )
1289 pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1290 pMixDoc->InitUndo( rDoc, nStartTab, nEndTab );
1291 rDoc.CopyToDocument(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
1292 InsertDeleteFlags::CONTENTS, false, *pMixDoc);
1296 /* Make draw layer and start drawing undo.
1297 - Needed before AdjustBlockHeight to track moved drawing objects.
1298 - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1300 if ( bPasteDraw )
1301 pDocSh->MakeDrawLayer();
1302 if ( bRecord )
1303 rDoc.BeginDrawUndo();
1305 InsertDeleteFlags nNoObjFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1306 if (!bAsLink)
1308 // copy normally (original range)
1309 rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
1310 pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
1311 bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );
1313 // adapt refs manually in case of transpose
1314 if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
1315 rDoc.UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc.get() );
1317 else if (!bTranspose)
1319 // copy with bAsLink=TRUE
1320 rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
1321 true, true, bIncludeFiltered, bSkipEmptyCells );
1323 else
1325 // copy all content (TransClipDoc contains only formula)
1326 rDoc.CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc.get(), pClipDoc );
1329 // skipped rows and merged cells don't mix
1330 if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1331 rDocFunc.UnmergeCells( aUserRange, false, nullptr );
1333 rDoc.ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true ); // refresh
1334 // new range
1336 if ( pMixDoc ) // calculate with original data?
1338 rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
1340 pMixDoc.reset();
1342 AdjustBlockHeight(); // update row heights before pasting objects
1344 ::std::vector< OUString > aExcludedChartNames;
1345 SdrPage* pPage = nullptr;
1347 if ( nFlags & InsertDeleteFlags::OBJECTS )
1349 ScDrawView* pScDrawView = GetScDrawView();
1350 SdrModel* pModel = ( pScDrawView ? pScDrawView->GetModel() : nullptr );
1351 pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : nullptr );
1352 if ( pPage )
1354 ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
1357 // Paste the drawing objects after the row heights have been updated.
1359 rDoc.CopyFromClip( aUserRange, aFilteredMark, InsertDeleteFlags::OBJECTS, pRefUndoDoc.get(), pClipDoc,
1360 true, false, bIncludeFiltered );
1363 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1364 nEndCol, nEndRow, nEndTab ); // content after the change
1366 // if necessary, delete autofilter-heads
1367 if (bCutMode)
1368 if (rDoc.RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
1369 nClipStartY+nClipSizeY, nStartTab ))
1371 pDocSh->PostPaint(
1372 ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
1373 PaintPartFlags::Grid );
1376 //! remove block-range on RefUndoDoc !!!
1378 if ( bRecord )
1380 ScDocumentUniquePtr pRedoDoc;
1381 // copy redo data after appearance of the first undo
1382 // don't create Redo-Doc without RefUndoDoc
1384 if (pRefUndoDoc)
1386 pRedoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1387 pRedoDoc->InitUndo( rDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
1389 // move adapted refs to Redo-Doc
1391 SCTAB nTabCount = rDoc.GetTableCount();
1392 pRedoDoc->AddUndoTab( 0, nTabCount-1 );
1393 rDoc.CopyUpdated( pRefUndoDoc.get(), pRedoDoc.get() );
1395 // move old refs to Undo-Doc
1397 // not charts?
1398 pUndoDoc->AddUndoTab( 0, nTabCount-1 );
1399 pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, InsertDeleteFlags::ALL );
1400 pRefUndoDoc->CopyToDocument( 0,0,0, pUndoDoc->MaxCol(), pUndoDoc->MaxRow(), nTabCount-1,
1401 InsertDeleteFlags::FORMULA, false, *pUndoDoc );
1402 pRefUndoDoc.reset();
1405 // DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
1406 // UndoData for redo is made during first undo
1408 ScUndoPasteOptions aOptions; // store options for repeat
1409 aOptions.nFunction = nFunction;
1410 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1411 aOptions.bTranspose = bTranspose;
1412 aOptions.bAsLink = bAsLink;
1413 aOptions.eMoveMode = eMoveMode;
1415 std::unique_ptr<SfxUndoAction> pUndo(new ScUndoPaste(
1416 pDocSh, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1417 aFilteredMark, std::move(pUndoDoc), std::move(pRedoDoc), nFlags | nUndoFlags, std::move(pUndoData),
1418 false, &aOptions )); // false = Redo data not yet copied
1420 if ( bInsertCells )
1422 // Merge the paste undo action into the insert action.
1423 // Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
1425 pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
1427 else
1428 pUndoMgr->AddUndoAction( std::move(pUndo) );
1429 pUndoMgr->LeaveListAction();
1432 PaintPartFlags nPaint = PaintPartFlags::Grid;
1433 if (bColInfo)
1435 nPaint |= PaintPartFlags::Top;
1436 nUndoEndCol = rDoc.MaxCol(); // just for drawing !
1438 if (bRowInfo)
1440 nPaint |= PaintPartFlags::Left;
1441 nUndoEndRow = rDoc.MaxRow(); // just for drawing !
1443 pDocSh->PostPaint(
1444 ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1445 nPaint, nExtFlags);
1446 // AdjustBlockHeight has already been called above
1448 aModificator.SetDocumentModified();
1449 PostPasteFromClip(aUserRange, rMark);
1451 if ( nFlags & InsertDeleteFlags::OBJECTS )
1453 ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>( pDocSh->GetModel() );
1454 if ( pPage && pModelObj )
1456 bool bSameDoc = ( rClipParam.getSourceDocID() == rDoc.GetDocumentID() );
1457 const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
1458 ScChartHelper::CreateProtectedChartListenersAndNotify( rDoc, pPage, pModelObj, nStartTab,
1459 rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
1462 OUString aStartAddress = aMarkRange.aStart.GetColRowString();
1463 OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
1464 collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "PASTE");
1465 return true;
1468 bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
1469 ScPasteFunc nFunction, bool bSkipEmptyCells,
1470 bool bIncludeFiltered, bool bTranspose, bool bAsLink,
1471 bool bAllowDialogs, InsCellCmd eMoveMode,
1472 InsertDeleteFlags nUndoFlags)
1474 ScViewData& rViewData = GetViewData();
1475 ScDocument& rDoc = rViewData.GetDocument();
1476 ScDocShell* pDocSh = rViewData.GetDocShell();
1477 ScMarkData aMark(rViewData.GetMarkData());
1478 const ScAddress& rCurPos = rViewData.GetCurPos();
1479 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1480 SCCOL nColSize = rClipParam.getPasteColSize();
1481 SCROW nRowSize = rClipParam.getPasteRowSize(*pClipDoc, bIncludeFiltered);
1483 if (bTranspose)
1485 if (static_cast<SCROW>(rCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(pClipDoc->MaxCol()))
1487 ErrorMessage(STR_PASTE_FULL);
1488 return false;
1491 ScDocumentUniquePtr pTransClip(new ScDocument(SCDOCMODE_CLIP));
1492 pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink, bIncludeFiltered);
1493 pClipDoc = pTransClip.release();
1494 SCCOL nTempColSize = nColSize;
1495 nColSize = static_cast<SCCOL>(nRowSize);
1496 nRowSize = static_cast<SCROW>(nTempColSize);
1499 if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
1501 ErrorMessage(STR_PASTE_FULL);
1502 return false;
1505 // Determine the first and last selected sheet numbers.
1506 SCTAB nTab1 = aMark.GetFirstSelected();
1507 SCTAB nTab2 = aMark.GetLastSelected();
1509 ScDocShellModificator aModificator(*pDocSh);
1511 // For multi-selection paste, we don't support cell duplication for larger
1512 // destination range. In case the destination is marked, we reset it to
1513 // the clip size.
1514 ScRange aMarkedRange(rCurPos.Col(), rCurPos.Row(), nTab1,
1515 rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, nTab2);
1517 // Extend the marked range to account for filtered rows in the destination
1518 // area.
1519 if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
1521 if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize))
1522 return false;
1525 bool bAskIfNotEmpty =
1526 bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1527 nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1529 if (bAskIfNotEmpty)
1531 ScRangeList aTestRanges(aMarkedRange);
1532 if (!checkDestRangeForOverwrite(aTestRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1533 return false;
1536 aMark.SetMarkArea(aMarkedRange);
1537 MarkRange(aMarkedRange);
1539 bool bInsertCells = (eMoveMode != INS_NONE);
1540 if (bInsertCells)
1542 if (!InsertCells(eMoveMode, rDoc.IsUndoEnabled(), true))
1543 return false;
1546 // TODO: position this call better for performance.
1547 ResetAutoSpellForContentChange();
1549 bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
1550 ScDocumentUniquePtr pUndoDoc;
1551 if (rDoc.IsUndoEnabled())
1553 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1554 pUndoDoc->InitUndoSelected(rDoc, aMark, false, bRowInfo);
1555 rDoc.CopyToDocument(aMarkedRange, nUndoFlags, false, *pUndoDoc, &aMark);
1558 ScDocumentUniquePtr pMixDoc;
1559 if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1561 if ( nFlags & InsertDeleteFlags::CONTENTS )
1563 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1564 pMixDoc->InitUndoSelected(rDoc, aMark);
1565 rDoc.CopyToDocument(aMarkedRange, InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1569 /* Make draw layer and start drawing undo.
1570 - Needed before AdjustBlockHeight to track moved drawing objects.
1571 - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1573 if (nFlags & InsertDeleteFlags::OBJECTS)
1574 pDocSh->MakeDrawLayer();
1575 if (rDoc.IsUndoEnabled())
1576 rDoc.BeginDrawUndo();
1578 InsertDeleteFlags nCopyFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1579 // in case of transpose, links were added in TransposeClip()
1580 if (bAsLink && bTranspose)
1581 nCopyFlags |= InsertDeleteFlags::FORMULA;
1582 rDoc.CopyMultiRangeFromClip(rCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
1583 bIncludeFiltered, bSkipEmptyCells);
1585 if (pMixDoc)
1586 rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);
1588 AdjustBlockHeight(); // update row heights before pasting objects
1590 if (nFlags & InsertDeleteFlags::OBJECTS)
1592 // Paste the drawing objects after the row heights have been updated.
1593 rDoc.CopyMultiRangeFromClip(rCurPos, aMark, InsertDeleteFlags::OBJECTS, pClipDoc, true,
1594 false, bIncludeFiltered, true);
1597 if (bRowInfo)
1598 pDocSh->PostPaint(aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nTab1, PaintPartFlags::Grid|PaintPartFlags::Left);
1599 else
1601 ScRange aTmp = aMarkedRange;
1602 aTmp.aStart.SetTab(nTab1);
1603 aTmp.aEnd.SetTab(nTab1);
1604 pDocSh->PostPaint(aTmp, PaintPartFlags::Grid);
1607 if (rDoc.IsUndoEnabled())
1609 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1610 OUString aUndo = ScResId(
1611 pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1612 pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1614 ScUndoPasteOptions aOptions; // store options for repeat
1615 aOptions.nFunction = nFunction;
1616 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1617 aOptions.bTranspose = bTranspose;
1618 aOptions.bAsLink = bAsLink;
1619 aOptions.eMoveMode = eMoveMode;
1621 std::unique_ptr<ScUndoPaste> pUndo(new ScUndoPaste(pDocSh,
1622 aMarkedRange, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1624 if (bInsertCells)
1625 pUndoMgr->AddUndoAction(std::make_unique<ScUndoWrapper>(std::move(pUndo)), true);
1626 else
1627 pUndoMgr->AddUndoAction(std::move(pUndo));
1629 pUndoMgr->LeaveListAction();
1632 aModificator.SetDocumentModified();
1633 PostPasteFromClip(aMarkedRange, aMark);
1634 return true;
1637 bool ScViewFunc::PasteFromClipToMultiRanges(
1638 InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
1639 bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
1640 InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
1642 if (bTranspose)
1644 // We don't allow transpose for this yet.
1645 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1646 return false;
1649 if (eMoveMode != INS_NONE)
1651 // We don't allow insertion mode either. Too complicated.
1652 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1653 return false;
1656 ScViewData& rViewData = GetViewData();
1657 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1658 if (rClipParam.mbCutMode)
1660 // No cut and paste with this, please.
1661 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1662 return false;
1665 const ScAddress& rCurPos = rViewData.GetCurPos();
1666 ScDocument& rDoc = rViewData.GetDocument();
1668 ScRange aSrcRange = rClipParam.getWholeRange();
1669 SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
1670 SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
1672 if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
1674 ErrorMessage(STR_PASTE_FULL);
1675 return false;
1678 ScMarkData aMark(rViewData.GetMarkData());
1680 ScRangeList aRanges;
1681 aMark.MarkToSimple();
1682 aMark.FillRangeListWithMarks(&aRanges, false);
1683 if (!ScClipUtil::CheckDestRanges(rDoc, nColSize, nRowSize, aMark, aRanges))
1685 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1686 return false;
1689 ScDocShell* pDocSh = rViewData.GetDocShell();
1691 ScDocShellModificator aModificator(*pDocSh);
1693 bool bAskIfNotEmpty =
1694 bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1695 nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1697 if (bAskIfNotEmpty)
1699 if (!checkDestRangeForOverwrite(aRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1700 return false;
1703 // TODO: position this call better for performance.
1704 ResetAutoSpellForContentChange();
1706 ScDocumentUniquePtr pUndoDoc;
1707 if (rDoc.IsUndoEnabled())
1709 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1710 pUndoDoc->InitUndoSelected(rDoc, aMark);
1711 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1713 rDoc.CopyToDocument(
1714 aRanges[i], nUndoFlags, false, *pUndoDoc, &aMark);
1718 ScDocumentUniquePtr pMixDoc;
1719 if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1721 if (nFlags & InsertDeleteFlags::CONTENTS)
1723 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1724 pMixDoc->InitUndoSelected(rDoc, aMark);
1725 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1727 rDoc.CopyToDocument(
1728 aRanges[i], InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1733 if (nFlags & InsertDeleteFlags::OBJECTS)
1734 pDocSh->MakeDrawLayer();
1735 if (rDoc.IsUndoEnabled())
1736 rDoc.BeginDrawUndo();
1738 // First, paste everything but the drawing objects.
1739 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1741 rDoc.CopyFromClip(
1742 aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
1743 false, false, true, bSkipEmptyCells);
1746 if (pMixDoc)
1748 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1749 rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
1752 AdjustBlockHeight(); // update row heights before pasting objects
1754 // Then paste the objects.
1755 if (nFlags & InsertDeleteFlags::OBJECTS)
1757 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1759 rDoc.CopyFromClip(
1760 aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
1761 false, false, true, bSkipEmptyCells);
1765 // Refresh the range that includes all pasted ranges. We only need to
1766 // refresh the current sheet.
1767 PaintPartFlags nPaint = PaintPartFlags::Grid;
1768 bool bRowInfo = (aSrcRange.aStart.Col()==0 && aSrcRange.aEnd.Col()==pClipDoc->MaxCol());
1769 if (bRowInfo)
1770 nPaint |= PaintPartFlags::Left;
1771 pDocSh->PostPaint(aRanges, nPaint);
1773 if (rDoc.IsUndoEnabled())
1775 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1776 OUString aUndo = ScResId(
1777 pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1778 pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1780 ScUndoPasteOptions aOptions; // store options for repeat
1781 aOptions.nFunction = nFunction;
1782 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1783 aOptions.bTranspose = bTranspose;
1784 aOptions.bAsLink = bAsLink;
1785 aOptions.eMoveMode = eMoveMode;
1788 pUndoMgr->AddUndoAction(
1789 std::make_unique<ScUndoPaste>(
1790 pDocSh, aRanges, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1791 pUndoMgr->LeaveListAction();
1794 aModificator.SetDocumentModified();
1795 PostPasteFromClip(aRanges, aMark);
1797 return false;
1800 void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
1802 ScViewData& rViewData = GetViewData();
1803 ScDocShell* pDocSh = rViewData.GetDocShell();
1804 pDocSh->UpdateOle(rViewData);
1806 SelectionChanged(true);
1808 ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
1809 if (!pModelObj)
1810 return;
1812 ScRangeList aChangeRanges;
1813 for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
1815 const ScRange& r = rPasteRanges[i];
1816 for (const auto& rTab : rMark)
1818 ScRange aChangeRange(r);
1819 aChangeRange.aStart.SetTab(rTab);
1820 aChangeRange.aEnd.SetTab(rTab);
1821 aChangeRanges.push_back(aChangeRange);
1824 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
1827 // D R A G A N D D R O P
1829 // inside the doc
1831 bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
1832 bool bCut )
1834 ScDocShell* pDocSh = GetViewData().GetDocShell();
1835 HideAllCursors();
1837 ResetAutoSpellForContentChange();
1839 bool bSuccess = true;
1840 SCTAB nDestTab = rDestPos.Tab();
1841 const ScMarkData& rMark = GetViewData().GetMarkData();
1842 if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
1844 // moving within one table and several tables selected -> apply to all selected tables
1846 OUString aUndo = ScResId( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
1847 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
1849 // collect ranges of consecutive selected tables
1851 ScRange aLocalSource = rSource;
1852 ScAddress aLocalDest = rDestPos;
1853 SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
1854 SCTAB nStartTab = 0;
1855 while ( nStartTab < nTabCount && bSuccess )
1857 while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
1858 ++nStartTab;
1859 if ( nStartTab < nTabCount )
1861 SCTAB nEndTab = nStartTab;
1862 while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
1863 ++nEndTab;
1865 aLocalSource.aStart.SetTab( nStartTab );
1866 aLocalSource.aEnd.SetTab( nEndTab );
1867 aLocalDest.SetTab( nStartTab );
1869 bSuccess = pDocSh->GetDocFunc().MoveBlock(
1870 aLocalSource, aLocalDest, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
1872 nStartTab = nEndTab + 1;
1876 pDocSh->GetUndoManager()->LeaveListAction();
1878 else
1880 // move the block as specified
1881 bSuccess = pDocSh->GetDocFunc().MoveBlock(
1882 rSource, rDestPos, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
1885 ShowAllCursors();
1886 if (bSuccess)
1888 // mark destination range
1889 ScAddress aDestEnd(
1890 rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
1891 rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
1892 nDestTab );
1894 bool bIncludeFiltered = bCut;
1895 if ( !bIncludeFiltered )
1897 // find number of non-filtered rows
1898 SCROW nPastedCount = pDocSh->GetDocument().CountNonFilteredRows(
1899 rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
1901 if ( nPastedCount == 0 )
1902 nPastedCount = 1;
1903 aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
1906 MarkRange( ScRange( rDestPos, aDestEnd ), false ); //! sal_False ???
1908 pDocSh->UpdateOle(GetViewData());
1909 SelectionChanged();
1911 return bSuccess;
1914 // link inside the doc
1916 bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos )
1918 // check overlapping
1920 if ( rSource.aStart.Tab() == rDestPos.Tab() )
1922 SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
1923 SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
1925 if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
1926 rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
1928 return false;
1932 // run with paste
1934 ScDocument& rDoc = GetViewData().GetDocument();
1935 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1936 rDoc.CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
1937 rSource.aEnd.Col(), rSource.aEnd.Row(),
1938 rSource.aStart.Tab(), pClipDoc.get() );
1940 // mark destination area (set cursor, no marks)
1942 if ( GetViewData().GetTabNo() != rDestPos.Tab() )
1943 SetTabNo( rDestPos.Tab() );
1945 MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
1947 // Paste
1949 PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(), ScPasteFunc::NONE, false, false, true ); // as a link
1951 return true;
1954 void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
1955 SCROW nStartRow , SCCOL nStartCol ,
1956 SCROW nEndRow , SCCOL nEndCol ,
1957 std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
1958 sal_uInt16 aColLength )
1960 ScDocument& rDoc = GetViewData().GetDocument();
1961 ScDocShell* pDocSh = GetViewData().GetDocShell();
1962 ScMarkData& rMark = GetViewData().GetMarkData();
1963 ScDocShellModificator aModificator( *pDocSh );
1964 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1966 const bool bRecord( rDoc.IsUndoEnabled());
1967 ScDocumentUniquePtr pUndoDoc;
1968 ScDocumentUniquePtr pRedoDoc;
1969 std::unique_ptr<ScRefUndoData> pUndoData;
1970 SCTAB nTab = GetViewData().GetTabNo();
1971 SCTAB nStartTab = nTab;
1972 SCTAB nEndTab = nTab;
1975 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1976 if ( pChangeTrack )
1977 pChangeTrack->ResetLastCut(); // no more cut-mode
1979 ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
1980 bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
1981 bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
1982 SCCOL nUndoEndCol = nStartCol+aColLength-1;
1983 SCROW nUndoEndRow = nCurrentRow;
1985 if ( bRecord )
1987 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1988 pUndoDoc->InitUndoSelected( rDoc , rMark , bColInfo , bRowInfo );
1989 rDoc.CopyToDocument( aUserRange , InsertDeleteFlags::VALUE , false, *pUndoDoc );
1991 sal_uInt16 nExtFlags = 0;
1992 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
1993 rDoc.BeginDrawUndo();
1995 for(sal_uInt16 i = 0; i < aColLength; i++)
1997 if (rEdits[i] != nullptr)
1999 OUString aFieldName = rEdits[i]->m_xEdit->get_text();
2000 rDoc.SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
2003 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab ); // content after the change
2004 std::unique_ptr<SfxUndoAction> pUndo( new ScUndoDataForm( pDocSh,
2005 nStartCol, nCurrentRow, nStartTab,
2006 nUndoEndCol, nUndoEndRow, nEndTab, rMark,
2007 std::move(pUndoDoc), std::move(pRedoDoc),
2008 std::move(pUndoData) ) );
2009 pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
2011 PaintPartFlags nPaint = PaintPartFlags::Grid;
2012 if (bColInfo)
2014 nPaint |= PaintPartFlags::Top;
2015 nUndoEndCol = rDoc.MaxCol(); // just for drawing !
2017 if (bRowInfo)
2019 nPaint |= PaintPartFlags::Left;
2020 nUndoEndRow = rDoc.MaxRow(); // just for drawing !
2023 pDocSh->PostPaint(
2024 ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
2025 nPaint, nExtFlags);
2026 pDocSh->UpdateOle(GetViewData());
2029 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */