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