tdf#35361 Add a Quick Look plugins for .od* files on macOS
[LibreOffice.git] / sw / source / core / frmedt / fecopy.cxx
blob84fb8c9682247bb60cd30abc22ab2b4a8c37a50a
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 TextAttribute should be removed in the node
162 // otherwise it will be recognised as TextSelection
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 if (SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj )))
200 SwFrameFormat *pFormat = pContact->GetFormat();
201 SwFormatAnchor aAnchor( pFormat->GetAnchor() );
202 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
203 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
204 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
205 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
207 aAnchor.SetAnchor( &aPos );
210 rClpDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true );
215 else
216 CopySelToDoc(rClpDoc); // copy the selections
218 rClpDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
219 rClpDoc.getIDocumentFieldsAccess().UnlockExpFields();
220 if( !rClpDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() )
221 rClpDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true);
224 static const Point &lcl_FindBasePos( const SwFrame *pFrame, const Point &rPt )
226 const SwFrame *pF = pFrame;
227 while ( pF && !pF->getFrameArea().Contains( rPt ) )
229 if ( pF->IsContentFrame() )
230 pF = static_cast<const SwContentFrame*>(pF)->GetFollow();
231 else
232 pF = nullptr;
234 if ( pF )
235 return pF->getFrameArea().Pos();
236 else
237 return pFrame->getFrameArea().Pos();
240 static bool lcl_SetAnchor( const SwPosition& rPos, const SwNode& rNd, SwFlyFrame const * pFly,
241 const Point& rInsPt, SwFEShell const & rDestShell, SwFormatAnchor& rAnchor,
242 Point& rNewPos, bool bCheckFlyRecur )
244 bool bRet = true;
245 rAnchor.SetAnchor( &rPos );
246 std::pair<Point, bool> const tmp(rInsPt, false);
247 SwContentFrame *const pTmpFrame = rNd.GetContentNode()->getLayoutFrame(
248 rDestShell.GetLayout(), nullptr, &tmp);
249 SwFlyFrame *pTmpFly = pTmpFrame->FindFlyFrame();
250 if( pTmpFly && bCheckFlyRecur && pFly->IsUpperOf( *pTmpFly ) )
252 bRet = false;
254 else if ( RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId() )
256 if( pTmpFly )
258 const SwNodeIndex& rIdx = *pTmpFly->GetFormat()->GetContent().GetContentIdx();
259 SwPosition aPos( rIdx );
260 rAnchor.SetAnchor( &aPos );
261 rNewPos = pTmpFly->getFrameArea().Pos();
263 else
265 rAnchor.SetType( RndStdIds::FLY_AT_PAGE );
266 rAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
267 const SwFrame *pPg = pTmpFrame->FindPageFrame();
268 rNewPos = pPg->getFrameArea().Pos();
271 else
272 rNewPos = ::lcl_FindBasePos( pTmpFrame, rInsPt );
273 return bRet;
276 bool SwFEShell::CopyDrawSel( SwFEShell& rDestShell, const Point& rSttPt,
277 const Point& rInsPt, bool bIsMove, bool bSelectInsert )
279 bool bRet = true;
281 // The list should be copied, because below new objects will be selected
282 const SdrMarkList aMrkList( Imp()->GetDrawView()->GetMarkedObjectList() );
283 const size_t nMarkCount = aMrkList.GetMarkCount();
284 if( !rDestShell.Imp()->GetDrawView() )
285 // should create it now
286 rDestShell.MakeDrawView();
287 else if( bSelectInsert )
288 rDestShell.Imp()->GetDrawView()->UnmarkAll();
290 SdrPageView *pDestPgView = rDestShell.Imp()->GetPageView(),
291 *pSrcPgView = Imp()->GetPageView();
292 SwDrawView *pDestDrwView = rDestShell.Imp()->GetDrawView(),
293 *pSrcDrwView = Imp()->GetDrawView();
294 SwDoc* pDestDoc = rDestShell.GetDoc();
296 Size aSiz( rInsPt.X() - rSttPt.X(), rInsPt.Y() - rSttPt.Y() );
297 for( size_t i = 0; i < nMarkCount; ++i )
299 SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj();
301 SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj ));
302 if (!pContact)
303 continue;
305 SwFrameFormat *pFormat = pContact->GetFormat();
306 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
308 bool bInsWithFormat = true;
310 if( pDestDrwView->IsGroupEntered() )
312 // insert into the group, when it belongs to an entered group
313 // or when the object is not anchored as a character
314 if( pSrcDrwView->IsGroupEntered() ||
315 (RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) )
318 rtl::Reference<SdrObject> xNew = pDestDoc->CloneSdrObj( *pObj, bIsMove &&
319 GetDoc() == pDestDoc, false );
320 xNew->NbcMove( aSiz );
321 pDestDrwView->InsertObjectAtView( xNew.get(), *pDestPgView );
322 bInsWithFormat = false;
326 if( bInsWithFormat )
328 SwFormatAnchor aAnchor( rAnchor );
329 Point aNewAnch;
331 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
332 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
333 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
334 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
336 if ( this == &rDestShell )
338 // same shell? Then request the position
339 // from the passed DocumentPosition
340 SwPosition aPos( *GetCursor()->GetPoint() );
341 Point aPt( rInsPt );
342 aPt -= rSttPt - pObj->GetSnapRect().TopLeft();
343 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
344 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState );
345 const SwNode *pNd;
346 if( (pNd = &aPos.GetNode())->IsNoTextNode() )
347 bRet = false;
348 else
349 bRet = ::lcl_SetAnchor( aPos, *pNd, nullptr, rInsPt,
350 rDestShell, aAnchor, aNewAnch, false );
352 else
354 SwPaM *pCursor = rDestShell.GetCursor();
355 if( pCursor->GetPointNode().IsNoTextNode() )
356 bRet = false;
357 else
358 bRet = ::lcl_SetAnchor( *pCursor->GetPoint(),
359 pCursor->GetPointNode(), nullptr, rInsPt,
360 rDestShell, aAnchor,
361 aNewAnch, false );
364 else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() )
366 aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
367 const SwRootFrame* pTmpRoot = rDestShell.GetLayout();
368 const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true );
369 if ( pPg )
370 aNewAnch = pPg->getFrameArea().Pos();
373 if( bRet )
375 if( pSrcDrwView->IsGroupEntered() ||
376 ( !pObj->GetUserCall() && pObj->getParentSdrObjectFromSdrObject()) )
378 SfxItemSet aSet( pDestDoc->GetAttrPool(),aFrameFormatSetRange);
379 aSet.Put( aAnchor );
380 rtl::Reference<SdrObject> xNew = pDestDoc->CloneSdrObj( *pObj, bIsMove &&
381 GetDoc() == pDestDoc );
382 pFormat = pDestDoc->getIDocumentContentOperations().InsertDrawObj( *rDestShell.GetCursor(), *xNew, aSet );
384 else
385 pFormat = pDestDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true );
387 // Can be 0, as Draws are not allowed in Headers/Footers
388 if ( pFormat )
390 // #tdf33692 - drawing object has to be made visible on ctrl+drag copy.
391 pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING));
392 SdrObject* pNew = pFormat->FindSdrObject();
393 if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() )
395 Point aPos( rInsPt );
396 aPos -= aNewAnch;
397 aPos -= rSttPt - pObj->GetSnapRect().TopLeft();
398 // OD 2004-04-05 #i26791# - change attributes instead of
399 // direct positioning
400 pFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME ) );
401 pFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME ) );
402 // #i47455# - notify draw frame format
403 // that position attributes are already set.
404 if (SwDrawFrameFormat *pDrawFormat = dynamic_cast<SwDrawFrameFormat*>(pFormat))
405 pDrawFormat->PosAttrSet();
407 if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, pObj))
409 SwTextBoxHelper::syncFlyFrameAttr(*pFormat, pFormat->GetAttrSet(), pObj);
412 if( bSelectInsert )
413 pDestDrwView->MarkObj( pNew, pDestPgView );
419 if ( bIsMove && bRet )
421 if( &rDestShell == this )
423 const SdrMarkList aList( pSrcDrwView->GetMarkedObjectList() );
424 pSrcDrwView->UnmarkAll();
426 for ( size_t i = 0, nMrkCnt = aMrkList.GetMarkCount(); i < nMrkCnt; ++i )
428 SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj();
429 pSrcDrwView->MarkObj( pObj, pSrcPgView );
431 DelSelectedObj();
432 for ( size_t i = 0, nMrkCnt = aList.GetMarkCount(); i < nMrkCnt; ++i )
434 SdrObject *pObj = aList.GetMark( i )->GetMarkedSdrObj();
435 pSrcDrwView->MarkObj( pObj, pSrcPgView );
438 else
439 DelSelectedObj();
442 return bRet;
445 bool SwFEShell::Copy( SwFEShell& rDestShell, const Point& rSttPt,
446 const Point& rInsPt, bool bIsMove, bool bSelectInsert )
448 bool bRet = false;
450 OSL_ENSURE( this == &rDestShell || !rDestShell.IsObjSelected(),
451 "Dest-Shell cannot be in Obj-Mode" );
453 CurrShell aCurr( &rDestShell );
455 rDestShell.StartAllAction();
456 rDestShell.GetDoc()->getIDocumentFieldsAccess().LockExpFields();
458 // Shift references
459 bool bCopyIsMove = mxDoc->IsCopyIsMove();
460 if( bIsMove )
461 // set a flag in Doc, handled in TextNodes
462 mxDoc->SetCopyIsMove( true );
464 RedlineFlags eOldRedlMode = rDestShell.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags();
465 rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode | RedlineFlags::DeleteRedlines );
467 // If there are table formulas in the area, then display the table first
468 // so that the table formula can calculate a new value first
469 // (individual boxes in the area are retrieved via the layout)
470 SwFieldType* pTableFieldTyp = rDestShell.GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table );
472 if( IsFrameSelected() )
474 SwFlyFrame* pFly = GetSelectedFlyFrame();
475 SwFrameFormat* pFlyFormat = pFly->GetFormat();
476 SwFormatAnchor aAnchor( pFlyFormat->GetAnchor() );
477 bRet = true;
478 Point aNewAnch;
480 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
481 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
482 (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) ||
483 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
485 if ( this == &rDestShell )
487 // same shell? Then request the position
488 // from the passed DocumentPosition
489 SwPosition aPos( *GetCursor()->GetPoint() );
490 Point aPt( rInsPt );
491 aPt -= rSttPt - pFly->getFrameArea().Pos();
492 SwCursorMoveState aState( CursorMoveState::SetOnlyText );
493 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState );
494 const SwNode *pNd;
495 if( (pNd = &aPos.GetNode())->IsNoTextNode() )
496 bRet = false;
497 else
499 // do not copy in itself
500 const SwNodeIndex *pTmp = pFlyFormat->GetContent().GetContentIdx();
501 if ( aPos.GetNodeIndex() > pTmp->GetIndex() &&
502 aPos.GetNodeIndex() < pTmp->GetNode().EndOfSectionIndex() )
504 bRet = false;
506 else
507 bRet = ::lcl_SetAnchor( aPos, *pNd, pFly, rInsPt,
508 rDestShell, aAnchor, aNewAnch, true );
511 else
513 const SwPaM *pCursor = rDestShell.GetCursor();
514 if( pCursor->GetPointNode().IsNoTextNode() )
515 bRet = false;
516 else
517 bRet = ::lcl_SetAnchor( *pCursor->GetPoint(), pCursor->GetPointNode(),
518 pFly, rInsPt, rDestShell, aAnchor,
519 aNewAnch, GetDoc() == rDestShell.GetDoc());
522 else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() )
524 aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) );
525 const SwRootFrame* pTmpRoot = rDestShell.GetLayout();
526 const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true );
527 if ( pPg )
528 aNewAnch = pPg->getFrameArea().Pos();
530 else {
531 OSL_ENSURE( false, "what anchor is it?" );
534 if( bRet )
536 SwFrameFormat *pOldFormat = pFlyFormat;
537 pFlyFormat = rDestShell.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pFlyFormat, aAnchor, true, true );
539 if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() )
541 Point aPos( rInsPt );
542 aPos -= aNewAnch;
543 aPos -= rSttPt - pFly->getFrameArea().Pos();
544 pFlyFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(),text::HoriOrientation::NONE, text::RelOrientation::FRAME ) );
545 pFlyFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(),text::VertOrientation::NONE, text::RelOrientation::FRAME ) );
548 const Point aPt( rDestShell.GetCursorDocPos() );
550 if( bIsMove )
551 GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pOldFormat );
553 // only select if it can be shifted/copied in the same shell
554 if( bSelectInsert )
556 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pFlyFormat)->GetFrame( &aPt );
557 if( pFlyFrame )
559 //JP 12.05.98: should this be in SelectFlyFrame???
560 rDestShell.Imp()->GetDrawView()->UnmarkAll();
561 rDestShell.SelectFlyFrame( *pFlyFrame );
565 if (this != &rDestShell && !rDestShell.HasShellFocus())
566 rDestShell.Imp()->GetDrawView()->hideMarkHandles();
569 else if ( IsObjSelected() )
570 bRet = CopyDrawSel( rDestShell, rSttPt, rInsPt, bIsMove, bSelectInsert );
571 else if( IsTableMode() )
573 // Copy parts from a table: create a table with the same
574 // width as the original and copy the selected boxes.
575 // Sizes will be corrected by percentage.
577 // find boxes via the layout
578 SwSelBoxes aBoxes;
579 GetTableSel( *this, aBoxes );
580 SwTableNode const*const pTableNd(
581 aBoxes.empty() ? nullptr : aBoxes[0]->GetSttNd()->FindTableNode());
582 if (nullptr != pTableNd)
584 std::optional<SwPosition> oDstPos;
585 if( this == &rDestShell )
587 // same shell? Then create new Cursor at the
588 // DocumentPosition passed
589 oDstPos.emplace( *GetCursor()->GetPoint() );
590 Point aPt( rInsPt );
591 GetLayout()->GetModelPositionForViewPoint( &*oDstPos, aPt );
592 if( !oDstPos->GetNode().IsNoTextNode() )
593 bRet = true;
595 else if( !rDestShell.GetCursor()->GetPointNode().IsNoTextNode() )
597 oDstPos.emplace( *rDestShell.GetCursor()->GetPoint() );
598 bRet = true;
601 if( bRet )
603 if( GetDoc() == rDestShell.GetDoc() )
604 ParkTableCursor();
606 bRet = rDestShell.GetDoc()->InsCopyOfTable( *oDstPos, aBoxes,nullptr,
607 bIsMove && this == &rDestShell &&
608 aBoxes.size() == pTableNd->GetTable().
609 GetTabSortBoxes().size(),
610 this != &rDestShell );
612 if( this != &rDestShell )
613 *rDestShell.GetCursor()->GetPoint() = *oDstPos;
615 // create all parked Cursor?
616 if( GetDoc() == rDestShell.GetDoc() )
617 GetCursor();
619 // JP 16.04.99: Bug 64908 - Set InsPos, to assure the parked
620 // Cursor is positioned at the insert position
621 if( this == &rDestShell )
622 GetCursorDocPos() = rInsPt;
626 else
628 bRet = true;
629 if( this == &rDestShell )
631 // same shell? then request the position
632 // at the passed document position
633 SwPosition aPos( *GetCursor()->GetPoint() );
634 Point aPt( rInsPt );
635 GetLayout()->GetModelPositionForViewPoint( &aPos, aPt );
636 bRet = !aPos.GetNode().IsNoTextNode();
638 else if( rDestShell.GetCursor()->GetPointNode().IsNoTextNode() )
639 bRet = false;
641 if( bRet )
642 bRet = SwEditShell::Copy( rDestShell );
645 rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode );
646 mxDoc->SetCopyIsMove( bCopyIsMove );
648 // have new table formulas been inserted?
649 if( pTableFieldTyp->HasWriterListeners() )
651 // finish old actions: the table frames are created and
652 // a selection can be made
653 sal_uInt16 nActCnt;
654 for( nActCnt = 0; rDestShell.ActionPend(); ++nActCnt )
655 rDestShell.EndAllAction();
657 for( ; nActCnt; --nActCnt )
658 rDestShell.StartAllAction();
660 rDestShell.GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
661 rDestShell.GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
663 rDestShell.EndAllAction();
664 return bRet;
667 // Paste for the internal clipboard. Copy the content of the clipboard
668 // in the document
669 namespace {
670 typedef std::shared_ptr<SwPaM> PaMPtr;
671 typedef std::shared_ptr<SwPosition> PositionPtr;
672 typedef std::pair< PaMPtr, PositionPtr > Insertion;
674 bool PamHasSelection(const SwPaM& rPaM)
676 return rPaM.HasMark() && *rPaM.GetPoint() != *rPaM.GetMark();
679 /// Is pFormat anchored in a fly frame which has an associated draw format?
680 bool IsInTextBox(const SwFrameFormat* pFormat)
682 const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
683 const SwNode* pAnchorNode = rAnchor.GetAnchorNode();
684 if (!pAnchorNode)
686 return false;
689 const SwStartNode* pFlyNode = pAnchorNode->FindFlyStartNode();
690 if (!pFlyNode)
692 return false;
695 for(const sw::SpzFrameFormat* pSpzFormat: *pFormat->GetDoc()->GetSpzFrameFormats())
697 if (pSpzFormat->Which() != RES_FLYFRMFMT)
699 continue;
702 const SwNodeIndex* pIdx = pSpzFormat->GetContent().GetContentIdx();
703 if (!pIdx || pFlyNode != &pIdx->GetNode())
705 continue;
708 return SwTextBoxHelper::isTextBox(pSpzFormat, RES_FLYFRMFMT);
711 return false;
715 namespace {
716 SwFrameFormat* lcl_PasteFlyOrDrawFormat(SwPaM& rPaM, SwFrameFormat* pCpyFormat, SwFEShell& rSh)
718 auto& rImp = *rSh.Imp();
719 auto& rDoc = *rSh.GetDoc();
720 auto& rDrawView = *rImp.GetDrawView();
721 if(rDrawView.IsGroupEntered() &&
722 RES_DRAWFRMFMT == pCpyFormat->Which() &&
723 (RndStdIds::FLY_AS_CHAR != pCpyFormat->GetAnchor().GetAnchorId()))
725 const SdrObject* pSdrObj = pCpyFormat->FindSdrObject();
726 if(pSdrObj)
728 rtl::Reference<SdrObject> xNew = rDoc.CloneSdrObj(*pSdrObj, false, false);
729 // Insert object sets any anchor position to 0.
730 // Therefore we calculate the absolute position here
731 // and after the insert the anchor of the object
732 // is set to the anchor of the group object.
733 tools::Rectangle aSnapRect = xNew->GetSnapRect();
734 if(xNew->GetAnchorPos().X() || xNew->GetAnchorPos().Y())
736 const Point aPoint(0, 0);
737 // OD 2004-04-05 #i26791# - direct drawing object
738 // positioning for group members
739 xNew->NbcSetAnchorPos(aPoint);
740 xNew->NbcSetSnapRect(aSnapRect);
743 rDrawView.InsertObjectAtView(xNew.get(), *rImp.GetPageView());
745 Point aGrpAnchor(0, 0);
746 SdrObjList* pList = xNew->getParentSdrObjListFromSdrObject();
747 if(pList)
749 SdrObjGroup* pOwner(dynamic_cast<SdrObjGroup*>(pList->getSdrObjectFromSdrObjList()));
751 if(nullptr != pOwner)
752 aGrpAnchor = pOwner->GetAnchorPos();
755 // OD 2004-04-05 #i26791# - direct drawing object
756 // positioning for group members
757 xNew->NbcSetAnchorPos(aGrpAnchor);
758 xNew->SetSnapRect(aSnapRect);
759 return nullptr;
762 SwFormatAnchor aAnchor(pCpyFormat->GetAnchor());
763 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
764 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
765 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
767 SwPosition* pPos = rPaM.GetPoint();
768 // allow shapes (no controls) in header/footer
769 if(RES_DRAWFRMFMT == pCpyFormat->Which() && rDoc.IsInHeaderFooter(pPos->GetNode()))
771 const SdrObject *pCpyObj = pCpyFormat->FindSdrObject();
772 if(pCpyObj && CheckControlLayer(pCpyObj))
773 return nullptr;
775 else if(pCpyFormat->Which() == RES_FLYFRMFMT && IsInTextBox(pCpyFormat))
777 // This is a fly frame which is anchored in a TextBox, ignore it as
778 // it's already copied as part of copying the content of the
779 // TextBox.
780 return nullptr;
782 // Ignore TextBoxes, they are already handled in sw::DocumentLayoutManager::CopyLayoutFormat().
783 if(SwTextBoxHelper::isTextBox(pCpyFormat, RES_FLYFRMFMT))
784 return nullptr;
785 aAnchor.SetAnchor(pPos);
787 else if(RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId())
789 aAnchor.SetPageNum(rSh.GetPhyPageNum());
791 else if(RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId())
793 Point aPt;
794 (void)lcl_SetAnchor(*rPaM.GetPoint(), rPaM.GetPointNode(), nullptr, aPt, rSh, aAnchor, aPt, false);
797 SwFrameFormat* pNew = rDoc.getIDocumentLayoutAccess().CopyLayoutFormat(*pCpyFormat, aAnchor, true, true);
798 return pNew;
801 void lcl_SelectFlyFormat(SwFrameFormat *const pNew, SwFEShell& rSh)
803 if(!pNew)
804 return;
805 switch(pNew->Which())
807 case RES_FLYFRMFMT:
809 assert(dynamic_cast<SwFlyFrameFormat*>(pNew));
810 const Point aPt(rSh.GetCursorDocPos());
811 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pNew)->GetFrame(&aPt);
812 if(pFlyFrame)
813 rSh.SelectFlyFrame(*pFlyFrame);
814 break;
816 case RES_DRAWFRMFMT:
818 auto& rDrawView = *rSh.Imp()->GetDrawView();
819 assert(dynamic_cast<SwDrawFrameFormat*>(pNew));
820 SwDrawFrameFormat* pDrawFormat = static_cast<SwDrawFrameFormat*>(pNew);
821 // #i52780# - drawing object has to be made visible on paste.
822 pDrawFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING));
823 SdrObject* pObj = pDrawFormat->FindSdrObject();
824 rDrawView.MarkObj(pObj, rDrawView.GetSdrPageView());
825 // #i47455# - notify draw frame format
826 // that position attributes are already set.
827 pDrawFormat->PosAttrSet();
828 break;
830 default:
831 SAL_WARN("sw.core", "unknown fly type");
836 bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable)
838 CurrShell aCurr( this );
839 // then till end of the nodes array
840 SwNodeIndex aIdx( rClpDoc.GetNodes().GetEndOfExtras(), 2 );
841 // select content section, whatever it may contain
842 SwPaM aCpyPam(aIdx, SwNodeIndex(rClpDoc.GetNodes().GetEndOfContent(), -1));
843 if (SwContentNode *const pAtEnd = aCpyPam.GetPointNode().GetContentNode())
845 aCpyPam.GetPoint()->AssignEndIndex(*pAtEnd);
848 // If there are table formulas in the area, then display the table first
849 // so that the table formula can calculate a new value first
850 // (individual boxes in the area are retrieved via the layout)
851 SwFieldType* pTableFieldTyp = GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table );
853 SwTableNode *const pSrcNd = aCpyPam.GetMarkNode().GetTableNode();
855 bool bRet = true;
856 StartAllAction();
857 GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY, nullptr );
858 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
860 // When the clipboard content has been created by a rectangular selection
861 // the pasting is more sophisticated:
862 // every paragraph will be inserted into another position.
863 // The first positions are given by the actual cursor ring,
864 // if there are more text portions to insert than cursor in this ring,
865 // the additional insert positions will be created by moving the last
866 // cursor position into the next line (like pressing the cursor down key)
867 if( rClpDoc.IsColumnSelection() && !IsTableMode() )
869 // Creation of the list of insert positions
870 std::vector< Insertion > aCopyVector;
871 // The number of text portions of the rectangular selection
872 const SwNodeOffset nSelCount = aCpyPam.GetPoint()->GetNodeIndex()
873 - aCpyPam.GetMark()->GetNodeIndex();
874 SwNodeOffset nCount = nSelCount;
875 SwNodeIndex aClpIdx( aIdx );
876 SwPaM* pStartCursor = GetCursor();
877 SwPaM* pCurrCursor = pStartCursor;
878 SwNodeOffset nCursorCount( pStartCursor->GetRingContainer().size() );
879 // If the target selection is a multi-selection, often the last and first
880 // cursor of the ring points to identical document positions. Then
881 // we should avoid double insertion of text portions...
882 while( nCursorCount > SwNodeOffset(1) && *pCurrCursor->GetPoint() ==
883 *(pCurrCursor->GetPrev()->GetPoint()) )
885 --nCursorCount;
886 pCurrCursor = pCurrCursor->GetNext();
887 pStartCursor = pCurrCursor;
889 SwPosition aStartPos( *pStartCursor->GetPoint() );
890 SwPosition aInsertPos( aStartPos ); // first insertion position
891 bool bCompletePara = false;
892 sal_uInt16 nMove = 0;
893 while( nCount )
895 --nCount;
896 OSL_ENSURE( aIdx.GetNode().GetContentNode(), "Who filled the clipboard?!" );
897 if( aIdx.GetNode().GetContentNode() ) // robust
899 Insertion aInsertion( std::make_shared<SwPaM>( aIdx ),
900 std::make_shared<SwPosition>( aInsertPos ) );
901 ++aIdx;
902 aInsertion.first->SetMark();
903 if( pStartCursor == pCurrCursor->GetNext() )
904 { // Now we have to look for insertion positions...
905 if( !nMove ) // Annotate the last given insert position
906 aStartPos = aInsertPos;
907 SwCursor aCursor( aStartPos, nullptr);
908 // Check if we find another insert position by moving
909 // down the last given position
910 if (aCursor.UpDown(false, ++nMove, nullptr, 0, *GetLayout()))
911 aInsertPos = *aCursor.GetPoint();
912 else // if there is no paragraph we have to create it
913 bCompletePara = nCount > SwNodeOffset(0);
914 nCursorCount = SwNodeOffset(0);
916 else // as long as we find more insert positions in the cursor ring
917 { // we'll take them
918 pCurrCursor = pCurrCursor->GetNext();
919 aInsertPos = *pCurrCursor->GetPoint();
920 --nCursorCount;
922 // If there are no more paragraphs e.g. at the end of a document,
923 // we insert complete paragraphs instead of text portions
924 if( bCompletePara )
925 aInsertion.first->GetPoint()->Assign(aIdx);
926 else
927 aInsertion.first->GetPoint()->SetContent(
928 aInsertion.first->GetPointContentNode()->Len() );
929 aCopyVector.push_back( aInsertion );
931 // If there are no text portions left but there are some more
932 // cursor positions to fill we have to restart with the first
933 // text portion
934 if( !nCount && nCursorCount )
936 nCount = min( nSelCount, nCursorCount );
937 aIdx = aClpIdx; // Start of clipboard content
940 for (auto const& item : aCopyVector)
942 SwPosition& rInsPos = *item.second;
943 SwPaM& rCopy = *item.first;
944 const SwStartNode* pBoxNd = rInsPos.GetNode().FindTableBoxStartNode();
945 if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() - pBoxNd->GetIndex() &&
946 rCopy.GetPoint()->GetNode() != rCopy.GetMark()->GetNode() )
948 // if more than one node will be copied into a cell
949 // the box attributes have to be removed
950 GetDoc()->ClearBoxNumAttrs( rInsPos.GetNode() );
953 SwNodeIndex aIndexBefore(rInsPos.GetNode());
954 --aIndexBefore;
955 rClpDoc.getIDocumentContentOperations().CopyRange(rCopy, rInsPos, SwCopyFlags::CheckPosInFly);
957 ++aIndexBefore;
958 SwPaM aPaM(SwPosition(aIndexBefore),
959 SwPosition(rInsPos.GetNode()));
960 aPaM.GetDoc().MakeUniqueNumRules(aPaM);
963 SaveTableBoxContent( &rInsPos );
966 else
968 bool bDelTable = true;
970 for(SwPaM& rPaM : GetCursor()->GetRingContainer())
973 SwTableNode *const pDestNd(SwDoc::IsInTable(rPaM.GetPoint()->GetNode()));
974 if (pSrcNd && nullptr != pDestNd &&
975 // not a forced nested table insertion
976 !bNestedTable &&
977 // Heuristics to allow copying table rows or nesting tables without
978 // using Edit -> Paste Special -> Paste as Nested Table:
979 // Using table cursor, or if the text selection starts in the
980 // first paragraph, or if there is no selection and the text cursor
981 // is there in the first paragraph, overwrite content of the cell(s)
982 // (else insert a nested table later, i.e. if nothing selected and
983 // the cursor is not in the first paragraph, or the selected text
984 // doesn't contain the first paragraph of the cell)
985 rPaM.GetPointNode().GetIndex() == rPaM.GetPointNode().FindTableBoxStartNode()->GetIndex() + 1)
987 SwPosition aDestPos( *rPaM.GetPoint() );
989 bool bParkTableCursor = false;
990 const SwStartNode* pSttNd = rPaM.GetPointNode().FindTableBoxStartNode();
992 // TABLE IN TABLE: copy table in table
993 // search boxes via the layout
994 SwSelBoxes aBoxes;
995 if( IsTableMode() ) // table selection?
997 GetTableSel( *this, aBoxes );
998 ParkTableCursor();
999 bParkTableCursor = true;
1001 else if( !PamHasSelection(rPaM) && rPaM.GetNext() == &rPaM &&
1002 ( !pSrcNd->GetTable().IsTableComplex() ||
1003 pDestNd->GetTable().IsNewModel() ) )
1005 // make relative table copy
1006 SwTableBox* pBox = pDestNd->GetTable().GetTableBox(
1007 pSttNd->GetIndex() );
1008 OSL_ENSURE( pBox, "Box is not in this table" );
1009 aBoxes.insert( pBox );
1012 SwNodeIndex aNdIdx( *pDestNd->EndOfSectionNode());
1013 if( !bParkTableCursor )
1015 // exit first the complete table
1016 // ???? what about only table in a frame ?????
1017 SwContentNode* pCNd = SwNodes::GoNext(&aNdIdx);
1018 SwPosition aPos( aNdIdx, pCNd, 0 );
1019 // #i59539: Don't remove all redline
1020 SwPaM const tmpPaM(*pDestNd, *pDestNd->EndOfSectionNode());
1021 ::PaMCorrAbs(tmpPaM, aPos);
1024 bRet = GetDoc()->InsCopyOfTable( aDestPos, aBoxes, &pSrcNd->GetTable() );
1026 if( bParkTableCursor )
1027 GetCursor();
1028 else
1030 // return to the box
1031 aNdIdx = *pSttNd;
1032 SwContentNode* pCNd = SwNodes::GoNext(&aNdIdx);
1033 SwPosition aPos( aNdIdx, pCNd, 0 );
1034 // #i59539: Don't remove all redline
1035 SwNode & rNode(rPaM.GetPoint()->GetNode());
1036 SwContentNode *const pContentNode( rNode.GetContentNode() );
1037 SwPaM const tmpPam(rNode, 0,
1038 rNode, pContentNode ? pContentNode->Len() : 0);
1039 ::PaMCorrAbs(tmpPam, aPos);
1042 break; // exit the "while-loop"
1044 else if(*aCpyPam.GetPoint() == *aCpyPam.GetMark() && !rClpDoc.GetSpzFrameFormats()->empty())
1046 // we need a DrawView
1047 if(!Imp()->GetDrawView())
1048 MakeDrawView();
1049 ::std::vector<SwFrameFormat*> inserted;
1050 for (sw::SpzFrameFormat* pFlyFormat: *rClpDoc.GetSpzFrameFormats())
1052 // if anchored inside other fly, will be copied when copying
1053 // top-level fly, so skip here! (other non-body anchor
1054 // shouldn't happen here)
1055 SwFormatAnchor const& rAnchor(pFlyFormat->GetAnchor());
1056 if (RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()
1057 || rClpDoc.GetNodes().GetEndOfExtras().GetIndex() < rAnchor.GetAnchorNode()->GetIndex())
1059 inserted.emplace_back(
1060 lcl_PasteFlyOrDrawFormat(rPaM, pFlyFormat, *this));
1063 for (auto const pFlyFormat : inserted)
1065 lcl_SelectFlyFormat(pFlyFormat, *this);
1068 else
1070 if( bDelTable && IsTableMode() )
1072 SwEditShell::Delete(false);
1073 bDelTable = false;
1076 SwPosition& rInsPos = *rPaM.GetPoint();
1077 const SwStartNode* pBoxNd = rInsPos.GetNode().
1078 FindTableBoxStartNode();
1079 if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() -
1080 pBoxNd->GetIndex() &&
1081 aCpyPam.GetPoint()->GetNode() != aCpyPam.GetMark()->GetNode() )
1083 // Copy more than 1 node in the current box. But
1084 // then the BoxAttribute should be removed
1085 GetDoc()->ClearBoxNumAttrs( rInsPos.GetNode() );
1088 // **
1089 // ** Update SwDoc::Append, if you change the following code **
1090 // **
1092 SwNodeIndex aIndexBefore(rInsPos.GetNode());
1094 --aIndexBefore;
1096 // copying to the clipboard, the section is inserted
1097 // at the start of the nodes, followed by empty text node
1098 bool const isSourceSection(aCpyPam.Start()->GetNode().IsSectionNode()
1099 && aCpyPam.End()->GetNodeIndex() == aCpyPam.Start()->GetNode().EndOfSectionIndex() + 1
1100 && aCpyPam.End()->GetNode().IsTextNode()
1101 && aCpyPam.End()->GetNode().GetTextNode()->Len() == 0);
1103 rClpDoc.getIDocumentContentOperations().CopyRange(aCpyPam, rInsPos, SwCopyFlags::CheckPosInFly);
1104 // Note: aCpyPam is invalid now
1106 if (isSourceSection
1107 && aIndexBefore.GetNode().IsStartNode()
1108 && rInsPos.GetNode().GetTextNode()->Len() == 0)
1109 { // if there is an empty text node at the start, it
1110 // should be *replaced* by the section, so delete it
1111 GetDoc()->getIDocumentContentOperations().DelFullPara(rPaM);
1114 ++aIndexBefore;
1115 SwPaM aPaM(aIndexBefore.GetNode(), rInsPos.GetNode());
1117 aPaM.GetDoc().MakeUniqueNumRules(aPaM);
1119 // Update the rsid of each pasted text node.
1120 SwNodes &rDestNodes = GetDoc()->GetNodes();
1121 SwNodeOffset const nEndIdx = aPaM.End()->GetNodeIndex();
1123 for (SwNodeOffset nIdx = aPaM.Start()->GetNodeIndex();
1124 nIdx <= nEndIdx; ++nIdx)
1126 SwTextNode *const pTextNode = rDestNodes[nIdx]->GetTextNode();
1127 if ( pTextNode )
1129 GetDoc()->UpdateParRsid( pTextNode );
1134 SaveTableBoxContent( &rInsPos );
1139 GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSGLOSSARY, nullptr );
1141 // have new table formulas been inserted?
1142 if( pTableFieldTyp->HasWriterListeners() )
1144 // finish old action: table-frames have been created
1145 // a selection can be made now
1146 sal_uInt16 nActCnt;
1147 for( nActCnt = 0; ActionPend(); ++nActCnt )
1148 EndAllAction();
1150 for( ; nActCnt; --nActCnt )
1151 StartAllAction();
1153 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1154 GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
1155 EndAllAction();
1157 return bRet;
1160 void SwFEShell::PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, sal_uInt16 nEndPage)
1162 Push();
1163 if(!GotoPage(nStartPage))
1165 Pop(PopMode::DeleteCurrent);
1166 return;
1168 MovePage( GetThisFrame, GetFirstSub );
1169 ::std::optional<SwPaM> oSourcePam( *GetCursor()->GetPoint() );
1170 OUString sStartingPageDesc = GetPageDesc( GetCurPageDesc()).GetName();
1171 SwPageDesc* pDesc = rToFill.FindPageDescByName( sStartingPageDesc, true );
1172 if( pDesc )
1173 rToFill.ChgCurPageDesc( *pDesc );
1175 if(!GotoPage(nEndPage))
1177 Pop(PopMode::DeleteCurrent);
1178 return;
1180 //if the page starts with a table a paragraph has to be inserted before
1181 SwNode *const pTableNode = oSourcePam->GetPointNode().FindTableNode();
1182 if(pTableNode)
1184 //insert a paragraph
1185 StartUndo(SwUndoId::INSERT);
1186 SwNodeIndex aTableIdx( *pTableNode, -1 );
1187 SwPosition aBefore(aTableIdx);
1188 if(GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore ))
1190 SwPaM aTmp(aBefore);
1191 *oSourcePam = aTmp;
1193 EndUndo(SwUndoId::INSERT);
1196 MovePage( GetThisFrame, GetLastSub );
1197 oSourcePam->SetMark();
1198 *oSourcePam->GetMark() = *GetCursor()->GetPoint();
1200 CurrShell aCurr( this );
1202 StartAllAction();
1203 GetDoc()->getIDocumentFieldsAccess().LockExpFields();
1204 SetSelection(*oSourcePam);
1205 // copy the text of the selection
1206 SwEditShell::Copy(rToFill);
1207 oSourcePam.reset(); // delete it because Undo will remove its node!
1209 if(pTableNode)
1211 //remove the inserted paragraph
1212 Undo();
1213 //remove the paragraph in the second doc, too
1214 SwPaM aPara( rToFill.GetDoc()->GetNodes().GetEndOfExtras(), SwNodeOffset(2) ); //DocStart
1215 rToFill.GetDoc()->getIDocumentContentOperations().DelFullPara(aPara);
1217 // now the page bound objects
1218 // additionally copy page bound frames
1219 if( !GetDoc()->GetSpzFrameFormats()->empty() )
1221 // create a draw view if necessary
1222 if( !rToFill.Imp()->GetDrawView() )
1223 rToFill.MakeDrawView();
1225 for(sw::SpzFrameFormat* pCpyFormat: *GetDoc()->GetSpzFrameFormats())
1227 SwFormatAnchor aAnchor( pCpyFormat->GetAnchor() );
1228 if ((RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId()) &&
1229 aAnchor.GetPageNum() >= nStartPage && aAnchor.GetPageNum() <= nEndPage)
1231 aAnchor.SetPageNum( aAnchor.GetPageNum() - nStartPage + 1);
1233 else
1234 continue;
1235 rToFill.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pCpyFormat, aAnchor, true, true );
1238 GetDoc()->getIDocumentFieldsAccess().UnlockExpFields();
1239 GetDoc()->getIDocumentFieldsAccess().UpdateFields(false);
1240 Pop(PopMode::DeleteCurrent);
1241 EndAllAction();
1244 comphelper::OInterfaceContainerHelper3<css::text::XPasteListener>& SwFEShell::GetPasteListeners() { return m_aPasteListeners; }
1246 bool SwFEShell::GetDrawObjGraphic( SotClipboardFormatId nFormat, Graphic& rGrf ) const
1248 OSL_ENSURE( Imp()->HasDrawView(), "GetDrawObjGraphic without DrawView?" );
1249 const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
1250 bool bConvert = true;
1251 if( rMrkList.GetMarkCount() )
1253 if( rMrkList.GetMarkCount() == 1 &&
1254 dynamic_cast< const SwVirtFlyDrawObj* >(rMrkList.GetMark( 0 )->GetMarkedSdrObj()) != nullptr )
1256 // select frame
1257 if( CNT_GRF == GetCntType() )
1259 const Graphic* pGrf( GetGraphic() );
1260 if ( pGrf )
1262 Graphic aGrf( *pGrf );
1263 if( SotClipboardFormatId::GDIMETAFILE == nFormat )
1265 if( GraphicType::Bitmap != aGrf.GetType() )
1267 rGrf = std::move(aGrf);
1268 bConvert = false;
1270 else if( GetWin() )
1272 Size aSz;
1273 Point aPt;
1274 GetGrfSize( aSz );
1276 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1277 pVirtDev->EnableOutput( false );
1279 MapMode aTmp( GetWin()->GetMapMode() );
1280 aTmp.SetOrigin( aPt );
1281 pVirtDev->SetMapMode( aTmp );
1283 GDIMetaFile aMtf;
1284 aMtf.Record( pVirtDev.get() );
1285 aGrf.Draw(*pVirtDev, aPt, aSz);
1286 aMtf.Stop();
1287 aMtf.SetPrefMapMode( aTmp );
1288 aMtf.SetPrefSize( aSz );
1289 rGrf = aMtf;
1292 else if( GraphicType::Bitmap == aGrf.GetType() )
1294 rGrf = std::move(aGrf);
1295 bConvert = false;
1297 else
1299 // Not the original size, but the current one.
1300 // Otherwise it could happen that for vector graphics
1301 // many MB's of memory are allocated.
1302 const Size aSz( GetSelectedFlyFrame()->getFramePrintArea().SSize() );
1303 ScopedVclPtrInstance< VirtualDevice > pVirtDev(*GetWin()->GetOutDev());
1305 MapMode aTmp( MapUnit::MapTwip );
1306 pVirtDev->SetMapMode( aTmp );
1307 if( pVirtDev->SetOutputSize( aSz ) )
1309 aGrf.Draw(*pVirtDev, Point(), aSz);
1310 rGrf = pVirtDev->GetBitmapEx( Point(), aSz );
1312 else
1314 rGrf = std::move(aGrf);
1315 bConvert = false;
1321 else if( SotClipboardFormatId::GDIMETAFILE == nFormat )
1322 rGrf = Imp()->GetDrawView()->GetMarkedObjMetaFile();
1323 else if( SotClipboardFormatId::BITMAP == nFormat || SotClipboardFormatId::PNG == nFormat )
1324 rGrf = Imp()->GetDrawView()->GetMarkedObjBitmapEx();
1326 return bConvert;
1329 // #i50824#
1330 // replace method <lcl_RemoveOleObjsFromSdrModel> by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs>
1331 static void lcl_ConvertSdrOle2ObjsToSdrGrafObjs( SdrModel& _rModel )
1333 for ( sal_uInt16 nPgNum = 0; nPgNum < _rModel.GetPageCount(); ++nPgNum )
1335 // setup object iterator in order to iterate through all objects
1336 // including objects in group objects, but exclusive group objects.
1337 SdrObjListIter aIter(_rModel.GetPage(nPgNum));
1338 while( aIter.IsMore() )
1340 SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( aIter.Next() );
1341 if( pOle2Obj )
1343 // found an ole2 shape
1344 SdrObjList* pObjList = pOle2Obj->getParentSdrObjListFromSdrObject();
1346 // get its graphic
1347 Graphic aGraphic;
1348 pOle2Obj->Connect();
1349 const Graphic* pGraphic = pOle2Obj->GetGraphic();
1350 if( pGraphic )
1351 aGraphic = *pGraphic;
1352 pOle2Obj->Disconnect();
1354 // create new graphic shape with the ole graphic and shape size
1355 rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj(
1356 _rModel,
1357 aGraphic,
1358 pOle2Obj->GetCurrentBoundRect());
1359 // apply layer of ole2 shape at graphic shape
1360 pGraphicObj->SetLayer( pOle2Obj->GetLayer() );
1362 // replace ole2 shape with the new graphic object and delete the ol2 shape
1363 pObjList->ReplaceObject( pGraphicObj.get(), pOle2Obj->GetOrdNum() );
1369 void SwFEShell::Paste( SvStream& rStrm, SwPasteSdr nAction, const Point* pPt )
1371 CurrShell aCurr( this );
1372 StartAllAction();
1373 StartUndo();
1375 std::unique_ptr< FmFormModel > pModel(
1376 new FmFormModel(
1377 nullptr,
1378 GetDoc()->GetDocShell()));
1380 rStrm.Seek(0);
1382 uno::Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( rStrm ) );
1383 SvxDrawingLayerImport( pModel.get(), xInputStream );
1385 if ( !Imp()->HasDrawView() )
1386 Imp()->MakeDrawView();
1388 Point aPos( pPt ? *pPt : GetCharRect().Pos() );
1389 SdrView *pView = Imp()->GetDrawView();
1391 // drop on the existing object: replace object or apply new attributes
1392 if( pModel->GetPageCount() > 0 &&
1393 1 == pModel->GetPage(0)->GetObjCount() &&
1394 1 == pView->GetMarkedObjectList().GetMarkCount() )
1396 // replace a marked 'virtual' drawing object
1397 // by its corresponding 'master' drawing object in the mark list.
1398 SwDrawView::ReplaceMarkedDrawVirtObjs( *pView );
1400 SdrObject* pClpObj = pModel->GetPage(0)->GetObj(0);
1401 SdrObject* pOldObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj();
1402 assert(pOldObj);
1404 if( SwPasteSdr::SetAttr == nAction && dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1405 nAction = SwPasteSdr::Replace;
1407 switch( nAction )
1409 case SwPasteSdr::Replace:
1411 const SwFrameFormat* pFormat(nullptr);
1412 const SwFrame* pAnchor(nullptr);
1413 if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1415 pFormat = FindFrameFormat( pOldObj );
1417 Point aNullPt;
1418 SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrameFormat*>(pFormat)->GetFrame( &aNullPt );
1419 pAnchor = pFlyFrame ? pFlyFrame->GetAnchorFrame() : nullptr;
1421 if (!pAnchor || pAnchor->FindFooterOrHeader())
1423 // if there is a textframe in the header/footer:
1424 // do not replace but insert
1425 nAction = SwPasteSdr::Insert;
1426 break;
1430 rtl::Reference<SdrObject> pNewObj(pClpObj->CloneSdrObject(pOldObj->getSdrModelFromSdrObject()));
1431 tools::Rectangle aOldObjRect( pOldObj->GetCurrentBoundRect() );
1432 Size aOldObjSize( aOldObjRect.GetSize() );
1433 tools::Rectangle aNewRect( pNewObj->GetCurrentBoundRect() );
1434 Size aNewSize( aNewRect.GetSize() );
1436 Fraction aScaleWidth( aOldObjSize.Width(), aNewSize.Width() );
1437 Fraction aScaleHeight( aOldObjSize.Height(), aNewSize.Height());
1438 pNewObj->NbcResize( aNewRect.TopLeft(), aScaleWidth, aScaleHeight);
1440 Point aVec = aOldObjRect.TopLeft() - aNewRect.TopLeft();
1441 pNewObj->NbcMove(Size(aVec.getX(), aVec.getY()));
1443 if( dynamic_cast<const SdrUnoObj*>( pNewObj.get()) != nullptr )
1444 pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() );
1445 else if( dynamic_cast<const SdrUnoObj*>( pOldObj) != nullptr )
1446 pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() );
1447 else
1448 pNewObj->SetLayer( pOldObj->GetLayer() );
1450 if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr )
1452 // store attributes, then set SdrObject
1453 SfxItemSetFixed<RES_SURROUND, RES_ANCHOR> aFrameSet( mxDoc->GetAttrPool() );
1454 aFrameSet.Set( pFormat->GetAttrSet() );
1456 Point aNullPt;
1457 if( pAnchor->IsTextFrame() && static_cast<const SwTextFrame*>(pAnchor)->IsFollow() )
1459 const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnchor);
1460 do {
1461 pTmp = pTmp->FindMaster();
1462 assert(pTmp && "Where's my Master?");
1463 } while( pTmp->IsFollow() );
1464 pAnchor = pTmp;
1466 if( auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pOldObj))
1467 aNullPt = pCaptionObj->GetTailPos();
1468 else
1469 aNullPt = aOldObjRect.TopLeft();
1471 Point aNewAnchor = pAnchor->GetFrameAnchorPos( ::HasWrap( pOldObj ) );
1472 // OD 2004-04-05 #i26791# - direct positioning of Writer
1473 // fly frame object for <SwDoc::Insert(..)>
1474 pNewObj->NbcSetRelativePos( aNullPt - aNewAnchor );
1475 pNewObj->NbcSetAnchorPos( aNewAnchor );
1477 pOldObj->GetOrdNum();
1479 DelSelectedObj();
1481 GetDoc()->getIDocumentContentOperations().InsertDrawObj( *GetCursor(), *pNewObj, aFrameSet );
1483 else
1485 // #i123922# for handling MasterObject and virtual ones correctly, SW
1486 // wants us to call ReplaceObject at the page, but that also
1487 // triggers the same assertion (I tried it), so stay at the view method
1488 pView->ReplaceObjectAtView(pOldObj, *Imp()->GetPageView(), pNewObj.get());
1491 break;
1493 case SwPasteSdr::SetAttr:
1495 SfxItemSet aSet( GetAttrPool() );
1496 const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pClpObj);
1498 if(pSdrGrafObj)
1500 SdrObject* pTarget = nullptr;
1502 if(0 != pView->GetMarkedObjectList().GetMarkCount())
1504 // try to get target (if it's at least one, take first)
1505 SdrMark* pMark = pView->GetMarkedObjectList().GetMark(0);
1507 if(pMark)
1509 pTarget = pMark->GetMarkedSdrObj();
1513 if(pTarget)
1515 // copy ItemSet from target
1516 aSet.Set(pTarget->GetMergedItemSet());
1519 // for SdrGrafObj, use the graphic as fill style argument
1520 const Graphic& rGraphic = pSdrGrafObj->GetGraphic();
1522 if(GraphicType::NONE != rGraphic.GetType() && GraphicType::Default != rGraphic.GetType())
1524 aSet.Put(XFillBitmapItem(OUString(), rGraphic));
1525 aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
1528 else
1530 aSet.Put(pClpObj->GetMergedItemSet());
1533 pView->SetAttributes( aSet );
1535 break;
1537 default:
1538 nAction = SwPasteSdr::Insert;
1539 break;
1542 else
1543 nAction = SwPasteSdr::Insert;
1545 if( SwPasteSdr::Insert == nAction )
1547 ::sw::DrawUndoGuard drawUndoGuard(GetDoc()->GetIDocumentUndoRedo());
1549 bool bDesignMode = pView->IsDesignMode();
1550 if( !bDesignMode )
1551 pView->SetDesignMode();
1553 // #i50824#
1554 // method <lcl_RemoveOleObjsFromSdrModel> replaced by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs>
1555 lcl_ConvertSdrOle2ObjsToSdrGrafObjs(*pModel);
1556 pView->Paste(*pModel, aPos, nullptr, SdrInsertFlags::NONE);
1558 const size_t nCnt = pView->GetMarkedObjectList().GetMarkCount();
1559 if( nCnt )
1561 const Point aNull( 0, 0 );
1562 for( size_t i=0; i < nCnt; ++i )
1564 SdrObject *pObj = pView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj();
1565 pObj->ImpSetAnchorPos( aNull );
1568 pView->SetCurrentObj( SdrObjKind::Group );
1569 if ( nCnt > 1 )
1570 pView->GroupMarked();
1571 SdrObject *pObj = pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
1572 assert(pObj);
1573 if( dynamic_cast<const SdrUnoObj*>( pObj) != nullptr )
1575 pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() );
1576 bDesignMode = true;
1578 else
1579 pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() );
1580 const tools::Rectangle &rSnap = pObj->GetSnapRect();
1581 const Size aDiff( rSnap.GetWidth()/2, rSnap.GetHeight()/2 );
1582 pView->MoveMarkedObj( aDiff );
1583 ImpEndCreate();
1584 if( !bDesignMode )
1585 pView->SetDesignMode( false );
1588 EndUndo();
1589 EndAllAction();
1592 bool SwFEShell::Paste(const Graphic &rGrf, const OUString& rURL)
1594 CurrShell aCurr( this );
1595 SdrObject* pObj = nullptr;
1596 SdrView *pView = Imp()->GetDrawView();
1598 bool bRet = 1 == pView->GetMarkedObjectList().GetMarkCount();
1599 if (bRet)
1601 pObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj();
1602 bRet = pObj->IsClosedObj() && dynamic_cast<const SdrOle2Obj*>( pObj) == nullptr;
1605 if( bRet && pObj )
1607 // #i123922# added code to handle the two cases of SdrGrafObj and a fillable, non-
1608 // OLE object in focus
1609 SdrObject* pResult = pObj;
1611 if(auto pGrafObj = dynamic_cast< SdrGrafObj* >(pObj))
1613 rtl::Reference<SdrGrafObj> pNewGrafObj = SdrObject::Clone(*pGrafObj, pGrafObj->getSdrModelFromSdrObject());
1615 pNewGrafObj->SetGraphic(rGrf);
1617 // #i123922# for handling MasterObject and virtual ones correctly, SW
1618 // wants us to call ReplaceObject at the page, but that also
1619 // triggers the same assertion (I tried it), so stay at the view method
1620 pView->ReplaceObjectAtView(pObj, *pView->GetSdrPageView(), pNewGrafObj.get());
1622 // set in all cases - the Clone() will have copied an existing link (!)
1623 pNewGrafObj->SetGraphicLink(rURL);
1625 pResult = pNewGrafObj.get();
1627 else
1629 pView->AddUndo(std::make_unique<SdrUndoAttrObj>(*pObj));
1631 SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(pView->GetModel().GetItemPool());
1633 aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
1634 aSet.Put(XFillBitmapItem(OUString(), rGrf));
1635 pObj->SetMergedItemSetAndBroadcast(aSet);
1638 // we are done; mark the modified/new object
1639 pView->MarkObj(pResult, pView->GetSdrPageView());
1642 return bRet;
1645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */