tdf#137335 calculate paragraph height in RTF/DOCX
[LibreOffice.git] / sc / source / ui / view / viewfun3.cxx
blobd3e40076187a4a43d567958e036604057ff66edf
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( aRange );
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}}, u"CUT"_ustr);
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}}, u"COPY"_ustr);
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 std::shared_ptr<ScDocument> pSysClipDoc;
229 if ( !pClipDoc ) // no clip doc specified
231 // Create one (deleted by ScTransferObj), and copy into system.
232 pSysClipDoc = std::make_shared<ScDocument>( SCDOCMODE_CLIP );
233 pClipDoc = pSysClipDoc.get();
235 if ( !bCut )
237 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
238 if ( pChangeTrack )
239 pChangeTrack->ResetLastCut();
242 if ( pSysClipDoc && bIncludeObjects )
244 bool bAnyOle = rDoc.HasOLEObjectsInArea( aRange );
245 // Update ScGlobal::xDrawClipDocShellRef.
246 ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle, pSysClipDoc ) );
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 (ScDocShell* pObjectShell = rDoc.GetDocumentShell())
256 // Copy document properties from pObjectShell to pClipDoc (to its clip options, as it has no object shell).
257 uno::Reference<util::XCloneable> xCloneable(pObjectShell->getDocProperties(), uno::UNO_QUERY_THROW);
258 std::unique_ptr<ScClipOptions> pOptions(new ScClipOptions);
259 pOptions->m_xDocumentProperties.set(xCloneable->createClone(), uno::UNO_QUERY);
260 pClipDoc->SetClipOptions(std::move(pOptions));
263 rDoc.CopyToClip( aClipParam, pClipDoc, &rMark, false, bIncludeObjects );
264 if (ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer())
266 ScClipParam& rClipDocClipParam = pClipDoc->GetClipParam();
267 ScRangeListVector& rRangesVector = rClipDocClipParam.maProtectedChartRangesVector;
268 SCTAB nTabCount = pClipDoc->GetTableCount();
269 for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
271 SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
272 if ( pPage )
274 ScChartHelper::FillProtectedChartRangesVector( rRangesVector, rDoc, pPage );
279 if ( pSysClipDoc )
281 ScDrawLayer::SetGlobalDrawPersist(nullptr);
282 ScGlobal::SetClipDocName( rDoc.GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
284 pClipDoc->ExtendMerge( aRange, true );
286 if ( pSysClipDoc )
288 ScDocShell* pDocSh = GetViewData().GetDocShell();
289 TransferableObjectDescriptor aObjDesc;
290 pDocSh->FillTransferableObjectDescriptor( aObjDesc );
291 aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
292 // maSize is set in ScTransferObj ctor
294 rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( pSysClipDoc, std::move(aObjDesc) ));
295 if ( ScGlobal::xDrawClipDocShellRef.is() )
297 SfxObjectShellRef aPersistRef(ScGlobal::xDrawClipDocShellRef);
298 pTransferObj->SetDrawPersist( aPersistRef );// keep persist for ole objects alive
300 pTransferObj->CopyToClipboard( GetActiveWin() );
303 return true;
306 bool ScViewFunc::CopyToClipMultiRange( const ScDocument* pInputClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects )
308 if (bCut)
310 // We don't support cutting of multi-selections.
311 if (!bApi)
312 ErrorMessage(STR_NOMULTISELECT);
313 return false;
315 if (pInputClipDoc)
317 // TODO: What's this for?
318 if (!bApi)
319 ErrorMessage(STR_NOMULTISELECT);
320 return false;
323 ScClipParam aClipParam( rRanges[0], bCut );
324 aClipParam.maRanges = rRanges;
325 ScDocument& rDoc = GetViewData().GetDocument();
326 ScMarkData& rMark = GetViewData().GetMarkData();
327 bool bDone = false;
328 bool bSuccess = false;
329 aClipParam.mbCutMode = false;
333 ScDocumentUniquePtr pDocClip(new ScDocument(SCDOCMODE_CLIP));
335 // Check for geometrical feasibility of the ranges.
336 bool bValidRanges = true;
337 ScRange const * p = &aClipParam.maRanges.front();
338 SCCOL nPrevColDelta = 0;
339 SCROW nPrevRowDelta = 0;
340 SCCOL nPrevCol = p->aStart.Col();
341 SCROW nPrevRow = p->aStart.Row();
342 SCCOL nPrevColSize = p->aEnd.Col() - p->aStart.Col() + 1;
343 SCROW nPrevRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
344 for ( size_t i = 1; i < aClipParam.maRanges.size(); ++i )
346 p = &aClipParam.maRanges[i];
347 if ( rDoc.HasSelectedBlockMatrixFragment(
348 p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark) )
350 if (!bApi)
351 ErrorMessage(STR_MATRIXFRAGMENTERR);
352 return false;
355 SCCOL nColDelta = p->aStart.Col() - nPrevCol;
356 SCROW nRowDelta = p->aStart.Row() - nPrevRow;
358 if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
360 bValidRanges = false;
361 break;
364 if (aClipParam.meDirection == ScClipParam::Unspecified)
366 if (nColDelta)
367 aClipParam.meDirection = ScClipParam::Column;
368 if (nRowDelta)
369 aClipParam.meDirection = ScClipParam::Row;
372 SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
373 SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
375 if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
377 // column-oriented ranges must have identical row size.
378 bValidRanges = false;
379 break;
381 if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
383 // likewise, row-oriented ranges must have identical
384 // column size.
385 bValidRanges = false;
386 break;
389 nPrevCol = p->aStart.Col();
390 nPrevRow = p->aStart.Row();
391 nPrevColDelta = nColDelta;
392 nPrevRowDelta = nRowDelta;
393 nPrevColSize = nColSize;
394 nPrevRowSize = nRowSize;
396 if (!bValidRanges)
397 break;
398 rDoc.CopyToClip(aClipParam, pDocClip.get(), &rMark, false, bIncludeObjects );
400 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
401 if ( pChangeTrack )
402 pChangeTrack->ResetLastCut(); // no more cut-mode
404 ScDocShell* pDocSh = GetViewData().GetDocShell();
405 TransferableObjectDescriptor aObjDesc;
406 pDocSh->FillTransferableObjectDescriptor( aObjDesc );
407 aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
408 // maSize is set in ScTransferObj ctor
410 rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( std::move(pDocClip), std::move(aObjDesc) ));
411 if ( ScGlobal::xDrawClipDocShellRef.is() )
413 SfxObjectShellRef aPersistRef(ScGlobal::xDrawClipDocShellRef);
414 pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
416 pTransferObj->CopyToClipboard( GetActiveWin() ); // system clipboard
418 bSuccess = true;
420 while (false);
422 if (!bSuccess && !bApi)
423 ErrorMessage(STR_NOMULTISELECT);
425 bDone = bSuccess;
427 return bDone;
430 rtl::Reference<ScTransferObj> ScViewFunc::CopyToTransferable()
432 ScRange aRange;
433 auto eMarkType = GetViewData().GetSimpleArea( aRange );
434 if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
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), std::move(aObjDesc) );
461 else if (eMarkType == SC_MARK_MULTI)
463 ScDocumentUniquePtr pClipDoc(new ScDocument(SCDOCMODE_CLIP));
464 // This takes care of the input line and calls CopyToClipMultiRange() for us.
465 CopyToClip(pClipDoc.get(), aRange, /*bCut=*/false, /*bApi=*/true);
466 TransferableObjectDescriptor aObjDesc;
467 return new ScTransferObj(std::move(pClipDoc), std::move(aObjDesc));
470 return nullptr;
473 // P A S T E
475 void ScViewFunc::PasteDraw()
477 ScViewData& rViewData = GetViewData();
478 SCCOL nPosX = rViewData.GetCurX();
479 SCROW nPosY = rViewData.GetCurY();
480 vcl::Window* pWin = GetActiveWin();
481 Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY,
482 rViewData.GetActivePart() ) );
483 const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewData.GetActiveWin()));
484 if (pDrawClip)
486 const OUString& aSrcShellID = pDrawClip->GetShellID();
487 OUString aDestShellID = SfxObjectShell::CreateShellID(rViewData.GetDocShell());
488 PasteDraw(aPos, pDrawClip->GetModel(), false, aSrcShellID, aDestShellID);
492 void ScViewFunc::PasteFromSystem()
494 UpdateInputLine();
496 vcl::Window* pWin = GetActiveWin();
497 css::uno::Reference<css::datatransfer::XTransferable2> xTransferable2(ScTabViewShell::GetClipData(pWin));
498 const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(xTransferable2);
499 // keep a reference in case the clipboard is changed during PasteFromClip
500 const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(xTransferable2);
501 if (pOwnClip)
503 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
504 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
505 true ); // allow warning dialog
507 else if (pDrawClip)
508 PasteDraw();
509 else
511 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
514 SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr);
515 SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr);
517 SotClipboardFormatId nFormat; // output param for GetExchangeAction
518 sal_uInt8 nEventAction; // output param for GetExchangeAction
520 uno::Reference<css::datatransfer::XTransferable> xTransferable( aDataHelper.GetXTransferable() );
521 sal_uInt8 nAction = SotExchange::GetExchangeAction(
522 aDataHelper.GetDataFlavorExVector(),
523 SotExchangeDest::SCDOC_FREE_AREA,
524 EXCHG_IN_ACTION_COPY,
525 EXCHG_IN_ACTION_DEFAULT,
526 nFormat, nEventAction, SotClipboardFormatId::NONE,
527 &xTransferable );
529 if ( nAction != EXCHG_INOUT_ACTION_NONE )
531 switch( nAction )
533 case EXCHG_OUT_ACTION_INSERT_SVXB:
534 case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
535 case EXCHG_OUT_ACTION_INSERT_BITMAP:
536 case EXCHG_OUT_ACTION_INSERT_GRAPH:
537 // SotClipboardFormatId::BITMAP
538 // SotClipboardFormatId::PNG
539 // SotClipboardFormatId::GDIMETAFILE
540 // SotClipboardFormatId::SVXB
541 PasteFromSystem(nFormat);
542 break;
543 default:
544 nAction = EXCHG_INOUT_ACTION_NONE;
548 if ( nAction == EXCHG_INOUT_ACTION_NONE )
550 // first SvDraw-model, then drawing
551 // (only one drawing is allowed)
553 if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
555 // special case for tables from drawing
556 if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
558 PasteFromSystem( SotClipboardFormatId::RTF );
560 else if( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
562 PasteFromSystem( SotClipboardFormatId::RICHTEXT );
564 else
566 PasteFromSystem( SotClipboardFormatId::DRAWING );
569 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
571 // If it's a Writer object, insert RTF instead of OLE
573 // Else, if the class id is all-zero, and SYLK is available,
574 // it probably is spreadsheet cells that have been put
575 // on the clipboard by OOo, so use the SYLK. (fdo#31077)
577 bool bDoRtf = false;
578 TransferableObjectDescriptor aObjDesc;
579 if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
581 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
582 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
583 && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
585 if ( bDoRtf )
586 PasteFromSystem( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT );
587 else if ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
588 && aDataHelper.HasFormat( SotClipboardFormatId::SYLK ))
589 PasteFromSystem( SotClipboardFormatId::SYLK );
590 else
591 PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE );
593 else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
594 PasteFromSystem( SotClipboardFormatId::LINK_SOURCE );
595 // the following format can not affect scenario from #89579#
596 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
597 PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE );
598 // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
599 else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
600 PasteFromSystem(nBiff8);
601 else if (aDataHelper.HasFormat(nBiff5))
602 PasteFromSystem(nBiff5);
603 else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
604 PasteFromSystem(SotClipboardFormatId::RTF);
605 else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
606 PasteFromSystem(SotClipboardFormatId::RICHTEXT);
607 else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
608 PasteFromSystem(SotClipboardFormatId::HTML);
609 else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
610 PasteFromSystem(SotClipboardFormatId::BITMAP);
611 else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
612 PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE);
613 else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
614 PasteFromSystem(SotClipboardFormatId::SYLK);
615 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
616 PasteFromSystem(SotClipboardFormatId::STRING_TSVC);
617 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
618 PasteFromSystem(SotClipboardFormatId::STRING);
619 // xxx_OLE formats come last, like in SotExchange tables
620 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
621 PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE );
622 else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
623 PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
627 // no exception-> SID_PASTE has FastCall-flag from idl
628 // will be called in case of empty clipboard (#42531#)
631 void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
633 if (auto pOwnClip = dynamic_cast<ScTransferObj*>(rxTransferable.get()))
635 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
636 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
637 true ); // allow warning dialog
639 else if (auto pDrawClip = dynamic_cast<ScDrawTransferObj*>(rxTransferable.get()))
641 ScViewData& rViewData = GetViewData();
642 SCCOL nPosX = rViewData.GetCurX();
643 SCROW nPosY = rViewData.GetCurY();
644 vcl::Window* pWin = GetActiveWin();
645 Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY, rViewData.GetActivePart() ) );
646 PasteDraw(
647 aPos, pDrawClip->GetModel(), false,
648 pDrawClip->GetShellID(), SfxObjectShell::CreateShellID(rViewData.GetDocShell()));
650 else
652 TransferableDataHelper aDataHelper( rxTransferable );
653 SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName(u"Biff8"_ustr);
654 SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName(u"Biff5"_ustr);
655 SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
656 // first SvDraw-model, then drawing
657 // (only one drawing is allowed)
659 if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
660 nFormatId = SotClipboardFormatId::DRAWING;
661 else if (aDataHelper.HasFormat( SotClipboardFormatId::SVXB ))
662 nFormatId = SotClipboardFormatId::SVXB;
663 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
665 // If it's a Writer object, insert RTF instead of OLE
666 bool bDoRtf = false;
667 TransferableObjectDescriptor aObjDesc;
668 if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
670 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
671 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
672 && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ));
674 if ( bDoRtf )
675 nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
676 else
677 nFormatId = SotClipboardFormatId::EMBED_SOURCE;
679 else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
680 nFormatId = SotClipboardFormatId::LINK_SOURCE;
681 // the following format can not affect scenario from #89579#
682 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
683 nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
684 // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
685 else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
686 nFormatId = nBiff8;
687 else if (aDataHelper.HasFormat(nBiff5))
688 nFormatId = nBiff5;
689 else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
690 nFormatId = SotClipboardFormatId::RTF;
691 else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
692 nFormatId = SotClipboardFormatId::RICHTEXT;
693 else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
694 nFormatId = SotClipboardFormatId::HTML;
695 else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
696 nFormatId = SotClipboardFormatId::HTML_SIMPLE;
697 else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
698 nFormatId = SotClipboardFormatId::SYLK;
699 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
700 nFormatId = SotClipboardFormatId::STRING_TSVC;
701 else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
702 nFormatId = SotClipboardFormatId::STRING;
703 else if (aDataHelper.HasFormat(SotClipboardFormatId::GDIMETAFILE))
704 nFormatId = SotClipboardFormatId::GDIMETAFILE;
705 else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
706 nFormatId = SotClipboardFormatId::BITMAP;
707 // xxx_OLE formats come last, like in SotExchange tables
708 else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
709 nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
710 else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
711 nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
712 else
713 return;
715 PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
716 GetViewData().GetCurX(), GetViewData().GetCurY(), nullptr );
720 bool ScViewFunc::PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi )
722 UpdateInputLine();
724 bool bRet = true;
725 vcl::Window* pWin = GetActiveWin();
726 // keep a reference in case the clipboard is changed during PasteFromClip
727 const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
728 if ( nFormatId == SotClipboardFormatId::NONE && pOwnClip )
730 PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
731 ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
732 !bApi ); // allow warning dialog
734 else
736 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
737 if ( !aDataHelper.GetTransferable().is() )
738 return false;
740 SCCOL nPosX = 0;
741 SCROW nPosY = 0;
743 ScViewData& rViewData = GetViewData();
744 ScRange aRange;
745 if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
747 nPosX = aRange.aStart.Col();
748 nPosY = aRange.aStart.Row();
750 else
752 nPosX = rViewData.GetCurX();
753 nPosY = rViewData.GetCurY();
756 bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
757 nPosX, nPosY,
758 nullptr, false, !bApi ); // allow warning dialog
760 if ( !bRet && !bApi )
762 ErrorMessage(STR_PASTE_ERROR);
764 else if (comphelper::LibreOfficeKit::isActive())
766 ScTabViewShell* pTabViewShell = rViewData.GetViewShell();
767 pTabViewShell->OnLOKSetWidthOrHeight(rViewData.GetCurX(), true);
768 pTabViewShell->OnLOKSetWidthOrHeight(rViewData.GetCurY(), false);
770 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pTabViewShell, true /* bColumns */, true /* bRows */,
771 true /* bSizes */, false /* bHidden */, false /* bFiltered */, false /* bGroups */, rViewData.GetTabNo());
774 return bRet;
777 // P A S T E
779 bool ScViewFunc::PasteOnDrawObjectLinked(
780 const uno::Reference<datatransfer::XTransferable>& rxTransferable,
781 SdrObject& rHitObj)
783 TransferableDataHelper aDataHelper( rxTransferable );
785 if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
787 if (ScDrawView* pScDrawView = GetScDrawView())
788 if (std::unique_ptr<SvStream> xStm = aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB ) )
790 Graphic aGraphic;
791 TypeSerializer aSerializer(*xStm);
792 aSerializer.readGraphic(aGraphic);
794 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
796 if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, u""_ustr ))
798 return true;
802 else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
804 GDIMetaFile aMtf;
805 ScDrawView* pScDrawView = GetScDrawView();
807 if( pScDrawView && aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
809 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
811 if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, u""_ustr ))
813 return true;
817 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) || aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
819 BitmapEx aBmpEx;
820 ScDrawView* pScDrawView = GetScDrawView();
822 if( pScDrawView && aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ) )
824 const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
826 if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmpEx), aBeginUndo, u""_ustr ))
828 return true;
833 return false;
836 static bool lcl_SelHasAttrib( const ScDocument& rDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
837 const ScMarkData& rTabSelection, HasAttrFlags nMask )
839 return std::any_of(rTabSelection.begin(), rTabSelection.end(),
840 [&](const SCTAB& rTab) { return rDoc.HasAttrib( nCol1, nRow1, rTab, nCol2, nRow2, rTab, nMask ); });
843 // paste into sheet:
845 // internal paste
847 namespace {
849 bool checkDestRangeForOverwrite(InsertDeleteFlags nFlags, const ScRangeList& rDestRanges,
850 const ScDocument& rDoc, const ScMarkData& rMark,
851 weld::Window* pParentWnd)
853 bool bIsEmpty = true;
854 size_t nRangeSize = rDestRanges.size();
856 for (const auto& rTab : rMark)
858 for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
860 const ScRange& rRange = rDestRanges[i];
861 // tdf#158110 - check if just the ADDNOTES flag is present without any other content
862 if ((nFlags & InsertDeleteFlags::ADDNOTES) == InsertDeleteFlags::ADDNOTES
863 && (nFlags & (InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE))
864 == InsertDeleteFlags::NONE)
865 bIsEmpty = rDoc.IsNotesBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
866 rRange.aEnd.Col(), rRange.aEnd.Row(), rTab);
867 else
868 bIsEmpty = rDoc.IsBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
869 rRange.aEnd.Col(), rRange.aEnd.Row(), rTab);
871 if (!bIsEmpty)
872 break;
875 if (!bIsEmpty)
877 ScReplaceWarnBox aBox(pParentWnd);
878 if (aBox.run() != RET_YES)
880 // changing the configuration is within the ScReplaceWarnBox
881 return false;
884 return true;
889 bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
890 ScPasteFunc nFunction, bool bSkipEmptyCells,
891 bool bTranspose, bool bAsLink,
892 InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
893 bool bAllowDialogs )
895 if (!pClipDoc)
897 OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
898 return false;
901 if (GetViewData().SelectionForbidsPaste(pClipDoc))
902 return false;
904 // undo: save all or no content
905 InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE;
906 if (nFlags & InsertDeleteFlags::CONTENTS)
907 nContFlags |= InsertDeleteFlags::CONTENTS;
908 if (nFlags & InsertDeleteFlags::ATTRIB)
909 nContFlags |= InsertDeleteFlags::ATTRIB;
910 // move attributes to undo without copying them from clip to doc
911 InsertDeleteFlags nUndoFlags = nContFlags;
912 if (nUndoExtraFlags & InsertDeleteFlags::ATTRIB)
913 nUndoFlags |= InsertDeleteFlags::ATTRIB;
914 // do not copy note captions into undo document
915 nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
917 ScClipParam& rClipParam = pClipDoc->GetClipParam();
918 if (rClipParam.isMultiRange())
920 // Source data is multi-range.
921 return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose,
922 bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
925 ScMarkData& rMark = GetViewData().GetMarkData();
926 if (rMark.IsMultiMarked())
928 // Source data is single-range but destination is multi-range.
929 return PasteFromClipToMultiRanges(
930 nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
931 eMoveMode, nUndoFlags);
934 bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc
935 bool bIncludeFiltered = bCutMode;
937 // paste drawing: also if InsertDeleteFlags::NOTE is set (to create drawing layer for note captions)
938 bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (InsertDeleteFlags::OBJECTS|InsertDeleteFlags::NOTE) ) );
940 ScDocShellRef aTransShellRef; // for objects in xTransClip - must remain valid as long as xTransClip
941 ScDocument* pOrigClipDoc = nullptr;
942 ScDocumentUniquePtr xTransClip;
943 if ( bTranspose )
945 SCCOL nX;
946 SCROW nY;
947 // include filtered rows until TransposeClip can skip them
948 pClipDoc->GetClipArea( nX, nY, true );
949 if ( nY > static_cast<sal_Int32>(pClipDoc->MaxCol()) ) // too many lines for transpose
951 ErrorMessage(STR_PASTE_FULL);
952 return false;
954 pOrigClipDoc = pClipDoc; // refs
956 if ( bPasteDraw )
958 aTransShellRef = new ScDocShell; // DocShell needs a Ref immediately
959 aTransShellRef->DoInitNew();
961 ScDrawLayer::SetGlobalDrawPersist( aTransShellRef.get() );
963 xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
964 pClipDoc->TransposeClip(xTransClip.get(), nFlags, bAsLink, bIncludeFiltered);
965 pClipDoc = xTransClip.get();
967 ScDrawLayer::SetGlobalDrawPersist(nullptr);
970 // TODO: position this call better for performance.
971 ResetAutoSpellForContentChange();
973 SCCOL nStartCol;
974 SCROW nStartRow;
975 SCTAB nStartTab;
976 SCCOL nEndCol;
977 SCROW nEndRow;
978 SCTAB nEndTab;
979 SCCOL nClipSizeX;
980 SCROW nClipSizeY;
981 pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, true ); // size in clipboard doc
983 // size in target doc: include filtered rows only if CutMode is set
984 SCCOL nDestSizeX;
985 SCROW nDestSizeY;
986 pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
988 ScDocument& rDoc = GetViewData().GetDocument();
989 ScDocShell* pDocSh = GetViewData().GetDocShell();
990 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
991 const bool bRecord(rDoc.IsUndoEnabled());
993 ScDocShellModificator aModificator( *pDocSh );
995 ScRange aMarkRange;
996 ScMarkData aFilteredMark( rMark); // local copy for all modifications
997 ScMarkType eMarkType = GetViewData().GetSimpleArea( aMarkRange, aFilteredMark);
998 bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
999 bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
1000 (bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));
1002 if (!bNoPaste)
1004 if (!rMark.IsMarked())
1006 // Create a selection with clipboard row count and check that for
1007 // filtered.
1008 nStartCol = GetViewData().GetCurX();
1009 nStartRow = GetViewData().GetCurY();
1010 nStartTab = GetViewData().GetTabNo();
1011 nEndCol = nStartCol + nDestSizeX;
1012 nEndRow = nStartRow + nDestSizeY;
1013 nEndTab = nStartTab;
1014 aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1015 if (ScViewUtil::HasFiltered(aMarkRange, rDoc))
1017 bMarkIsFiltered = true;
1018 // Fit to clipboard's row count unfiltered rows. If there is no
1019 // fit assume that pasting is not possible. Note that nDestSizeY is
1020 // size-1 (difference).
1021 if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1022 bNoPaste = true;
1024 aFilteredMark.SetMarkArea( aMarkRange);
1026 else
1028 // Expand the marked area when the destination area is larger than the
1029 // current selection, to get the undo do the right thing. (i#106711)
1030 ScRange aRange = aFilteredMark.GetMarkArea();
1031 if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
1033 aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
1034 aFilteredMark.SetMarkArea(aRange);
1039 if (bNoPaste)
1041 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1042 return false;
1045 SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
1046 ScRangeList aRangeList;
1047 if (bMarkIsFiltered)
1049 ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1050 aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
1051 nUnfilteredRows = 0;
1052 size_t ListSize = aRangeList.size();
1053 for ( size_t i = 0; i < ListSize; ++i )
1055 ScRange & r = aRangeList[i];
1056 nUnfilteredRows += r.aEnd.Row() - r.aStart.Row() + 1;
1058 #if 0
1059 /* This isn't needed but could be a desired restriction. */
1060 // For filtered, destination rows have to be an exact multiple of
1061 // source rows. Note that nDestSizeY is size-1 (difference), so
1062 // nDestSizeY==0 fits always.
1063 if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
1065 /* FIXME: this should be a more descriptive error message then. */
1066 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1067 return false;
1069 #endif
1072 // Also for a filtered selection the area is used, for undo et al.
1073 if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
1075 aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1076 SCCOL nBlockAddX = nEndCol-nStartCol;
1077 SCROW nBlockAddY = nEndRow-nStartRow;
1079 // request, if the selection is greater than one row/column, but smaller
1080 // as the Clipboard (then inserting is done beyond the selection)
1082 // ClipSize is not size, but difference
1083 if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
1084 ( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
1085 ( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
1087 ScWaitCursorOff aWaitOff( GetFrameWin() );
1088 OUString aMessage = ScResId( STR_PASTE_BIGGER );
1090 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
1091 VclMessageType::Question, VclButtonsType::YesNo,
1092 aMessage));
1093 xQueryBox->set_default_response(RET_NO);
1094 if (xQueryBox->run() != RET_YES)
1096 return false;
1100 if (nBlockAddX <= nDestSizeX)
1101 nEndCol = nStartCol + nDestSizeX;
1103 if (nBlockAddY <= nDestSizeY)
1105 nEndRow = nStartRow + nDestSizeY;
1106 if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
1108 // Same as above if nothing was marked: re-fit selection to
1109 // unfiltered rows. Extending the selection actually may
1110 // introduce filtered rows where there weren't any before, so
1111 // we also need to test for that.
1112 aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1113 if (bMarkIsFiltered || ScViewUtil::HasFiltered(aMarkRange, rDoc))
1115 bMarkIsFiltered = true;
1116 // Worst case: all rows up to the end of the sheet are filtered.
1117 if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
1119 ErrorMessage(STR_PASTE_FULL);
1120 return false;
1123 aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
1124 aFilteredMark.SetMarkArea( aMarkRange);
1125 if (bMarkIsFiltered)
1127 ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
1128 aFilteredMark.FillRangeListWithMarks( &aRangeList, true);
1133 else
1135 nStartCol = GetViewData().GetCurX();
1136 nStartRow = GetViewData().GetCurY();
1137 nStartTab = GetViewData().GetTabNo();
1138 nEndCol = nStartCol + nDestSizeX;
1139 nEndRow = nStartRow + nDestSizeY;
1140 nEndTab = nStartTab;
1143 bool bOffLimits = !rDoc.ValidCol(nEndCol) || !rDoc.ValidRow(nEndRow);
1145 // target-range, as displayed:
1146 ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
1148 // should lines be inserted?
1149 // ( too large nEndCol/nEndRow are detected below)
1150 bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
1151 if ( bInsertCells )
1153 // Instead of EnterListAction, the paste undo action is merged into the
1154 // insert action, so Repeat can insert the right cells
1156 MarkRange( aUserRange ); // set through CopyFromClip
1158 // CutMode is reset on insertion of cols/rows but needed again on cell move
1159 bool bCut = pClipDoc->IsCutMode();
1160 if (!InsertCells( eMoveMode, bRecord, true )) // is inserting possible?
1162 return false;
1163 // #i21036# EnterListAction isn't used, and InsertCells doesn't insert
1164 // its undo action on failure, so no undo handling is needed here
1166 if ( bCut )
1167 pClipDoc->SetCutMode( bCut );
1169 else if (!bOffLimits)
1171 bool bAskIfNotEmpty = bAllowDialogs &&
1172 ( nFlags & InsertDeleteFlags::CONTENTS ) &&
1173 nFunction == ScPasteFunc::NONE &&
1174 SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1175 if ( bAskIfNotEmpty )
1177 ScRangeList aTestRanges(aUserRange);
1178 if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aFilteredMark, GetViewData().GetDialogParent()))
1179 return false;
1183 SCCOL nClipStartX; // enlarge clipboard-range
1184 SCROW nClipStartY;
1185 pClipDoc->GetClipStart( nClipStartX, nClipStartY );
1186 SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
1187 SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document
1188 bool bClipOver = false;
1189 // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
1190 // The same end column/row can be used for all calls because the clip doc doesn't contain
1191 // content outside the clip area.
1192 for (SCTAB nClipTab=0; nClipTab < pClipDoc->GetTableCount(); nClipTab++)
1193 if ( pClipDoc->HasTable(nClipTab) )
1194 if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab ) )
1195 bClipOver = true;
1196 nUndoEndCol -= nClipStartX + nClipSizeX;
1197 nUndoEndRow -= nClipStartY + nClipSizeY; // now contains only the difference added by ExtendMerge
1198 nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
1199 nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
1201 if (nUndoEndCol>pClipDoc->MaxCol() || nUndoEndRow>pClipDoc->MaxRow())
1203 ErrorMessage(STR_PASTE_FULL);
1204 return false;
1207 rDoc.ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark );
1209 // check cell-protection
1211 ScEditableTester aTester( rDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
1212 if (!aTester.IsEditable())
1214 ErrorMessage(aTester.GetMessageId());
1215 return false;
1218 //! check overlapping
1219 //! just check truly intersection !!!!!!!
1221 ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
1222 if ( bRecord )
1224 OUString aUndo = ScResId( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
1225 pUndoMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
1228 if (bClipOver)
1229 if (lcl_SelHasAttrib( rDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HasAttrFlags::Overlapped ))
1230 { // "Cell merge not possible if cells already merged"
1231 ScDocAttrIterator aIter( rDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
1232 const ScPatternAttr* pPattern = nullptr;
1233 SCCOL nCol = -1;
1234 SCROW nRow1 = -1;
1235 SCROW nRow2 = -1;
1236 while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != nullptr )
1238 const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
1239 const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
1240 if (rMergeFlag.IsMerged() || rMergeFlagAttr.IsOverlapped())
1242 ScRange aRange(nCol, nRow1, nStartTab);
1243 rDoc.ExtendOverlapped(aRange);
1244 rDoc.ExtendMerge(aRange, true);
1245 rDocFunc.UnmergeCells(aRange, bRecord, nullptr /*TODO: should pass combined UndoDoc if bRecord*/);
1250 if ( !bCutMode )
1252 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1253 if ( pChangeTrack )
1254 pChangeTrack->ResetLastCut(); // no more cut-mode
1257 bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
1258 bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
1260 ScDocumentUniquePtr pUndoDoc;
1261 std::unique_ptr<ScDocument> pRefUndoDoc;
1262 std::unique_ptr<ScRefUndoData> pUndoData;
1264 if ( bRecord )
1266 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1267 pUndoDoc->InitUndoSelected( rDoc, aFilteredMark, bColInfo, bRowInfo );
1269 // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
1270 SCTAB nTabCount = rDoc.GetTableCount();
1271 rDoc.CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
1272 nUndoFlags, false, *pUndoDoc );
1274 if ( bCutMode )
1276 pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1277 pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
1279 pUndoData.reset(new ScRefUndoData( &rDoc ));
1283 const bool bSingleCellBefore = nStartCol == nEndCol &&
1284 nStartRow == nEndRow &&
1285 nStartTab == nEndTab;
1286 tools::Long nBeforeHint(bSingleCellBefore ? pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)) : -1);
1288 sal_uInt16 nExtFlags = 0;
1289 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1290 nEndCol, nEndRow, nEndTab ); // content before the change
1292 if (GetViewData().IsActive())
1294 DoneBlockMode();
1295 InitOwnBlockMode( aUserRange );
1297 rMark.SetMarkArea( aUserRange );
1298 MarkDataChanged();
1300 // copy from clipboard
1301 // save original data in case of calculation
1303 ScDocumentUniquePtr pMixDoc;
1304 if (nFunction != ScPasteFunc::NONE)
1306 bSkipEmptyCells = false;
1307 if ( nFlags & InsertDeleteFlags::CONTENTS )
1309 pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1310 pMixDoc->InitUndo( rDoc, nStartTab, nEndTab );
1311 rDoc.CopyToDocument(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
1312 InsertDeleteFlags::CONTENTS, false, *pMixDoc);
1316 /* Make draw layer and start drawing undo.
1317 - Needed before AdjustBlockHeight to track moved drawing objects.
1318 - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1320 if ( bPasteDraw )
1321 pDocSh->MakeDrawLayer();
1322 if ( bRecord )
1323 rDoc.BeginDrawUndo();
1325 InsertDeleteFlags nNoObjFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1326 if (!bAsLink)
1328 // copy normally (original range)
1329 rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
1330 pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
1331 bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );
1333 // adapt refs manually in case of transpose
1334 if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
1335 rDoc.UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc.get() );
1337 else if (!bTranspose)
1339 // copy with bAsLink=TRUE
1340 rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
1341 true, true, bIncludeFiltered, bSkipEmptyCells );
1343 else
1345 // copy all content (TransClipDoc contains only formula)
1346 rDoc.CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc.get(), pClipDoc );
1349 // skipped rows and merged cells don't mix
1350 if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1351 rDocFunc.UnmergeCells( aUserRange, false, nullptr );
1353 rDoc.ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true ); // refresh
1354 // new range
1356 if ( pMixDoc ) // calculate with original data?
1358 rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
1360 pMixDoc.reset();
1362 AdjustBlockHeight(); // update row heights before pasting objects
1364 ::std::vector< OUString > aExcludedChartNames;
1365 SdrPage* pPage = nullptr;
1367 if ( nFlags & InsertDeleteFlags::OBJECTS )
1369 ScDrawView* pScDrawView = GetScDrawView();
1370 SdrModel* pModel = ( pScDrawView ? &pScDrawView->GetModel() : nullptr );
1371 pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : nullptr );
1372 if ( pPage )
1374 ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
1377 // Paste the drawing objects after the row heights have been updated.
1379 rDoc.CopyFromClip( aUserRange, aFilteredMark, InsertDeleteFlags::OBJECTS, pRefUndoDoc.get(), pClipDoc,
1380 true, false, bIncludeFiltered );
1383 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
1384 nEndCol, nEndRow, nEndTab ); // content after the change
1386 // if necessary, delete autofilter-heads
1387 if (bCutMode)
1388 if (rDoc.RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
1389 nClipStartY+nClipSizeY, nStartTab ))
1391 pDocSh->PostPaint(
1392 ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
1393 PaintPartFlags::Grid );
1396 //! remove block-range on RefUndoDoc !!!
1398 if ( bRecord )
1400 ScDocumentUniquePtr pRedoDoc;
1401 // copy redo data after appearance of the first undo
1402 // don't create Redo-Doc without RefUndoDoc
1404 if (pRefUndoDoc)
1406 pRedoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1407 pRedoDoc->InitUndo( rDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
1409 // move adapted refs to Redo-Doc
1411 SCTAB nTabCount = rDoc.GetTableCount();
1412 pRedoDoc->AddUndoTab( 0, nTabCount-1 );
1413 rDoc.CopyUpdated( pRefUndoDoc.get(), pRedoDoc.get() );
1415 // move old refs to Undo-Doc
1417 // not charts?
1418 pUndoDoc->AddUndoTab( 0, nTabCount-1 );
1419 pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, InsertDeleteFlags::ALL );
1420 pRefUndoDoc->CopyToDocument( 0,0,0, pUndoDoc->MaxCol(), pUndoDoc->MaxRow(), nTabCount-1,
1421 InsertDeleteFlags::FORMULA, false, *pUndoDoc );
1422 pRefUndoDoc.reset();
1425 // DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
1426 // UndoData for redo is made during first undo
1428 ScUndoPasteOptions aOptions; // store options for repeat
1429 aOptions.nFunction = nFunction;
1430 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1431 aOptions.bTranspose = bTranspose;
1432 aOptions.bAsLink = bAsLink;
1433 aOptions.eMoveMode = eMoveMode;
1435 std::unique_ptr<SfxUndoAction> pUndo(new ScUndoPaste(
1436 pDocSh, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1437 aFilteredMark, std::move(pUndoDoc), std::move(pRedoDoc), nFlags | nUndoFlags, std::move(pUndoData),
1438 false, &aOptions )); // false = Redo data not yet copied
1440 if ( bInsertCells )
1442 // Merge the paste undo action into the insert action.
1443 // Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
1445 pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
1447 else
1448 pUndoMgr->AddUndoAction( std::move(pUndo) );
1449 pUndoMgr->LeaveListAction();
1452 PaintPartFlags nPaint = PaintPartFlags::Grid;
1453 if (bColInfo)
1455 nPaint |= PaintPartFlags::Top;
1456 nUndoEndCol = rDoc.MaxCol(); // just for drawing !
1458 if (bRowInfo)
1460 nPaint |= PaintPartFlags::Left;
1461 nUndoEndRow = rDoc.MaxRow(); // just for drawing !
1464 tools::Long nMaxWidthAffectedHint = -1;
1465 const bool bSingleCellAfter = nStartCol == nUndoEndCol &&
1466 nStartRow == nUndoEndRow &&
1467 nStartTab == nEndTab;
1468 if (bSingleCellBefore && bSingleCellAfter)
1470 tools::Long nAfterHint(pDocSh->GetTwipWidthHint(ScAddress(nStartCol, nStartRow, nStartTab)));
1471 nMaxWidthAffectedHint = std::max(nBeforeHint, nAfterHint);
1474 pDocSh->PostPaint(
1475 ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
1476 nPaint, nExtFlags, nMaxWidthAffectedHint);
1477 // AdjustBlockHeight has already been called above
1479 aModificator.SetDocumentModified();
1480 PostPasteFromClip(aUserRange, rMark);
1482 if ( nFlags & InsertDeleteFlags::OBJECTS )
1484 ScModelObj* pModelObj = pDocSh->GetModel();
1485 if ( pPage && pModelObj )
1487 bool bSameDoc = ( rClipParam.getSourceDocID() == rDoc.GetDocumentID() );
1488 const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
1489 ScChartHelper::CreateProtectedChartListenersAndNotify( rDoc, pPage, pModelObj, nStartTab,
1490 rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
1493 OUString aStartAddress = aMarkRange.aStart.GetColRowString();
1494 OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
1495 collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, u"PASTE"_ustr);
1496 return true;
1499 bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
1500 ScPasteFunc nFunction, bool bSkipEmptyCells,
1501 bool bTranspose, bool bAsLink,
1502 bool bAllowDialogs, InsCellCmd eMoveMode,
1503 InsertDeleteFlags nUndoFlags)
1505 ScViewData& rViewData = GetViewData();
1506 ScDocument& rDoc = rViewData.GetDocument();
1507 ScDocShell* pDocSh = rViewData.GetDocShell();
1508 ScMarkData aMark(rViewData.GetMarkData());
1509 const ScAddress& rCurPos = rViewData.GetCurPos();
1510 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1511 SCCOL nColSize = rClipParam.getPasteColSize();
1512 SCROW nRowSize = rClipParam.getPasteRowSize(*pClipDoc, /*bIncludeFiltered*/false);
1514 if (bTranspose)
1516 if (static_cast<SCROW>(rCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(pClipDoc->MaxCol()))
1518 ErrorMessage(STR_PASTE_FULL);
1519 return false;
1522 ScDocumentUniquePtr pTransClip(new ScDocument(SCDOCMODE_CLIP));
1523 pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink, /*bIncludeFiltered*/false);
1524 pClipDoc = pTransClip.release();
1525 SCCOL nTempColSize = nColSize;
1526 nColSize = static_cast<SCCOL>(nRowSize);
1527 nRowSize = static_cast<SCROW>(nTempColSize);
1530 if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
1532 ErrorMessage(STR_PASTE_FULL);
1533 return false;
1536 // Determine the first and last selected sheet numbers.
1537 SCTAB nTab1 = aMark.GetFirstSelected();
1538 SCTAB nTab2 = aMark.GetLastSelected();
1540 ScDocShellModificator aModificator(*pDocSh);
1542 // For multi-selection paste, we don't support cell duplication for larger
1543 // destination range. In case the destination is marked, we reset it to
1544 // the clip size.
1545 ScRange aMarkedRange(rCurPos.Col(), rCurPos.Row(), nTab1,
1546 rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, nTab2);
1548 // Extend the marked range to account for filtered rows in the destination
1549 // area.
1550 if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
1552 if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize))
1553 return false;
1556 bool bAskIfNotEmpty =
1557 bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1558 nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1560 if (bAskIfNotEmpty)
1562 ScRangeList aTestRanges(aMarkedRange);
1563 if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1564 return false;
1567 aMark.SetMarkArea(aMarkedRange);
1568 MarkRange(aMarkedRange);
1570 bool bInsertCells = (eMoveMode != INS_NONE);
1571 if (bInsertCells)
1573 if (!InsertCells(eMoveMode, rDoc.IsUndoEnabled(), true))
1574 return false;
1577 // TODO: position this call better for performance.
1578 ResetAutoSpellForContentChange();
1580 bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
1581 ScDocumentUniquePtr pUndoDoc;
1582 if (rDoc.IsUndoEnabled())
1584 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1585 pUndoDoc->InitUndoSelected(rDoc, aMark, false, bRowInfo);
1586 rDoc.CopyToDocument(aMarkedRange, nUndoFlags, false, *pUndoDoc, &aMark);
1589 ScDocumentUniquePtr pMixDoc;
1590 if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1592 if ( nFlags & InsertDeleteFlags::CONTENTS )
1594 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1595 pMixDoc->InitUndoSelected(rDoc, aMark);
1596 rDoc.CopyToDocument(aMarkedRange, InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1600 /* Make draw layer and start drawing undo.
1601 - Needed before AdjustBlockHeight to track moved drawing objects.
1602 - Needed before rDoc.CopyFromClip to track inserted note caption objects.
1604 if (nFlags & InsertDeleteFlags::OBJECTS)
1605 pDocSh->MakeDrawLayer();
1606 if (rDoc.IsUndoEnabled())
1607 rDoc.BeginDrawUndo();
1609 InsertDeleteFlags nCopyFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
1610 // in case of transpose, links were added in TransposeClip()
1611 if (bAsLink && bTranspose)
1612 nCopyFlags |= InsertDeleteFlags::FORMULA;
1613 rDoc.CopyMultiRangeFromClip(rCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
1614 /*bIncludeFiltered*/false, bSkipEmptyCells);
1616 if (pMixDoc)
1617 rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);
1619 AdjustBlockHeight(); // update row heights before pasting objects
1621 if (nFlags & InsertDeleteFlags::OBJECTS)
1623 // Paste the drawing objects after the row heights have been updated.
1624 rDoc.CopyMultiRangeFromClip(rCurPos, aMark, InsertDeleteFlags::OBJECTS, pClipDoc, true,
1625 false, /*bIncludeFiltered*/false, true);
1628 if (bRowInfo)
1629 pDocSh->PostPaint(aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nTab1, PaintPartFlags::Grid|PaintPartFlags::Left);
1630 else
1632 ScRange aTmp = aMarkedRange;
1633 aTmp.aStart.SetTab(nTab1);
1634 aTmp.aEnd.SetTab(nTab1);
1635 pDocSh->PostPaint(aTmp, PaintPartFlags::Grid);
1638 if (rDoc.IsUndoEnabled())
1640 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1641 OUString aUndo = ScResId(
1642 pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1643 pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1645 ScUndoPasteOptions aOptions; // store options for repeat
1646 aOptions.nFunction = nFunction;
1647 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1648 aOptions.bTranspose = bTranspose;
1649 aOptions.bAsLink = bAsLink;
1650 aOptions.eMoveMode = eMoveMode;
1652 std::unique_ptr<ScUndoPaste> pUndo(new ScUndoPaste(pDocSh,
1653 aMarkedRange, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1655 if (bInsertCells)
1656 pUndoMgr->AddUndoAction(std::make_unique<ScUndoWrapper>(std::move(pUndo)), true);
1657 else
1658 pUndoMgr->AddUndoAction(std::move(pUndo));
1660 pUndoMgr->LeaveListAction();
1663 aModificator.SetDocumentModified();
1664 PostPasteFromClip(aMarkedRange, aMark);
1665 return true;
1668 bool ScViewFunc::PasteFromClipToMultiRanges(
1669 InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
1670 bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
1671 InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
1673 if (bTranspose)
1675 // We don't allow transpose for this yet.
1676 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1677 return false;
1680 if (eMoveMode != INS_NONE)
1682 // We don't allow insertion mode either. Too complicated.
1683 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1684 return false;
1687 ScViewData& rViewData = GetViewData();
1688 ScClipParam& rClipParam = pClipDoc->GetClipParam();
1689 if (rClipParam.mbCutMode)
1691 // No cut and paste with this, please.
1692 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1693 return false;
1696 const ScAddress& rCurPos = rViewData.GetCurPos();
1697 ScDocument& rDoc = rViewData.GetDocument();
1699 ScRange aSrcRange = rClipParam.getWholeRange();
1700 SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
1701 SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
1703 if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
1705 ErrorMessage(STR_PASTE_FULL);
1706 return false;
1709 ScMarkData aMark(rViewData.GetMarkData());
1711 ScRangeList aRanges;
1712 aMark.MarkToSimple();
1713 aMark.FillRangeListWithMarks(&aRanges, false);
1714 if (!ScClipUtil::CheckDestRanges(rDoc, nColSize, nRowSize, aMark, aRanges))
1716 ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
1717 return false;
1720 ScDocShell* pDocSh = rViewData.GetDocShell();
1722 ScDocShellModificator aModificator(*pDocSh);
1724 bool bAskIfNotEmpty =
1725 bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
1726 nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
1728 if (bAskIfNotEmpty)
1730 if (!checkDestRangeForOverwrite(nFlags, aRanges, rDoc, aMark, GetViewData().GetDialogParent()))
1731 return false;
1734 // TODO: position this call better for performance.
1735 ResetAutoSpellForContentChange();
1737 ScDocumentUniquePtr pUndoDoc;
1738 if (rDoc.IsUndoEnabled())
1740 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1741 pUndoDoc->InitUndoSelected(rDoc, aMark);
1742 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1744 rDoc.CopyToDocument(
1745 aRanges[i], nUndoFlags, false, *pUndoDoc, &aMark);
1749 ScDocumentUniquePtr pMixDoc;
1750 if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
1752 if (nFlags & InsertDeleteFlags::CONTENTS)
1754 pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1755 pMixDoc->InitUndoSelected(rDoc, aMark);
1756 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1758 rDoc.CopyToDocument(
1759 aRanges[i], InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
1764 if (nFlags & InsertDeleteFlags::OBJECTS)
1765 pDocSh->MakeDrawLayer();
1766 if (rDoc.IsUndoEnabled())
1767 rDoc.BeginDrawUndo();
1769 // First, paste everything but the drawing objects.
1770 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1772 rDoc.CopyFromClip(
1773 aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
1774 false, false, true, bSkipEmptyCells);
1777 if (pMixDoc)
1779 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1780 rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
1783 AdjustBlockHeight(); // update row heights before pasting objects
1785 // Then paste the objects.
1786 if (nFlags & InsertDeleteFlags::OBJECTS)
1788 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
1790 rDoc.CopyFromClip(
1791 aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
1792 false, false, true, bSkipEmptyCells);
1796 // Refresh the range that includes all pasted ranges. We only need to
1797 // refresh the current sheet.
1798 PaintPartFlags nPaint = PaintPartFlags::Grid;
1799 bool bRowInfo = (aSrcRange.aStart.Col()==0 && aSrcRange.aEnd.Col()==pClipDoc->MaxCol());
1800 if (bRowInfo)
1801 nPaint |= PaintPartFlags::Left;
1802 pDocSh->PostPaint(aRanges, nPaint);
1804 if (rDoc.IsUndoEnabled())
1806 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1807 OUString aUndo = ScResId(
1808 pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
1809 pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
1811 ScUndoPasteOptions aOptions; // store options for repeat
1812 aOptions.nFunction = nFunction;
1813 aOptions.bSkipEmptyCells = bSkipEmptyCells;
1814 aOptions.bTranspose = bTranspose;
1815 aOptions.bAsLink = bAsLink;
1816 aOptions.eMoveMode = eMoveMode;
1819 pUndoMgr->AddUndoAction(
1820 std::make_unique<ScUndoPaste>(
1821 pDocSh, aRanges, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
1822 pUndoMgr->LeaveListAction();
1825 aModificator.SetDocumentModified();
1826 PostPasteFromClip(aRanges, aMark);
1828 return false;
1831 void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
1833 ScViewData& rViewData = GetViewData();
1834 ScDocShell* pDocSh = rViewData.GetDocShell();
1835 pDocSh->UpdateOle(rViewData);
1837 SelectionChanged(true);
1839 ScModelObj* pModelObj = pDocSh->GetModel();
1841 ScRangeList aChangeRanges;
1842 for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
1844 const ScRange& r = rPasteRanges[i];
1845 for (const auto& rTab : rMark)
1847 ScRange aChangeRange(r);
1848 aChangeRange.aStart.SetTab(rTab);
1849 aChangeRange.aEnd.SetTab(rTab);
1850 aChangeRanges.push_back(aChangeRange);
1854 if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj))
1855 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"paste"_ustr);
1856 else if (pModelObj)
1857 HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, u"data-area-invalidate"_ustr);
1860 // D R A G A N D D R O P
1862 // inside the doc
1864 bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
1865 bool bCut )
1867 ScDocShell* pDocSh = GetViewData().GetDocShell();
1868 HideAllCursors();
1870 ResetAutoSpellForContentChange();
1872 bool bSuccess = true;
1873 SCTAB nDestTab = rDestPos.Tab();
1874 const ScMarkData& rMark = GetViewData().GetMarkData();
1875 if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
1877 // moving within one table and several tables selected -> apply to all selected tables
1879 OUString aUndo = ScResId( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
1880 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
1882 // collect ranges of consecutive selected tables
1884 ScRange aLocalSource = rSource;
1885 ScAddress aLocalDest = rDestPos;
1886 SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
1887 SCTAB nStartTab = 0;
1888 while ( nStartTab < nTabCount && bSuccess )
1890 while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
1891 ++nStartTab;
1892 if ( nStartTab < nTabCount )
1894 SCTAB nEndTab = nStartTab;
1895 while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
1896 ++nEndTab;
1898 aLocalSource.aStart.SetTab( nStartTab );
1899 aLocalSource.aEnd.SetTab( nEndTab );
1900 aLocalDest.SetTab( nStartTab );
1902 bSuccess = pDocSh->GetDocFunc().MoveBlock(
1903 aLocalSource, aLocalDest, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
1905 nStartTab = nEndTab + 1;
1909 pDocSh->GetUndoManager()->LeaveListAction();
1911 else
1913 // move the block as specified
1914 bSuccess = pDocSh->GetDocFunc().MoveBlock(
1915 rSource, rDestPos, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
1918 ShowAllCursors();
1919 if (bSuccess)
1921 // mark destination range
1922 ScAddress aDestEnd(
1923 rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
1924 rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
1925 nDestTab );
1927 bool bIncludeFiltered = bCut;
1928 if ( !bIncludeFiltered )
1930 // find number of non-filtered rows
1931 SCROW nPastedCount = pDocSh->GetDocument().CountNonFilteredRows(
1932 rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
1934 if ( nPastedCount == 0 )
1935 nPastedCount = 1;
1936 aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
1939 MarkRange( ScRange( rDestPos, aDestEnd ), false ); //! sal_False ???
1941 pDocSh->UpdateOle(GetViewData());
1942 SelectionChanged();
1944 return bSuccess;
1947 // link inside the doc
1949 bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos )
1951 // check overlapping
1953 if ( rSource.aStart.Tab() == rDestPos.Tab() )
1955 SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
1956 SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
1958 if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
1959 rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
1961 return false;
1965 // run with paste
1967 ScDocument& rDoc = GetViewData().GetDocument();
1968 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1969 rDoc.CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
1970 rSource.aEnd.Col(), rSource.aEnd.Row(),
1971 rSource.aStart.Tab(), pClipDoc.get() );
1973 // mark destination area (set cursor, no marks)
1975 if ( GetViewData().GetTabNo() != rDestPos.Tab() )
1976 SetTabNo( rDestPos.Tab() );
1978 MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
1980 // Paste
1982 PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(), ScPasteFunc::NONE, false, false, true ); // as a link
1984 return true;
1987 void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
1988 SCROW nStartRow , SCCOL nStartCol ,
1989 SCROW nEndRow , SCCOL nEndCol ,
1990 std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
1991 sal_uInt16 aColLength )
1993 ScDocument& rDoc = GetViewData().GetDocument();
1994 ScDocShell* pDocSh = GetViewData().GetDocShell();
1995 ScMarkData& rMark = GetViewData().GetMarkData();
1996 ScDocShellModificator aModificator( *pDocSh );
1997 SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
1999 const bool bRecord( rDoc.IsUndoEnabled());
2000 ScDocumentUniquePtr pUndoDoc;
2001 ScDocumentUniquePtr pRedoDoc;
2002 std::unique_ptr<ScRefUndoData> pUndoData;
2003 SCTAB nTab = GetViewData().GetTabNo();
2004 SCTAB nStartTab = nTab;
2005 SCTAB nEndTab = nTab;
2008 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2009 if ( pChangeTrack )
2010 pChangeTrack->ResetLastCut(); // no more cut-mode
2012 ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
2013 bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
2014 bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
2015 SCCOL nUndoEndCol = nStartCol+aColLength-1;
2016 SCROW nUndoEndRow = nCurrentRow;
2018 if ( bRecord )
2020 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2021 pUndoDoc->InitUndoSelected( rDoc , rMark , bColInfo , bRowInfo );
2022 rDoc.CopyToDocument( aUserRange , InsertDeleteFlags::VALUE , false, *pUndoDoc );
2024 sal_uInt16 nExtFlags = 0;
2025 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
2026 rDoc.BeginDrawUndo();
2028 for(sal_uInt16 i = 0; i < aColLength; i++)
2030 if (rEdits[i] != nullptr)
2032 OUString aFieldName = rEdits[i]->m_xEdit->get_text();
2033 rDoc.SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
2036 pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab ); // content after the change
2037 std::unique_ptr<SfxUndoAction> pUndo( new ScUndoDataForm( pDocSh,
2038 nStartCol, nCurrentRow, nStartTab,
2039 nUndoEndCol, nUndoEndRow, nEndTab, rMark,
2040 std::move(pUndoDoc), std::move(pRedoDoc),
2041 std::move(pUndoData) ) );
2042 pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
2044 PaintPartFlags nPaint = PaintPartFlags::Grid;
2045 if (bColInfo)
2047 nPaint |= PaintPartFlags::Top;
2048 nUndoEndCol = rDoc.MaxCol(); // just for drawing !
2050 if (bRowInfo)
2052 nPaint |= PaintPartFlags::Left;
2053 nUndoEndRow = rDoc.MaxRow(); // just for drawing !
2056 pDocSh->PostPaint(
2057 ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
2058 nPaint, nExtFlags);
2059 pDocSh->UpdateOle(GetViewData());
2062 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */