android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / frmedt / fecopy.cxx
blobd0be7aa0d5155d7a919f1d1809d4f3b9142d22ef
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 <memory>
21 #include <hintids.hxx>
23 #include <vcl/graph.hxx>
24 #include <sot/formats.hxx>
25 #include <svx/xfillit0.hxx>
26 #include <svx/svdocapt.hxx>
27 #include <svx/svdouno.hxx>
28 #include <svx/xbtmpit.hxx>
29 #include <svx/svdpage.hxx>
30 #include <svx/svdogrp.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <svx/fmmodel.hxx>
33 #include <svx/unomodel.hxx>
34 #include <svx/svditer.hxx>
35 #include <svx/svdograf.hxx>
36 #include <tools/stream.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <osl/diagnose.h>
39 #include <fmtanchr.hxx>
40 #include <fmtcntnt.hxx>
41 #include <fmtornt.hxx>
42 #include <fmtflcnt.hxx>
43 #include <frmfmt.hxx>
44 #include <txtfrm.hxx>
45 #include <txtflcnt.hxx>
46 #include <fesh.hxx>
47 #include <doc.hxx>
48 #include <IDocumentUndoRedo.hxx>
49 #include <IDocumentDrawModelAccess.hxx>
50 #include <IDocumentRedlineAccess.hxx>
51 #include <DocumentFieldsManager.hxx>
52 #include <IDocumentLayoutAccess.hxx>
53 #include <rootfrm.hxx>
54 #include <ndtxt.hxx>
55 #include <pam.hxx>
56 #include <tblsel.hxx>
57 #include <swtable.hxx>
58 #include <flyfrm.hxx>
59 #include <pagefrm.hxx>
60 #include <fldbas.hxx>
61 #include <swundo.hxx>
62 #include <viewimp.hxx>
63 #include <dview.hxx>
64 #include <dcontact.hxx>
65 #include <dflyobj.hxx>
66 #include <docsh.hxx>
67 #include <pagedesc.hxx>
68 #include <mvsave.hxx>
69 #include <textboxhelper.hxx>
70 #include <frameformats.hxx>
71 #include <vcl/virdev.hxx>
72 #include <svx/svdundo.hxx>
74 using namespace ::com::sun::star;
76 // Copy for the internal clipboard. Copies all selections to the clipboard.
77 void SwFEShell::Copy( SwDoc& rClpDoc, const OUString* pNewClpText )
79 rClpDoc.GetIDocumentUndoRedo().DoUndo(false); // always false!
81 // delete content if ClpDocument contains content
82 SwNodeIndex aSttIdx( rClpDoc.GetNodes().GetEndOfExtras(), 2 );
83 SwNodeIndex aEndNdIdx( *aSttIdx.GetNode().EndOfSectionNode() );
84 SwTextNode* pTextNd = aSttIdx.GetNode().GetTextNode();
85 if (!pTextNd || !pTextNd->GetText().isEmpty() ||
86 aSttIdx.GetIndex()+1 != rClpDoc.GetNodes().GetEndOfContent().GetIndex() )
88 rClpDoc.GetNodes().Delete( aSttIdx,
89 rClpDoc.GetNodes().GetEndOfContent().GetIndex() - aSttIdx.GetIndex() );
90 pTextNd = rClpDoc.GetNodes().MakeTextNode( aSttIdx.GetNode(),
91 rClpDoc.GetDfltTextFormatColl() );
92 --aSttIdx;
95 // also delete surrounding FlyFrames if any
96 for(sw::SpzFrameFormat* pFly : *rClpDoc.GetSpzFrameFormats() )
98 SwFormatAnchor const*const pAnchor = &pFly->GetAnchor();
99 SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
100 if (pAnchorNode &&
101 ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
102 (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
103 aSttIdx <= *pAnchorNode && *pAnchorNode <= aEndNdIdx.GetNode() )
105 rClpDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFly );
109 rClpDoc.GetDocumentFieldsManager().GCFieldTypes(); // delete the FieldTypes
111 // if a string was passed, copy it to the clipboard-
112 // document. Then also the Calculator can use the internal
113 // clipboard
114 if( pNewClpText )
116 pTextNd->InsertText( *pNewClpText, SwContentIndex( pTextNd ) );
117 return; // that's it
120 rClpDoc.getIDocumentFieldsAccess().LockExpFields();
121 rClpDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines );
123 // do we want to copy a FlyFrame?
124 if( IsFrameSelected() )
126 // get the FlyFormat
127 SwFlyFrame* pFly = GetSelectedFlyFrame();
128 SwFrameFormat* pFlyFormat = pFly->GetFormat();
129 SwFormatAnchor aAnchor( pFlyFormat->GetAnchor() );
131 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
132 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
133 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
134 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
136 SwPosition aPos( aSttIdx );
137 if ( RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId() )
139 aPos.SetContent( 0 );
141 aAnchor.SetAnchor( &aPos );
143 pFlyFormat = rClpDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFlyFormat, aAnchor, true, true );
145 // assure the "RootFormat" is the first element in Spz-Array
146 // (if necessary Flys were copied in Flys)
147 sw::SpzFrameFormats& rSpzFrameFormats = *rClpDoc.GetSpzFrameFormats();
148 if( rSpzFrameFormats[ 0 ] != pFlyFormat )
150 #ifndef NDEBUG
151 bool inserted =
152 #endif
153 rSpzFrameFormats.newDefault(static_cast<sw::SpzFrameFormat*>(pFlyFormat));
154 assert( !inserted && "Fly not contained in Spz-Array" );
157 if ( RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId() )
159 // JP 13.02.99 Bug 61863: if a frameselection is passed to the
160 // clipboard, it should be found at pasting. Therefore
161 // the copied TextAttribut should be removed in the node
162 // otherwise it will be recognised as TextSelektion
163 const SwPosition& rPos = *pFlyFormat->GetAnchor().GetContentAnchor();
164 SwTextFlyCnt *const pTextFly = static_cast<SwTextFlyCnt *>(
165 pTextNd->GetTextAttrForCharAt(
166 rPos.GetContentIndex(), RES_TXTATR_FLYCNT));
167 if( pTextFly )
169 const_cast<SwFormatFlyCnt&>(pTextFly->GetFlyCnt()).SetFlyFormat();
170 pTextNd->EraseText( rPos, 1 );
174 else if ( IsObjSelected() )
176 SwPosition aPos( aSttIdx, pTextNd, 0 );
177 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
178 for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
180 SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
182 if( Imp()->GetDrawView()->IsGroupEntered() ||
183 ( !pObj->GetUserCall() && pObj->getParentSdrObjectFromSdrObject()) )
185 SfxItemSet aSet( rClpDoc.GetAttrPool(), aFrameFormatSetRange );
187 SwFormatAnchor aAnchor( RndStdIds::FLY_AT_PARA );
188 aAnchor.SetAnchor( &aPos );
189 aSet.Put( aAnchor );
191 rtl::Reference<SdrObject> xNew = rClpDoc.CloneSdrObj( *pObj );
193 SwPaM aTemp(aPos);
194 rClpDoc.getIDocumentContentOperations().InsertDrawObj(aTemp, *xNew, aSet );
196 else
198 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
199 SwFrameFormat *pFormat = pContact->GetFormat();
200 SwFormatAnchor aAnchor( pFormat->GetAnchor() );
201 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
202 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
203 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
204 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
206 aAnchor.SetAnchor( &aPos );
209 rClpDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true );
213 else
214 CopySelToDoc(rClpDoc); // copy the selections
216 rClpDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
217 rClpDoc.getIDocumentFieldsAccess().UnlockExpFields();
218 if( !rClpDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() )
219 rClpDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
222 static const Point &lcl_FindBasePos( const SwFrame *pFrame, const Point &rPt )
224 const SwFrame *pF = pFrame;
225 while ( pF && !pF->getFrameArea().Contains( rPt ) )
227 if ( pF->IsContentFrame() )
228 pF = static_cast<const SwContentFrame*>(pF)->GetFollow();
229 else
230 pF = nullptr;
232 if ( pF )
233 return pF->getFrameArea().Pos();
234 else
235 return pFrame->getFrameArea().Pos();
238 static bool lcl_SetAnchor( const SwPosition& rPos, const SwNode& rNd, SwFlyFrame const * pFly,
239 const Point& rInsPt, SwFEShell const & rDestShell, SwFormatAnchor& rAnchor,
240 Point& rNewPos, bool bCheckFlyRecur )
242 bool bRet = true;
243 rAnchor.SetAnchor( &rPos );
244 std::pair<Point, bool> const tmp(rInsPt, false);
245 SwContentFrame *const pTmpFrame = rNd.GetContentNode()->getLayoutFrame(
246 rDestShell.GetLayout(), nullptr, &tmp);
247 SwFlyFrame *pTmpFly = pTmpFrame->FindFlyFrame();
248 if( pTmpFly && bCheckFlyRecur && pFly->IsUpperOf( *pTmpFly ) )
250 bRet = false;
252 else if ( RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId() )
254 if( pTmpFly )
256 const SwNodeIndex& rIdx = *pTmpFly->GetFormat()->GetContent().GetContentIdx();
257 SwPosition aPos( rIdx );
258 rAnchor.SetAnchor( &aPos );
259 rNewPos = pTmpFly->getFrameArea().Pos();
261 else
263 rAnchor.SetType( RndStdIds::FLY_AT_PAGE );
264 rAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
265 const SwFrame *pPg = pTmpFrame->FindPageFrame();
266 rNewPos = pPg->getFrameArea().Pos();
269 else
270 rNewPos = ::lcl_FindBasePos( pTmpFrame, rInsPt );
271 return bRet;
274 bool SwFEShell::CopyDrawSel( SwFEShell& rDestShell, const Point& rSttPt,
275 const Point& rInsPt, bool bIsMove, bool bSelectInsert )
277 bool bRet = true;
279 // The list should be copied, because below new objects will be selected
280 const SdrMarkList aMrkList( Imp()->GetDrawView()->GetMarkedObjectList() );
281 const size_t nMarkCount = aMrkList.GetMarkCount();
282 if( !rDestShell.Imp()->GetDrawView() )
283 // should create it now
284 rDestShell.MakeDrawView();
285 else if( bSelectInsert )
286 rDestShell.Imp()->GetDrawView()->UnmarkAll();
288 SdrPageView *pDestPgView = rDestShell.Imp()->GetPageView(),
289 *pSrcPgView = Imp()->GetPageView();
290 SwDrawView *pDestDrwView = rDestShell.Imp()->GetDrawView(),
291 *pSrcDrwView = Imp()->GetDrawView();
292 SwDoc* pDestDoc = rDestShell.GetDoc();
294 Size aSiz( rInsPt.X() - rSttPt.X(), rInsPt.Y() - rSttPt.Y() );
295 for( size_t i = 0; i < nMarkCount; ++i )
297 SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj();
299 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
300 SwFrameFormat *pFormat = pContact->GetFormat();
301 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
303 bool bInsWithFormat = true;
305 if( pDestDrwView->IsGroupEntered() )
307 // insert into the group, when it belongs to an entered group
308 // or when the object is not anchored as a character
309 if( pSrcDrwView->IsGroupEntered() ||
310 (RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) )
313 rtl::Reference<SdrObject> xNew = pDestDoc->CloneSdrObj( *pObj, bIsMove &&
314 GetDoc() == pDestDoc, false );
315 xNew->NbcMove( aSiz );
316 pDestDrwView->InsertObjectAtView( xNew.get(), *pDestPgView );
317 bInsWithFormat = false;
321 if( bInsWithFormat )
323 SwFormatAnchor aAnchor( rAnchor );
324 Point aNewAnch;
326 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
327 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
328 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
329 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
331 if ( this == &rDestShell )
333 // same shell? Then request the position
334 // from the passed DocumentPosition
335 SwPosition aPos( *GetCursor()->GetPoint() );
336 Point aPt( rInsPt );
337 aPt -= rSttPt - pObj->GetSnapRect().TopLeft();
338 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
339 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState );
340 const SwNode *pNd;
341 if( (pNd = &aPos.GetNode())->IsNoTextNode() )
342 bRet = false;
343 else
344 bRet = ::lcl_SetAnchor( aPos, *pNd, nullptr, rInsPt,
345 rDestShell, aAnchor, aNewAnch, false );
347 else
349 SwPaM *pCursor = rDestShell.GetCursor();
350 if( pCursor->GetPointNode().IsNoTextNode() )
351 bRet = false;
352 else
353 bRet = ::lcl_SetAnchor( *pCursor->GetPoint(),
354 pCursor->GetPointNode(), nullptr, rInsPt,
355 rDestShell, aAnchor,
356 aNewAnch, false );
359 else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() )
361 aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
362 const SwRootFrame* pTmpRoot = rDestShell.GetLayout();
363 const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true );
364 if ( pPg )
365 aNewAnch = pPg->getFrameArea().Pos();
368 if( bRet )
370 if( pSrcDrwView->IsGroupEntered() ||
371 ( !pObj->GetUserCall() && pObj->getParentSdrObjectFromSdrObject()) )
373 SfxItemSet aSet( pDestDoc->GetAttrPool(),aFrameFormatSetRange);
374 aSet.Put( aAnchor );
375 rtl::Reference<SdrObject> xNew = pDestDoc->CloneSdrObj( *pObj, bIsMove &&
376 GetDoc() == pDestDoc );
377 pFormat = pDestDoc->getIDocumentContentOperations().InsertDrawObj( *rDestShell.GetCursor(), *xNew, aSet );
379 else
380 pFormat = pDestDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true );
382 // Can be 0, as Draws are not allowed in Headers/Footers
383 if ( pFormat )
385 // #tdf33692 - drawing object has to be made visible on ctrl+drag copy.
386 pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING));
387 SdrObject* pNew = pFormat->FindSdrObject();
388 if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() )
390 Point aPos( rInsPt );
391 aPos -= aNewAnch;
392 aPos -= rSttPt - pObj->GetSnapRect().TopLeft();
393 // OD 2004-04-05 #i26791# - change attributes instead of
394 // direct positioning
395 pFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME ) );
396 pFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME ) );
397 // #i47455# - notify draw frame format
398 // that position attributes are already set.
399 if (SwDrawFrameFormat *pDrawFormat = dynamic_cast<SwDrawFrameFormat*>(pFormat))
400 pDrawFormat->PosAttrSet();
402 if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, pObj))
404 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, pFormat->GetAttrSet(), pObj);
407 if( bSelectInsert )
408 pDestDrwView->MarkObj( pNew, pDestPgView );
414 if ( bIsMove && bRet )
416 if( &rDestShell == this )
418 const SdrMarkList aList( pSrcDrwView->GetMarkedObjectList() );
419 pSrcDrwView->UnmarkAll();
421 for ( size_t i = 0, nMrkCnt = aMrkList.GetMarkCount(); i < nMrkCnt; ++i )
423 SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj();
424 pSrcDrwView->MarkObj( pObj, pSrcPgView );
426 DelSelectedObj();
427 for ( size_t i = 0, nMrkCnt = aList.GetMarkCount(); i < nMrkCnt; ++i )
429 SdrObject *pObj = aList.GetMark( i )->GetMarkedSdrObj();
430 pSrcDrwView->MarkObj( pObj, pSrcPgView );
433 else
434 DelSelectedObj();
437 return bRet;
440 bool SwFEShell::Copy( SwFEShell& rDestShell, const Point& rSttPt,
441 const Point& rInsPt, bool bIsMove, bool bSelectInsert )
443 bool bRet = false;
445 OSL_ENSURE( this == &rDestShell || !rDestShell.IsObjSelected(),
446 "Dest-Shell cannot be in Obj-Mode" );
448 CurrShell aCurr( &rDestShell );
450 rDestShell.StartAllAction();
451 rDestShell.GetDoc()->getIDocumentFieldsAccess().LockExpFields();
453 // Shift references
454 bool bCopyIsMove = mxDoc->IsCopyIsMove();
455 if( bIsMove )
456 // set a flag in Doc, handled in TextNodes
457 mxDoc->SetCopyIsMove( true );
459 RedlineFlags eOldRedlMode = rDestShell.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
460 rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode | RedlineFlags::DeleteRedlines );
462 // If there are table formulas in the area, then display the table first
463 // so that the table formula can calculate a new value first
464 // (individual boxes in the area are retrieved via the layout)
465 SwFieldType* pTableFieldTyp = rDestShell.GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table );
467 if( IsFrameSelected() )
469 SwFlyFrame* pFly = GetSelectedFlyFrame();
470 SwFrameFormat* pFlyFormat = pFly->GetFormat();
471 SwFormatAnchor aAnchor( pFlyFormat->GetAnchor() );
472 bRet = true;
473 Point aNewAnch;
475 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
476 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
477 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
478 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
480 if ( this == &rDestShell )
482 // same shell? Then request the position
483 // from the passed DocumentPosition
484 SwPosition aPos( *GetCursor()->GetPoint() );
485 Point aPt( rInsPt );
486 aPt -= rSttPt - pFly->getFrameArea().Pos();
487 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
488 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState );
489 const SwNode *pNd;
490 if( (pNd = &aPos.GetNode())->IsNoTextNode() )
491 bRet = false;
492 else
494 // do not copy in itself
495 const SwNodeIndex *pTmp = pFlyFormat->GetContent().GetContentIdx();
496 if ( aPos.GetNodeIndex() > pTmp->GetIndex() &&
497 aPos.GetNodeIndex() < pTmp->GetNode().EndOfSectionIndex() )
499 bRet = false;
501 else
502 bRet = ::lcl_SetAnchor( aPos, *pNd, pFly, rInsPt,
503 rDestShell, aAnchor, aNewAnch, true );
506 else
508 const SwPaM *pCursor = rDestShell.GetCursor();
509 if( pCursor->GetPointNode().IsNoTextNode() )
510 bRet = false;
511 else
512 bRet = ::lcl_SetAnchor( *pCursor->GetPoint(), pCursor->GetPointNode(),
513 pFly, rInsPt, rDestShell, aAnchor,
514 aNewAnch, GetDoc() == rDestShell.GetDoc());
517 else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() )
519 aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
520 const SwRootFrame* pTmpRoot = rDestShell.GetLayout();
521 const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true );
522 if ( pPg )
523 aNewAnch = pPg->getFrameArea().Pos();
525 else {
526 OSL_ENSURE( false, "what anchor is it?" );
529 if( bRet )
531 SwFrameFormat *pOldFormat = pFlyFormat;
532 pFlyFormat = rDestShell.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pFlyFormat, aAnchor, true, true );
534 if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() )
536 Point aPos( rInsPt );
537 aPos -= aNewAnch;
538 aPos -= rSttPt - pFly->getFrameArea().Pos();
539 pFlyFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(),text::HoriOrientation::NONE, text::RelOrientation::FRAME ) );
540 pFlyFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(),text::VertOrientation::NONE, text::RelOrientation::FRAME ) );
543 const Point aPt( rDestShell.GetCursorDocPos() );
545 if( bIsMove )
546 GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pOldFormat );
548 // only select if it can be shifted/copied in the same shell
549 if( bSelectInsert )
551 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pFlyFormat)->GetFrame( &aPt );
552 if( pFlyFrame )
554 //JP 12.05.98: should this be in SelectFlyFrame???
555 rDestShell.Imp()->GetDrawView()->UnmarkAll();
556 rDestShell.SelectFlyFrame( *pFlyFrame );
560 if (this != &rDestShell && !rDestShell.HasShellFocus())
561 rDestShell.Imp()->GetDrawView()->hideMarkHandles();
564 else if ( IsObjSelected() )
565 bRet = CopyDrawSel( rDestShell, rSttPt, rInsPt, bIsMove, bSelectInsert );
566 else if( IsTableMode() )
568 // Copy parts from a table: create a table with the same
569 // width as the original and copy the selected boxes.
570 // Sizes will be corrected by percentage.
572 // find boxes via the layout
573 SwSelBoxes aBoxes;
574 GetTableSel( *this, aBoxes );
575 SwTableNode const*const pTableNd(
576 aBoxes.empty() ? nullptr : aBoxes[0]->GetSttNd()->FindTableNode());
577 if (nullptr != pTableNd)
579 std::optional<SwPosition> oDstPos;
580 if( this == &rDestShell )
582 // same shell? Then create new Cursor at the
583 // DocumentPosition passed
584 oDstPos.emplace( *GetCursor()->GetPoint() );
585 Point aPt( rInsPt );
586 GetLayout()->GetModelPositionForViewPoint( &*oDstPos, aPt );
587 if( !oDstPos->GetNode().IsNoTextNode() )
588 bRet = true;
590 else if( !rDestShell.GetCursor()->GetPointNode().IsNoTextNode() )
592 oDstPos.emplace( *rDestShell.GetCursor()->GetPoint() );
593 bRet = true;
596 if( bRet )
598 if( GetDoc() == rDestShell.GetDoc() )
599 ParkTableCursor();
601 bRet = rDestShell.GetDoc()->InsCopyOfTable( *oDstPos, aBoxes,nullptr,
602 bIsMove && this == &rDestShell &&
603 aBoxes.size() == pTableNd->GetTable().
604 GetTabSortBoxes().size(),
605 this != &rDestShell );
607 if( this != &rDestShell )
608 *rDestShell.GetCursor()->GetPoint() = *oDstPos;
610 // create all parked Cursor?
611 if( GetDoc() == rDestShell.GetDoc() )
612 GetCursor();
614 // JP 16.04.99: Bug 64908 - Set InsPos, to assure the parked
615 // Cursor is positioned at the insert position
616 if( this == &rDestShell )
617 GetCursorDocPos() = rInsPt;
621 else
623 bRet = true;
624 if( this == &rDestShell )
626 // same shell? then request the position
627 // at the passed document position
628 SwPosition aPos( *GetCursor()->GetPoint() );
629 Point aPt( rInsPt );
630 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
631 bRet = !aPos.GetNode().IsNoTextNode();
633 else if( rDestShell.GetCursor()->GetPointNode().IsNoTextNode() )
634 bRet = false;
636 if( bRet )
637 bRet = SwEditShell::Copy( rDestShell );
640 rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode );
641 mxDoc->SetCopyIsMove( bCopyIsMove );
643 // have new table formulas been inserted?
644 if( pTableFieldTyp->HasWriterListeners() )
646 // finish old actions: the table frames are created and
647 // a selection can be made
648 sal_uInt16 nActCnt;
649 for( nActCnt = 0; rDestShell.ActionPend(); ++nActCnt )
650 rDestShell.EndAllAction();
652 for( ; nActCnt; --nActCnt )
653 rDestShell.StartAllAction();
655 rDestShell.GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
656 rDestShell.GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
658 rDestShell.EndAllAction();
659 return bRet;
662 // Paste for the internal clipboard. Copy the content of the clipboard
663 // in the document
664 namespace {
665 typedef std::shared_ptr<SwPaM> PaMPtr;
666 typedef std::shared_ptr<SwPosition> PositionPtr;
667 typedef std::pair< PaMPtr, PositionPtr > Insertion;
669 bool PamHasSelection(const SwPaM& rPaM)
671 return rPaM.HasMark() && *rPaM.GetPoint() != *rPaM.GetMark();
674 /// Is pFormat anchored in a fly frame which has an associated draw format?
675 bool IsInTextBox(const SwFrameFormat* pFormat)
677 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
678 const SwNode* pAnchorNode = rAnchor.GetAnchorNode();
679 if (!pAnchorNode)
681 return false;
684 const SwStartNode* pFlyNode = pAnchorNode->FindFlyStartNode();
685 if (!pFlyNode)
687 return false;
690 for(const sw::SpzFrameFormat* pSpzFormat: *pFormat->GetDoc()->GetSpzFrameFormats())
692 if (pSpzFormat->Which() != RES_FLYFRMFMT)
694 continue;
697 const SwNodeIndex* pIdx = pSpzFormat->GetContent().GetContentIdx();
698 if (!pIdx || pFlyNode != &pIdx->GetNode())
700 continue;
703 return SwTextBoxHelper::isTextBox(pSpzFormat, RES_FLYFRMFMT);
706 return false;
710 namespace {
711 SwFrameFormat* lcl_PasteFlyOrDrawFormat(SwPaM& rPaM, SwFrameFormat* pCpyFormat, SwFEShell& rSh)
713 auto& rImp = *rSh.Imp();
714 auto& rDoc = *rSh.GetDoc();
715 auto& rDrawView = *rImp.GetDrawView();
716 if(rDrawView.IsGroupEntered() &&
717 RES_DRAWFRMFMT == pCpyFormat->Which() &&
718 (RndStdIds::FLY_AS_CHAR != pCpyFormat->GetAnchor().GetAnchorId()))
720 const SdrObject* pSdrObj = pCpyFormat->FindSdrObject();
721 if(pSdrObj)
723 rtl::Reference<SdrObject> xNew = rDoc.CloneSdrObj(*pSdrObj, false, false);
724 // Insert object sets any anchor position to 0.
725 // Therefore we calculate the absolute position here
726 // and after the insert the anchor of the object
727 // is set to the anchor of the group object.
728 tools::Rectangle aSnapRect = xNew->GetSnapRect();
729 if(xNew->GetAnchorPos().X() || xNew->GetAnchorPos().Y())
731 const Point aPoint(0, 0);
732 // OD 2004-04-05 #i26791# - direct drawing object
733 // positioning for group members
734 xNew->NbcSetAnchorPos(aPoint);
735 xNew->NbcSetSnapRect(aSnapRect);
738 rDrawView.InsertObjectAtView(xNew.get(), *rImp.GetPageView());
740 Point aGrpAnchor(0, 0);
741 SdrObjList* pList = xNew->getParentSdrObjListFromSdrObject();
742 if(pList)
744 SdrObjGroup* pOwner(dynamic_cast<SdrObjGroup*>(pList->getSdrObjectFromSdrObjList()));
746 if(nullptr != pOwner)
747 aGrpAnchor = pOwner->GetAnchorPos();
750 // OD 2004-04-05 #i26791# - direct drawing object
751 // positioning for group members
752 xNew->NbcSetAnchorPos(aGrpAnchor);
753 xNew->SetSnapRect(aSnapRect);
754 return nullptr;
757 SwFormatAnchor aAnchor(pCpyFormat->GetAnchor());
758 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
759 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
760 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
762 SwPosition* pPos = rPaM.GetPoint();
763 // allow shapes (no controls) in header/footer
764 if(RES_DRAWFRMFMT == pCpyFormat->Which() && rDoc.IsInHeaderFooter(pPos->GetNode()))
766 const SdrObject *pCpyObj = pCpyFormat->FindSdrObject();
767 if(pCpyObj && CheckControlLayer(pCpyObj))
768 return nullptr;
770 else if(pCpyFormat->Which() == RES_FLYFRMFMT && IsInTextBox(pCpyFormat))
772 // This is a fly frame which is anchored in a TextBox, ignore it as
773 // it's already copied as part of copying the content of the
774 // TextBox.
775 return nullptr;
777 // Ignore TextBoxes, they are already handled in sw::DocumentLayoutManager::CopyLayoutFormat().
778 if(SwTextBoxHelper::isTextBox(pCpyFormat, RES_FLYFRMFMT))
779 return nullptr;
780 aAnchor.SetAnchor(pPos);
782 else if(RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId())
784 aAnchor.SetPageNum(rSh.GetPhyPageNum());
786 else if(RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId())
788 Point aPt;
789 (void)lcl_SetAnchor(*rPaM.GetPoint(), rPaM.GetPointNode(), nullptr, aPt, rSh, aAnchor, aPt, false);
792 SwFrameFormat* pNew = rDoc.getIDocumentLayoutAccess().CopyLayoutFormat(*pCpyFormat, aAnchor, true, true);
793 return pNew;
796 void lcl_SelectFlyFormat(SwFrameFormat *const pNew, SwFEShell& rSh)
798 if(!pNew)
799 return;
800 switch(pNew->Which())
802 case RES_FLYFRMFMT:
804 assert(dynamic_cast<SwFlyFrameFormat*>(pNew));
805 const Point aPt(rSh.GetCursorDocPos());
806 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pNew)->GetFrame(&aPt);
807 if(pFlyFrame)
808 rSh.SelectFlyFrame(*pFlyFrame);
809 break;
811 case RES_DRAWFRMFMT:
813 auto& rDrawView = *rSh.Imp()->GetDrawView();
814 assert(dynamic_cast<SwDrawFrameFormat*>(pNew));
815 SwDrawFrameFormat* pDrawFormat = static_cast<SwDrawFrameFormat*>(pNew);
816 // #i52780# - drawing object has to be made visible on paste.
817 pDrawFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING));
818 SdrObject* pObj = pDrawFormat->FindSdrObject();
819 rDrawView.MarkObj(pObj, rDrawView.GetSdrPageView());
820 // #i47455# - notify draw frame format
821 // that position attributes are already set.
822 pDrawFormat->PosAttrSet();
823 break;
825 default:
826 SAL_WARN("sw.core", "unknown fly type");
831 bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
833 CurrShell aCurr( this );
834 // then till end of the nodes array
835 SwNodeIndex aIdx( rClpDoc.GetNodes().GetEndOfExtras(), 2 );
836 // select content section, whatever it may contain
837 SwPaM aCpyPam(aIdx, SwNodeIndex(rClpDoc.GetNodes().GetEndOfContent(), -1));
838 if (SwContentNode *const pAtEnd = aCpyPam.GetPointNode().GetContentNode())
840 aCpyPam.GetPoint()->AssignEndIndex(*pAtEnd);
843 // If there are table formulas in the area, then display the table first
844 // so that the table formula can calculate a new value first
845 // (individual boxes in the area are retrieved via the layout)
846 SwFieldType* pTableFieldTyp = GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table );
848 SwTableNode *const pSrcNd = aCpyPam.GetMarkNode().GetTableNode();
850 bool bRet = true;
851 StartAllAction();
852 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY, nullptr );
853 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
855 // When the clipboard content has been created by a rectangular selection
856 // the pasting is more sophisticated:
857 // every paragraph will be inserted into another position.
858 // The first positions are given by the actual cursor ring,
859 // if there are more text portions to insert than cursor in this ring,
860 // the additional insert positions will be created by moving the last
861 // cursor position into the next line (like pressing the cursor down key)
862 if( rClpDoc.IsColumnSelection() && !IsTableMode() )
864 // Creation of the list of insert positions
865 std::vector< Insertion > aCopyVector;
866 // The number of text portions of the rectangular selection
867 const SwNodeOffset nSelCount = aCpyPam.GetPoint()->GetNodeIndex()
868 - aCpyPam.GetMark()->GetNodeIndex();
869 SwNodeOffset nCount = nSelCount;
870 SwNodeIndex aClpIdx( aIdx );
871 SwPaM* pStartCursor = GetCursor();
872 SwPaM* pCurrCursor = pStartCursor;
873 SwNodeOffset nCursorCount( pStartCursor->GetRingContainer().size() );
874 // If the target selection is a multi-selection, often the last and first
875 // cursor of the ring points to identical document positions. Then
876 // we should avoid double insertion of text portions...
877 while( nCursorCount > SwNodeOffset(1) && *pCurrCursor->GetPoint() ==
878 *(pCurrCursor->GetPrev()->GetPoint()) )
880 --nCursorCount;
881 pCurrCursor = pCurrCursor->GetNext();
882 pStartCursor = pCurrCursor;
884 SwPosition aStartPos( *pStartCursor->GetPoint() );
885 SwPosition aInsertPos( aStartPos ); // first insertion position
886 bool bCompletePara = false;
887 sal_uInt16 nMove = 0;
888 while( nCount )
890 --nCount;
891 OSL_ENSURE( aIdx.GetNode().GetContentNode(), "Who filled the clipboard?!" );
892 if( aIdx.GetNode().GetContentNode() ) // robust
894 Insertion aInsertion( std::make_shared<SwPaM>( aIdx ),
895 std::make_shared<SwPosition>( aInsertPos ) );
896 ++aIdx;
897 aInsertion.first->SetMark();
898 if( pStartCursor == pCurrCursor->GetNext() )
899 { // Now we have to look for insertion positions...
900 if( !nMove ) // Annotate the last given insert position
901 aStartPos = aInsertPos;
902 SwCursor aCursor( aStartPos, nullptr);
903 // Check if we find another insert position by moving
904 // down the last given position
905 if (aCursor.UpDown(false, ++nMove, nullptr, 0, *GetLayout()))
906 aInsertPos = *aCursor.GetPoint();
907 else // if there is no paragraph we have to create it
908 bCompletePara = nCount > SwNodeOffset(0);
909 nCursorCount = SwNodeOffset(0);
911 else // as long as we find more insert positions in the cursor ring
912 { // we'll take them
913 pCurrCursor = pCurrCursor->GetNext();
914 aInsertPos = *pCurrCursor->GetPoint();
915 --nCursorCount;
917 // If there are no more paragraphs e.g. at the end of a document,
918 // we insert complete paragraphs instead of text portions
919 if( bCompletePara )
920 aInsertion.first->GetPoint()->Assign(aIdx);
921 else
922 aInsertion.first->GetPoint()->SetContent(
923 aInsertion.first->GetPointContentNode()->Len() );
924 aCopyVector.push_back( aInsertion );
926 // If there are no text portions left but there are some more
927 // cursor positions to fill we have to restart with the first
928 // text portion
929 if( !nCount && nCursorCount )
931 nCount = min( nSelCount, nCursorCount );
932 aIdx = aClpIdx; // Start of clipboard content
935 for (auto const& item : aCopyVector)
937 SwPosition& rInsPos = *item.second;
938 SwPaM& rCopy = *item.first;
939 const SwStartNode* pBoxNd = rInsPos.GetNode().FindTableBoxStartNode();
940 if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() - pBoxNd->GetIndex() &&
941 rCopy.GetPoint()->GetNode() != rCopy.GetMark()->GetNode() )
943 // if more than one node will be copied into a cell
944 // the box attributes have to be removed
945 GetDoc()->ClearBoxNumAttrs( rInsPos.GetNode() );
948 SwNodeIndex aIndexBefore(rInsPos.GetNode());
949 --aIndexBefore;
950 rClpDoc.getIDocumentContentOperations().CopyRange(rCopy, rInsPos, SwCopyFlags::CheckPosInFly);
952 ++aIndexBefore;
953 SwPaM aPaM(SwPosition(aIndexBefore),
954 SwPosition(rInsPos.GetNode()));
955 aPaM.GetDoc().MakeUniqueNumRules(aPaM);
958 SaveTableBoxContent( &rInsPos );
961 else
963 bool bDelTable = true;
965 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
968 SwTableNode *const pDestNd(SwDoc::IsInTable(rPaM.GetPoint()->GetNode()));
969 if (pSrcNd && nullptr != pDestNd &&
970 // not a forced nested table insertion
971 !bNestedTable &&
972 // Heuristics to allow copying table rows or nesting tables without
973 // using Edit -> Paste Special -> Paste as Nested Table:
974 // Using table cursor, or if the text selection starts in the
975 // first paragraph, or if there is no selection and the text cursor
976 // is there in the first paragraph, overwrite content of the cell(s)
977 // (else insert a nested table later, i.e. if nothing selected and
978 // the cursor is not in the first paragraph, or the selected text
979 // doesn't contain the first paragraph of the cell)
980 rPaM.GetPointNode().GetIndex() == rPaM.GetPointNode().FindTableBoxStartNode()->GetIndex() + 1)
982 SwPosition aDestPos( *rPaM.GetPoint() );
984 bool bParkTableCursor = false;
985 const SwStartNode* pSttNd = rPaM.GetPointNode().FindTableBoxStartNode();
987 // TABLE IN TABLE: copy table in table
988 // search boxes via the layout
989 SwSelBoxes aBoxes;
990 if( IsTableMode() ) // table selection?
992 GetTableSel( *this, aBoxes );
993 ParkTableCursor();
994 bParkTableCursor = true;
996 else if( !PamHasSelection(rPaM) && rPaM.GetNext() == &rPaM &&
997 ( !pSrcNd->GetTable().IsTableComplex() ||
998 pDestNd->GetTable().IsNewModel() ) )
1000 // make relative table copy
1001 SwTableBox* pBox = pDestNd->GetTable().GetTableBox(
1002 pSttNd->GetIndex() );
1003 OSL_ENSURE( pBox, "Box is not in this table" );
1004 aBoxes.insert( pBox );
1007 SwNodeIndex aNdIdx( *pDestNd->EndOfSectionNode());
1008 if( !bParkTableCursor )
1010 // exit first the complete table
1011 // ???? what about only table in a frame ?????
1012 SwContentNode* pCNd = GetDoc()->GetNodes().GoNext( &aNdIdx );
1013 SwPosition aPos( aNdIdx, pCNd, 0 );
1014 // #i59539: Don't remove all redline
1015 SwPaM const tmpPaM(*pDestNd, *pDestNd->EndOfSectionNode());
1016 ::PaMCorrAbs(tmpPaM, aPos);
1019 bRet = GetDoc()->InsCopyOfTable( aDestPos, aBoxes, &pSrcNd->GetTable() );
1021 if( bParkTableCursor )
1022 GetCursor();
1023 else
1025 // return to the box
1026 aNdIdx = *pSttNd;
1027 SwContentNode* pCNd = GetDoc()->GetNodes().GoNext( &aNdIdx );
1028 SwPosition aPos( aNdIdx, pCNd, 0 );
1029 // #i59539: Don't remove all redline
1030 SwNode & rNode(rPaM.GetPoint()->GetNode());
1031 SwContentNode *const pContentNode( rNode.GetContentNode() );
1032 SwPaM const tmpPam(rNode, 0,
1033 rNode, pContentNode ? pContentNode->Len() : 0);
1034 ::PaMCorrAbs(tmpPam, aPos);
1037 break; // exit the "while-loop"
1039 else if(*aCpyPam.GetPoint() == *aCpyPam.GetMark() && !rClpDoc.GetSpzFrameFormats()->empty())
1041 // we need a DrawView
1042 if(!Imp()->GetDrawView())
1043 MakeDrawView();
1044 ::std::vector<SwFrameFormat*> inserted;
1045 for (sw::SpzFrameFormat* pFlyFormat: *rClpDoc.GetSpzFrameFormats())
1047 // if anchored inside other fly, will be copied when copying
1048 // top-level fly, so skip here! (other non-body anchor
1049 // shouldn't happen here)
1050 SwFormatAnchor const& rAnchor(pFlyFormat->GetAnchor());
1051 if (RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()
1052 || rClpDoc.GetNodes().GetEndOfExtras().GetIndex() < rAnchor.GetAnchorNode()->GetIndex())
1054 inserted.emplace_back(
1055 lcl_PasteFlyOrDrawFormat(rPaM, pFlyFormat, *this));
1058 for (auto const pFlyFormat : inserted)
1060 lcl_SelectFlyFormat(pFlyFormat, *this);
1063 else
1065 if( bDelTable && IsTableMode() )
1067 SwEditShell::Delete(false);
1068 bDelTable = false;
1071 SwPosition& rInsPos = *rPaM.GetPoint();
1072 const SwStartNode* pBoxNd = rInsPos.GetNode().
1073 FindTableBoxStartNode();
1074 if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() -
1075 pBoxNd->GetIndex() &&
1076 aCpyPam.GetPoint()->GetNode() != aCpyPam.GetMark()->GetNode() )
1078 // Copy more than 1 node in the current box. But
1079 // then the BoxAttribute should be removed
1080 GetDoc()->ClearBoxNumAttrs( rInsPos.GetNode() );
1083 // **
1084 // ** Update SwDoc::Append, if you change the following code **
1085 // **
1087 SwNodeIndex aIndexBefore(rInsPos.GetNode());
1089 --aIndexBefore;
1091 rClpDoc.getIDocumentContentOperations().CopyRange(aCpyPam, rInsPos, SwCopyFlags::CheckPosInFly);
1092 // Note: aCpyPam is invalid now
1094 ++aIndexBefore;
1095 SwPaM aPaM(aIndexBefore.GetNode(), rInsPos.GetNode());
1097 aPaM.GetDoc().MakeUniqueNumRules(aPaM);
1099 // Update the rsid of each pasted text node.
1100 SwNodes &rDestNodes = GetDoc()->GetNodes();
1101 SwNodeOffset const nEndIdx = aPaM.End()->GetNodeIndex();
1103 for (SwNodeOffset nIdx = aPaM.Start()->GetNodeIndex();
1104 nIdx <= nEndIdx; ++nIdx)
1106 SwTextNode *const pTextNode = rDestNodes[nIdx]->GetTextNode();
1107 if ( pTextNode )
1109 GetDoc()->UpdateParRsid( pTextNode );
1114 SaveTableBoxContent( &rInsPos );
1119 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSGLOSSARY, nullptr );
1121 // have new table formulas been inserted?
1122 if( pTableFieldTyp->HasWriterListeners() )
1124 // finish old action: table-frames have been created
1125 // a selection can be made now
1126 sal_uInt16 nActCnt;
1127 for( nActCnt = 0; ActionPend(); ++nActCnt )
1128 EndAllAction();
1130 for( ; nActCnt; --nActCnt )
1131 StartAllAction();
1133 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1134 GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
1135 EndAllAction();
1137 return bRet;
1140 void SwFEShell::PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, sal_uInt16 nEndPage)
1142 Push();
1143 if(!GotoPage(nStartPage))
1145 Pop(PopMode::DeleteCurrent);
1146 return;
1148 MovePage( GetThisFrame, GetFirstSub );
1149 ::std::optional<SwPaM> oSourcePam( *GetCursor()->GetPoint() );
1150 OUString sStartingPageDesc = GetPageDesc( GetCurPageDesc()).GetName();
1151 SwPageDesc* pDesc = rToFill.FindPageDescByName( sStartingPageDesc, true );
1152 if( pDesc )
1153 rToFill.ChgCurPageDesc( *pDesc );
1155 if(!GotoPage(nEndPage))
1157 Pop(PopMode::DeleteCurrent);
1158 return;
1160 //if the page starts with a table a paragraph has to be inserted before
1161 SwNode *const pTableNode = oSourcePam->GetPointNode().FindTableNode();
1162 if(pTableNode)
1164 //insert a paragraph
1165 StartUndo(SwUndoId::INSERT);
1166 SwNodeIndex aTableIdx( *pTableNode, -1 );
1167 SwPosition aBefore(aTableIdx);
1168 if(GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ))
1170 SwPaM aTmp(aBefore);
1171 *oSourcePam = aTmp;
1173 EndUndo(SwUndoId::INSERT);
1176 MovePage( GetThisFrame, GetLastSub );
1177 oSourcePam->SetMark();
1178 *oSourcePam->GetMark() = *GetCursor()->GetPoint();
1180 CurrShell aCurr( this );
1182 StartAllAction();
1183 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
1184 SetSelection(*oSourcePam);
1185 // copy the text of the selection
1186 SwEditShell::Copy(rToFill);
1187 oSourcePam.reset(); // delete it because Undo will remove its node!
1189 if(pTableNode)
1191 //remove the inserted paragraph
1192 Undo();
1193 //remove the paragraph in the second doc, too
1194 SwPaM aPara( rToFill.GetDoc()->GetNodes().GetEndOfExtras(), SwNodeOffset(2) ); //DocStart
1195 rToFill.GetDoc()->getIDocumentContentOperations().DelFullPara(aPara);
1197 // now the page bound objects
1198 // additionally copy page bound frames
1199 if( !GetDoc()->GetSpzFrameFormats()->empty() )
1201 // create a draw view if necessary
1202 if( !rToFill.Imp()->GetDrawView() )
1203 rToFill.MakeDrawView();
1205 for(sw::SpzFrameFormat* pCpyFormat: *GetDoc()->GetSpzFrameFormats())
1207 SwFormatAnchor aAnchor( pCpyFormat->GetAnchor() );
1208 if ((RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId()) &&
1209 aAnchor.GetPageNum() >= nStartPage && aAnchor.GetPageNum() <= nEndPage)
1211 aAnchor.SetPageNum( aAnchor.GetPageNum() - nStartPage + 1);
1213 else
1214 continue;
1215 rToFill.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pCpyFormat, aAnchor, true, true );
1218 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1219 GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
1220 Pop(PopMode::DeleteCurrent);
1221 EndAllAction();
1224 comphelper::OInterfaceContainerHelper3<css::text::XPasteListener>& SwFEShell::GetPasteListeners() { return m_aPasteListeners; }
1226 bool SwFEShell::GetDrawObjGraphic( SotClipboardFormatId nFormat, Graphic& rGrf ) const
1228 OSL_ENSURE( Imp()->HasDrawView(), "GetDrawObjGraphic without DrawView?" );
1229 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1230 bool bConvert = true;
1231 if( rMrkList.GetMarkCount() )
1233 if( rMrkList.GetMarkCount() == 1 &&
1234 dynamic_cast< const SwVirtFlyDrawObj* >(rMrkList.GetMark( 0 )->GetMarkedSdrObj()) != nullptr )
1236 // select frame
1237 if( CNT_GRF == GetCntType() )
1239 const Graphic* pGrf( GetGraphic() );
1240 if ( pGrf )
1242 Graphic aGrf( *pGrf );
1243 if( SotClipboardFormatId::GDIMETAFILE == nFormat )
1245 if( GraphicType::Bitmap != aGrf.GetType() )
1247 rGrf = aGrf;
1248 bConvert = false;
1250 else if( GetWin() )
1252 Size aSz;
1253 Point aPt;
1254 GetGrfSize( aSz );
1256 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1257 pVirtDev->EnableOutput( false );
1259 MapMode aTmp( GetWin()->GetMapMode() );
1260 aTmp.SetOrigin( aPt );
1261 pVirtDev->SetMapMode( aTmp );
1263 GDIMetaFile aMtf;
1264 aMtf.Record( pVirtDev.get() );
1265 aGrf.Draw(*pVirtDev, aPt, aSz);
1266 aMtf.Stop();
1267 aMtf.SetPrefMapMode( aTmp );
1268 aMtf.SetPrefSize( aSz );
1269 rGrf = aMtf;
1272 else if( GraphicType::Bitmap == aGrf.GetType() )
1274 rGrf = aGrf;
1275 bConvert = false;
1277 else
1279 // Not the original size, but the current one.
1280 // Otherwise it could happen that for vector graphics
1281 // many MB's of memory are allocated.
1282 const Size aSz( GetSelectedFlyFrame()->getFramePrintArea().SSize() );
1283 ScopedVclPtrInstance< VirtualDevice > pVirtDev(*GetWin()->GetOutDev());
1285 MapMode aTmp( MapUnit::MapTwip );
1286 pVirtDev->SetMapMode( aTmp );
1287 if( pVirtDev->SetOutputSize( aSz ) )
1289 aGrf.Draw(*pVirtDev, Point(), aSz);
1290 rGrf = pVirtDev->GetBitmapEx( Point(), aSz );
1292 else
1294 rGrf = aGrf;
1295 bConvert = false;
1301 else if( SotClipboardFormatId::GDIMETAFILE == nFormat )
1302 rGrf = Imp()->GetDrawView()->GetMarkedObjMetaFile();
1303 else if( SotClipboardFormatId::BITMAP == nFormat || SotClipboardFormatId::PNG == nFormat )
1304 rGrf = Imp()->GetDrawView()->GetMarkedObjBitmapEx();
1306 return bConvert;
1309 // #i50824#
1310 // replace method <lcl_RemoveOleObjsFromSdrModel> by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs>
1311 static void lcl_ConvertSdrOle2ObjsToSdrGrafObjs( SdrModel& _rModel )
1313 for ( sal_uInt16 nPgNum = 0; nPgNum < _rModel.GetPageCount(); ++nPgNum )
1315 // setup object iterator in order to iterate through all objects
1316 // including objects in group objects, but exclusive group objects.
1317 SdrObjListIter aIter(_rModel.GetPage(nPgNum));
1318 while( aIter.IsMore() )
1320 SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( aIter.Next() );
1321 if( pOle2Obj )
1323 // found an ole2 shape
1324 SdrObjList* pObjList = pOle2Obj->getParentSdrObjListFromSdrObject();
1326 // get its graphic
1327 Graphic aGraphic;
1328 pOle2Obj->Connect();
1329 const Graphic* pGraphic = pOle2Obj->GetGraphic();
1330 if( pGraphic )
1331 aGraphic = *pGraphic;
1332 pOle2Obj->Disconnect();
1334 // create new graphic shape with the ole graphic and shape size
1335 rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj(
1336 _rModel,
1337 aGraphic,
1338 pOle2Obj->GetCurrentBoundRect());
1339 // apply layer of ole2 shape at graphic shape
1340 pGraphicObj->SetLayer( pOle2Obj->GetLayer() );
1342 // replace ole2 shape with the new graphic object and delete the ol2 shape
1343 pObjList->ReplaceObject( pGraphicObj.get(), pOle2Obj->GetOrdNum() );
1349 void SwFEShell::Paste( SvStream& rStrm, SwPasteSdr nAction, const Point* pPt )
1351 CurrShell aCurr( this );
1352 StartAllAction();
1353 StartUndo();
1355 std::unique_ptr< FmFormModel > pModel(
1356 new FmFormModel(
1357 nullptr,
1358 GetDoc()->GetDocShell()));
1360 pModel->GetItemPool().FreezeIdRanges();
1362 rStrm.Seek(0);
1364 uno::Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( rStrm ) );
1365 SvxDrawingLayerImport( pModel.get(), xInputStream );
1367 if ( !Imp()->HasDrawView() )
1368 Imp()->MakeDrawView();
1370 Point aPos( pPt ? *pPt : GetCharRect().Pos() );
1371 SdrView *pView = Imp()->GetDrawView();
1373 // drop on the existing object: replace object or apply new attributes
1374 if( pModel->GetPageCount() > 0 &&
1375 1 == pModel->GetPage(0)->GetObjCount() &&
1376 1 == pView->GetMarkedObjectList().GetMarkCount() )
1378 // replace a marked 'virtual' drawing object
1379 // by its corresponding 'master' drawing object in the mark list.
1380 SwDrawView::ReplaceMarkedDrawVirtObjs( *pView );
1382 SdrObject* pClpObj = pModel->GetPage(0)->GetObj(0);
1383 SdrObject* pOldObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj();
1385 if( SwPasteSdr::SetAttr == nAction && dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1386 nAction = SwPasteSdr::Replace;
1388 switch( nAction )
1390 case SwPasteSdr::Replace:
1392 const SwFrameFormat* pFormat(nullptr);
1393 const SwFrame* pAnchor(nullptr);
1394 if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1396 pFormat = FindFrameFormat( pOldObj );
1398 Point aNullPt;
1399 SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrameFormat*>(pFormat)->GetFrame( &aNullPt );
1400 pAnchor = pFlyFrame ? pFlyFrame->GetAnchorFrame() : nullptr;
1402 if (!pAnchor || pAnchor->FindFooterOrHeader())
1404 // if there is a textframe in the header/footer:
1405 // do not replace but insert
1406 nAction = SwPasteSdr::Insert;
1407 break;
1411 rtl::Reference<SdrObject> pNewObj(pClpObj->CloneSdrObject(pOldObj->getSdrModelFromSdrObject()));
1412 tools::Rectangle aOldObjRect( pOldObj->GetCurrentBoundRect() );
1413 Size aOldObjSize( aOldObjRect.GetSize() );
1414 tools::Rectangle aNewRect( pNewObj->GetCurrentBoundRect() );
1415 Size aNewSize( aNewRect.GetSize() );
1417 Fraction aScaleWidth( aOldObjSize.Width(), aNewSize.Width() );
1418 Fraction aScaleHeight( aOldObjSize.Height(), aNewSize.Height());
1419 pNewObj->NbcResize( aNewRect.TopLeft(), aScaleWidth, aScaleHeight);
1421 Point aVec = aOldObjRect.TopLeft() - aNewRect.TopLeft();
1422 pNewObj->NbcMove(Size(aVec.getX(), aVec.getY()));
1424 if( dynamic_cast<const SdrUnoObj*>( pNewObj.get()) != nullptr )
1425 pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() );
1426 else if( dynamic_cast<const SdrUnoObj*>( pOldObj) != nullptr )
1427 pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() );
1428 else
1429 pNewObj->SetLayer( pOldObj->GetLayer() );
1431 if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1433 // store attributes, then set SdrObject
1434 SfxItemSetFixed<RES_SURROUND, RES_ANCHOR> aFrameSet( mxDoc->GetAttrPool() );
1435 aFrameSet.Set( pFormat->GetAttrSet() );
1437 Point aNullPt;
1438 if( pAnchor->IsTextFrame() && static_cast<const SwTextFrame*>(pAnchor)->IsFollow() )
1440 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnchor);
1441 do {
1442 pTmp = pTmp->FindMaster();
1443 OSL_ENSURE( pTmp, "Where's my Master?" );
1444 } while( pTmp->IsFollow() );
1445 pAnchor = pTmp;
1447 if( auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pOldObj))
1448 aNullPt = pCaptionObj->GetTailPos();
1449 else
1450 aNullPt = aOldObjRect.TopLeft();
1452 Point aNewAnchor = pAnchor->GetFrameAnchorPos( ::HasWrap( pOldObj ) );
1453 // OD 2004-04-05 #i26791# - direct positioning of Writer
1454 // fly frame object for <SwDoc::Insert(..)>
1455 pNewObj->NbcSetRelativePos( aNullPt - aNewAnchor );
1456 pNewObj->NbcSetAnchorPos( aNewAnchor );
1458 pOldObj->GetOrdNum();
1460 DelSelectedObj();
1462 GetDoc()->getIDocumentContentOperations().InsertDrawObj( *GetCursor(), *pNewObj, aFrameSet );
1464 else
1466 // #i123922# for handling MasterObject and virtual ones correctly, SW
1467 // wants us to call ReplaceObject at the page, but that also
1468 // triggers the same assertion (I tried it), so stay at the view method
1469 pView->ReplaceObjectAtView(pOldObj, *Imp()->GetPageView(), pNewObj.get());
1472 break;
1474 case SwPasteSdr::SetAttr:
1476 SfxItemSet aSet( GetAttrPool() );
1477 const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pClpObj);
1479 if(pSdrGrafObj)
1481 SdrObject* pTarget = nullptr;
1483 if(0 != pView->GetMarkedObjectList().GetMarkCount())
1485 // try to get target (if it's at least one, take first)
1486 SdrMark* pMark = pView->GetMarkedObjectList().GetMark(0);
1488 if(pMark)
1490 pTarget = pMark->GetMarkedSdrObj();
1494 if(pTarget)
1496 // copy ItemSet from target
1497 aSet.Set(pTarget->GetMergedItemSet());
1500 // for SdrGrafObj, use the graphic as fill style argument
1501 const Graphic& rGraphic = pSdrGrafObj->GetGraphic();
1503 if(GraphicType::NONE != rGraphic.GetType() && GraphicType::Default != rGraphic.GetType())
1505 aSet.Put(XFillBitmapItem(OUString(), rGraphic));
1506 aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
1509 else
1511 aSet.Put(pClpObj->GetMergedItemSet());
1514 pView->SetAttributes( aSet );
1516 break;
1518 default:
1519 nAction = SwPasteSdr::Insert;
1520 break;
1523 else
1524 nAction = SwPasteSdr::Insert;
1526 if( SwPasteSdr::Insert == nAction )
1528 ::sw::DrawUndoGuard drawUndoGuard(GetDoc()->GetIDocumentUndoRedo());
1530 bool bDesignMode = pView->IsDesignMode();
1531 if( !bDesignMode )
1532 pView->SetDesignMode();
1534 // #i50824#
1535 // method <lcl_RemoveOleObjsFromSdrModel> replaced by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs>
1536 lcl_ConvertSdrOle2ObjsToSdrGrafObjs(*pModel);
1537 pView->Paste(*pModel, aPos, nullptr, SdrInsertFlags::NONE);
1539 const size_t nCnt = pView->GetMarkedObjectList().GetMarkCount();
1540 if( nCnt )
1542 const Point aNull( 0, 0 );
1543 for( size_t i=0; i < nCnt; ++i )
1545 SdrObject *pObj = pView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj();
1546 pObj->ImpSetAnchorPos( aNull );
1549 pView->SetCurrentObj( SdrObjKind::Group );
1550 if ( nCnt > 1 )
1551 pView->GroupMarked();
1552 SdrObject *pObj = pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
1553 if( dynamic_cast<const SdrUnoObj*>( pObj) != nullptr )
1555 pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() );
1556 bDesignMode = true;
1558 else
1559 pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() );
1560 const tools::Rectangle &rSnap = pObj->GetSnapRect();
1561 const Size aDiff( rSnap.GetWidth()/2, rSnap.GetHeight()/2 );
1562 pView->MoveMarkedObj( aDiff );
1563 ImpEndCreate();
1564 if( !bDesignMode )
1565 pView->SetDesignMode( false );
1568 EndUndo();
1569 EndAllAction();
1572 bool SwFEShell::Paste(const Graphic &rGrf, const OUString& rURL)
1574 CurrShell aCurr( this );
1575 SdrObject* pObj = nullptr;
1576 SdrView *pView = Imp()->GetDrawView();
1578 bool bRet = 1 == pView->GetMarkedObjectList().GetMarkCount();
1579 if (bRet)
1581 pObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj();
1582 bRet = pObj->IsClosedObj() && dynamic_cast<const SdrOle2Obj*>( pObj) == nullptr;
1585 if( bRet && pObj )
1587 // #i123922# added code to handle the two cases of SdrGrafObj and a fillable, non-
1588 // OLE object in focus
1589 SdrObject* pResult = pObj;
1591 if(auto pGrafObj = dynamic_cast< SdrGrafObj* >(pObj))
1593 rtl::Reference<SdrGrafObj> pNewGrafObj = SdrObject::Clone(*pGrafObj, pGrafObj->getSdrModelFromSdrObject());
1595 pNewGrafObj->SetGraphic(rGrf);
1597 // #i123922# for handling MasterObject and virtual ones correctly, SW
1598 // wants us to call ReplaceObject at the page, but that also
1599 // triggers the same assertion (I tried it), so stay at the view method
1600 pView->ReplaceObjectAtView(pObj, *pView->GetSdrPageView(), pNewGrafObj.get());
1602 // set in all cases - the Clone() will have copied an existing link (!)
1603 pNewGrafObj->SetGraphicLink(rURL);
1605 pResult = pNewGrafObj.get();
1607 else
1609 pView->AddUndo(std::make_unique<SdrUndoAttrObj>(*pObj));
1611 SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(pView->GetModel().GetItemPool());
1613 aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
1614 aSet.Put(XFillBitmapItem(OUString(), rGrf));
1615 pObj->SetMergedItemSetAndBroadcast(aSet);
1618 // we are done; mark the modified/new object
1619 pView->MarkObj(pResult, pView->GetSdrPageView());
1622 return bRet;
1625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */