diff options
Diffstat (limited to 'sw/source/core/frmedt/fecopy.cxx')
-rw-r--r-- | sw/source/core/frmedt/fecopy.cxx | 1629 |
1 files changed, 1629 insertions, 0 deletions
diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx new file mode 100644 index 000000000..591451480 --- /dev/null +++ b/sw/source/core/frmedt/fecopy.cxx @@ -0,0 +1,1629 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <hintids.hxx> + +#include <vcl/graph.hxx> +#include <sot/formats.hxx> +#include <svx/xfillit0.hxx> +#include <svx/svdocapt.hxx> +#include <svx/svdouno.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdogrp.hxx> +#include <svx/svdoole2.hxx> +#include <svx/fmmodel.hxx> +#include <svx/unomodel.hxx> +#include <svx/svditer.hxx> +#include <svx/svdograf.hxx> +#include <tools/stream.hxx> +#include <unotools/streamwrap.hxx> +#include <osl/diagnose.h> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <fmtornt.hxx> +#include <fmtflcnt.hxx> +#include <frmfmt.hxx> +#include <txtfrm.hxx> +#include <txtflcnt.hxx> +#include <fesh.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentRedlineAccess.hxx> +#include <DocumentFieldsManager.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <rootfrm.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <tblsel.hxx> +#include <swtable.hxx> +#include <flyfrm.hxx> +#include <pagefrm.hxx> +#include <fldbas.hxx> +#include <swundo.hxx> +#include <viewimp.hxx> +#include <dview.hxx> +#include <dcontact.hxx> +#include <dflyobj.hxx> +#include <docsh.hxx> +#include <pagedesc.hxx> +#include <mvsave.hxx> +#include <textboxhelper.hxx> +#include <frameformats.hxx> +#include <vcl/virdev.hxx> +#include <svx/svdundo.hxx> + +using namespace ::com::sun::star; + +// Copy for the internal clipboard. Copies all selections to the clipboard. +void SwFEShell::Copy( SwDoc& rClpDoc, const OUString* pNewClpText ) +{ + rClpDoc.GetIDocumentUndoRedo().DoUndo(false); // always false! + + // delete content if ClpDocument contains content + SwNodeIndex aSttIdx( rClpDoc.GetNodes().GetEndOfExtras(), 2 ); + SwNodeIndex aEndNdIdx( *aSttIdx.GetNode().EndOfSectionNode() ); + SwTextNode* pTextNd = aSttIdx.GetNode().GetTextNode(); + if (!pTextNd || !pTextNd->GetText().isEmpty() || + aSttIdx.GetIndex()+1 != rClpDoc.GetNodes().GetEndOfContent().GetIndex() ) + { + rClpDoc.GetNodes().Delete( aSttIdx, + rClpDoc.GetNodes().GetEndOfContent().GetIndex() - aSttIdx.GetIndex() ); + pTextNd = rClpDoc.GetNodes().MakeTextNode( aSttIdx, + rClpDoc.GetDfltTextFormatColl() ); + --aSttIdx; + } + + // also delete surrounding FlyFrames if any + for( const auto pFly : *rClpDoc.GetSpzFrameFormats() ) + { + SwFormatAnchor const*const pAnchor = &pFly->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetContentAnchor(); + if (pAPos && + ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) && + aSttIdx <= pAPos->nNode && pAPos->nNode <= aEndNdIdx ) + { + rClpDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFly ); + } + } + + rClpDoc.GetDocumentFieldsManager().GCFieldTypes(); // delete the FieldTypes + + // if a string was passed, copy it to the clipboard- + // document. Then also the Calculator can use the internal + // clipboard + if( pNewClpText ) + { + pTextNd->InsertText( *pNewClpText, SwIndex( pTextNd ) ); + return; // that's it + } + + rClpDoc.getIDocumentFieldsAccess().LockExpFields(); + rClpDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::DeleteRedlines ); + + // do we want to copy a FlyFrame? + if( IsFrameSelected() ) + { + // get the FlyFormat + SwFlyFrame* pFly = GetSelectedFlyFrame(); + SwFrameFormat* pFlyFormat = pFly->GetFormat(); + SwFormatAnchor aAnchor( pFlyFormat->GetAnchor() ); + + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + SwPosition aPos( aSttIdx ); + if ( RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId() ) + { + aPos.nContent.Assign( pTextNd, 0 ); + } + aAnchor.SetAnchor( &aPos ); + } + pFlyFormat = rClpDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFlyFormat, aAnchor, true, true ); + + // assure the "RootFormat" is the first element in Spz-Array + // (if necessary Flys were copied in Flys) + SwFrameFormats& rSpzFrameFormats = *rClpDoc.GetSpzFrameFormats(); + if( rSpzFrameFormats[ 0 ] != pFlyFormat ) + { +#ifndef NDEBUG + bool inserted = +#endif + rSpzFrameFormats.newDefault( pFlyFormat ); + assert( !inserted && "Fly not contained in Spz-Array" ); + } + + if ( RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId() ) + { + // JP 13.02.99 Bug 61863: if a frameselection is passed to the + // clipboard, it should be found at pasting. Therefore + // the copied TextAttribut should be removed in the node + // otherwise it will be recognised as TextSelektion + const SwIndex& rIdx = pFlyFormat->GetAnchor().GetContentAnchor()->nContent; + SwTextFlyCnt *const pTextFly = static_cast<SwTextFlyCnt *>( + pTextNd->GetTextAttrForCharAt( + rIdx.GetIndex(), RES_TXTATR_FLYCNT)); + if( pTextFly ) + { + const_cast<SwFormatFlyCnt&>(pTextFly->GetFlyCnt()).SetFlyFormat(); + pTextNd->EraseText( rIdx, 1 ); + } + } + } + else if ( IsObjSelected() ) + { + SwPosition aPos( aSttIdx, SwIndex( pTextNd, 0 )); + const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); + for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i ) + { + SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); + + if( Imp()->GetDrawView()->IsGroupEntered() || + ( !pObj->GetUserCall() && pObj->getParentSdrObjectFromSdrObject()) ) + { + SfxItemSet aSet( rClpDoc.GetAttrPool(), aFrameFormatSetRange ); + + SwFormatAnchor aAnchor( RndStdIds::FLY_AT_PARA ); + aAnchor.SetAnchor( &aPos ); + aSet.Put( aAnchor ); + + SdrObject *const pNew = + rClpDoc.CloneSdrObj( *pObj ); + + SwPaM aTemp(aPos); + rClpDoc.getIDocumentContentOperations().InsertDrawObj(aTemp, *pNew, aSet ); + } + else + { + SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj )); + SwFrameFormat *pFormat = pContact->GetFormat(); + SwFormatAnchor aAnchor( pFormat->GetAnchor() ); + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + aAnchor.SetAnchor( &aPos ); + } + + rClpDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true ); + } + } + } + else + CopySelToDoc(rClpDoc); // copy the selections + + rClpDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE ); + rClpDoc.getIDocumentFieldsAccess().UnlockExpFields(); + if( !rClpDoc.getIDocumentFieldsAccess().IsExpFieldsLocked() ) + rClpDoc.getIDocumentFieldsAccess().UpdateExpFields(nullptr, true); +} + +static const Point &lcl_FindBasePos( const SwFrame *pFrame, const Point &rPt ) +{ + const SwFrame *pF = pFrame; + while ( pF && !pF->getFrameArea().Contains( rPt ) ) + { + if ( pF->IsContentFrame() ) + pF = static_cast<const SwContentFrame*>(pF)->GetFollow(); + else + pF = nullptr; + } + if ( pF ) + return pF->getFrameArea().Pos(); + else + return pFrame->getFrameArea().Pos(); +} + +static bool lcl_SetAnchor( const SwPosition& rPos, const SwNode& rNd, SwFlyFrame const * pFly, + const Point& rInsPt, SwFEShell const & rDestShell, SwFormatAnchor& rAnchor, + Point& rNewPos, bool bCheckFlyRecur ) +{ + bool bRet = true; + rAnchor.SetAnchor( &rPos ); + std::pair<Point, bool> const tmp(rInsPt, false); + SwContentFrame *const pTmpFrame = rNd.GetContentNode()->getLayoutFrame( + rDestShell.GetLayout(), nullptr, &tmp); + SwFlyFrame *pTmpFly = pTmpFrame->FindFlyFrame(); + if( pTmpFly && bCheckFlyRecur && pFly->IsUpperOf( *pTmpFly ) ) + { + bRet = false; + } + else if ( RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId() ) + { + if( pTmpFly ) + { + const SwNodeIndex& rIdx = *pTmpFly->GetFormat()->GetContent().GetContentIdx(); + SwPosition aPos( rIdx ); + rAnchor.SetAnchor( &aPos ); + rNewPos = pTmpFly->getFrameArea().Pos(); + } + else + { + rAnchor.SetType( RndStdIds::FLY_AT_PAGE ); + rAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) ); + const SwFrame *pPg = pTmpFrame->FindPageFrame(); + rNewPos = pPg->getFrameArea().Pos(); + } + } + else + rNewPos = ::lcl_FindBasePos( pTmpFrame, rInsPt ); + return bRet; +} + +bool SwFEShell::CopyDrawSel( SwFEShell& rDestShell, const Point& rSttPt, + const Point& rInsPt, bool bIsMove, bool bSelectInsert ) +{ + bool bRet = true; + + // The list should be copied, because below new objects will be selected + const SdrMarkList aMrkList( Imp()->GetDrawView()->GetMarkedObjectList() ); + const size_t nMarkCount = aMrkList.GetMarkCount(); + if( !rDestShell.Imp()->GetDrawView() ) + // should create it now + rDestShell.MakeDrawView(); + else if( bSelectInsert ) + rDestShell.Imp()->GetDrawView()->UnmarkAll(); + + SdrPageView *pDestPgView = rDestShell.Imp()->GetPageView(), + *pSrcPgView = Imp()->GetPageView(); + SwDrawView *pDestDrwView = rDestShell.Imp()->GetDrawView(), + *pSrcDrwView = Imp()->GetDrawView(); + SwDoc* pDestDoc = rDestShell.GetDoc(); + + Size aSiz( rInsPt.X() - rSttPt.X(), rInsPt.Y() - rSttPt.Y() ); + for( size_t i = 0; i < nMarkCount; ++i ) + { + SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj(); + + SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall( pObj )); + SwFrameFormat *pFormat = pContact->GetFormat(); + const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); + + bool bInsWithFormat = true; + + if( pDestDrwView->IsGroupEntered() ) + { + // insert into the group, when it belongs to an entered group + // or when the object is not anchored as a character + if( pSrcDrwView->IsGroupEntered() || + (RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) ) + + { + SdrObject* pNew = pDestDoc->CloneSdrObj( *pObj, bIsMove && + GetDoc() == pDestDoc, false ); + pNew->NbcMove( aSiz ); + pDestDrwView->InsertObjectAtView( pNew, *pDestPgView ); + bInsWithFormat = false; + } + } + + if( bInsWithFormat ) + { + SwFormatAnchor aAnchor( rAnchor ); + Point aNewAnch; + + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + if ( this == &rDestShell ) + { + // same shell? Then request the position + // from the passed DocumentPosition + SwPosition aPos( *GetCursor()->GetPoint() ); + Point aPt( rInsPt ); + aPt -= rSttPt - pObj->GetSnapRect().TopLeft(); + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState ); + const SwNode *pNd; + if( (pNd = &aPos.nNode.GetNode())->IsNoTextNode() ) + bRet = false; + else + bRet = ::lcl_SetAnchor( aPos, *pNd, nullptr, rInsPt, + rDestShell, aAnchor, aNewAnch, false ); + } + else + { + SwPaM *pCursor = rDestShell.GetCursor(); + if( pCursor->GetNode().IsNoTextNode() ) + bRet = false; + else + bRet = ::lcl_SetAnchor( *pCursor->GetPoint(), + pCursor->GetNode(), nullptr, rInsPt, + rDestShell, aAnchor, + aNewAnch, false ); + } + } + else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() ) + { + aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) ); + const SwRootFrame* pTmpRoot = rDestShell.GetLayout(); + const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true ); + if ( pPg ) + aNewAnch = pPg->getFrameArea().Pos(); + } + + if( bRet ) + { + if( pSrcDrwView->IsGroupEntered() || + ( !pObj->GetUserCall() && pObj->getParentSdrObjectFromSdrObject()) ) + { + SfxItemSet aSet( pDestDoc->GetAttrPool(),aFrameFormatSetRange); + aSet.Put( aAnchor ); + SdrObject* pNew = pDestDoc->CloneSdrObj( *pObj, bIsMove && + GetDoc() == pDestDoc ); + pFormat = pDestDoc->getIDocumentContentOperations().InsertDrawObj( *rDestShell.GetCursor(), *pNew, aSet ); + } + else + pFormat = pDestDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, true, true ); + + // Can be 0, as Draws are not allowed in Headers/Footers + if ( pFormat ) + { + // #tdf33692 - drawing object has to be made visible on ctrl+drag copy. + pFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING)); + SdrObject* pNew = pFormat->FindSdrObject(); + if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() ) + { + Point aPos( rInsPt ); + aPos -= aNewAnch; + aPos -= rSttPt - pObj->GetSnapRect().TopLeft(); + // OD 2004-04-05 #i26791# - change attributes instead of + // direct positioning + pFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(), text::HoriOrientation::NONE, text::RelOrientation::FRAME ) ); + pFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(), text::VertOrientation::NONE, text::RelOrientation::FRAME ) ); + // #i47455# - notify draw frame format + // that position attributes are already set. + if (SwDrawFrameFormat *pDrawFormat = dynamic_cast<SwDrawFrameFormat*>(pFormat)) + pDrawFormat->PosAttrSet(); + } + if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, pObj)) + { + SwTextBoxHelper::syncFlyFrameAttr(*pFormat, pFormat->GetAttrSet(), pObj); + } + + if( bSelectInsert ) + pDestDrwView->MarkObj( pNew, pDestPgView ); + } + } + } + } + + if ( bIsMove && bRet ) + { + if( &rDestShell == this ) + { + const SdrMarkList aList( pSrcDrwView->GetMarkedObjectList() ); + pSrcDrwView->UnmarkAll(); + + for ( size_t i = 0, nMrkCnt = aMrkList.GetMarkCount(); i < nMrkCnt; ++i ) + { + SdrObject *pObj = aMrkList.GetMark( i )->GetMarkedSdrObj(); + pSrcDrwView->MarkObj( pObj, pSrcPgView ); + } + DelSelectedObj(); + for ( size_t i = 0, nMrkCnt = aList.GetMarkCount(); i < nMrkCnt; ++i ) + { + SdrObject *pObj = aList.GetMark( i )->GetMarkedSdrObj(); + pSrcDrwView->MarkObj( pObj, pSrcPgView ); + } + } + else + DelSelectedObj(); + } + + return bRet; +} + +bool SwFEShell::Copy( SwFEShell& rDestShell, const Point& rSttPt, + const Point& rInsPt, bool bIsMove, bool bSelectInsert ) +{ + bool bRet = false; + + OSL_ENSURE( this == &rDestShell || !rDestShell.IsObjSelected(), + "Dest-Shell cannot be in Obj-Mode" ); + + CurrShell aCurr( &rDestShell ); + + rDestShell.StartAllAction(); + rDestShell.GetDoc()->getIDocumentFieldsAccess().LockExpFields(); + + // Shift references + bool bCopyIsMove = mxDoc->IsCopyIsMove(); + if( bIsMove ) + // set a flag in Doc, handled in TextNodes + mxDoc->SetCopyIsMove( true ); + + RedlineFlags eOldRedlMode = rDestShell.GetDoc()->getIDocumentRedlineAccess().GetRedlineFlags(); + rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode | RedlineFlags::DeleteRedlines ); + + // If there are table formulas in the area, then display the table first + // so that the table formula can calculate a new value first + // (individual boxes in the area are retrieved via the layout) + SwFieldType* pTableFieldTyp = rDestShell.GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table ); + + if( IsFrameSelected() ) + { + SwFlyFrame* pFly = GetSelectedFlyFrame(); + SwFrameFormat* pFlyFormat = pFly->GetFormat(); + SwFormatAnchor aAnchor( pFlyFormat->GetAnchor() ); + bRet = true; + Point aNewAnch; + + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + if ( this == &rDestShell ) + { + // same shell? Then request the position + // from the passed DocumentPosition + SwPosition aPos( *GetCursor()->GetPoint() ); + Point aPt( rInsPt ); + aPt -= rSttPt - pFly->getFrameArea().Pos(); + SwCursorMoveState aState( CursorMoveState::SetOnlyText ); + GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aState ); + const SwNode *pNd; + if( (pNd = &aPos.nNode.GetNode())->IsNoTextNode() ) + bRet = false; + else + { + // do not copy in itself + const SwNodeIndex *pTmp = pFlyFormat->GetContent().GetContentIdx(); + if ( aPos.nNode > *pTmp && aPos.nNode < + pTmp->GetNode().EndOfSectionIndex() ) + { + bRet = false; + } + else + bRet = ::lcl_SetAnchor( aPos, *pNd, pFly, rInsPt, + rDestShell, aAnchor, aNewAnch, true ); + } + } + else + { + const SwPaM *pCursor = rDestShell.GetCursor(); + if( pCursor->GetNode().IsNoTextNode() ) + bRet = false; + else + bRet = ::lcl_SetAnchor( *pCursor->GetPoint(), pCursor->GetNode(), + pFly, rInsPt, rDestShell, aAnchor, + aNewAnch, GetDoc() == rDestShell.GetDoc()); + } + } + else if ( RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId() ) + { + aAnchor.SetPageNum( rDestShell.GetPageNumber( rInsPt ) ); + const SwRootFrame* pTmpRoot = rDestShell.GetLayout(); + const SwFrame* pPg = pTmpRoot->GetPageAtPos( rInsPt, nullptr, true ); + if ( pPg ) + aNewAnch = pPg->getFrameArea().Pos(); + } + else { + OSL_ENSURE( false, "what anchor is it?" ); + } + + if( bRet ) + { + SwFrameFormat *pOldFormat = pFlyFormat; + pFlyFormat = rDestShell.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pFlyFormat, aAnchor, true, true ); + + if ( RndStdIds::FLY_AS_CHAR != aAnchor.GetAnchorId() ) + { + Point aPos( rInsPt ); + aPos -= aNewAnch; + aPos -= rSttPt - pFly->getFrameArea().Pos(); + pFlyFormat->SetFormatAttr( SwFormatHoriOrient( aPos.getX(),text::HoriOrientation::NONE, text::RelOrientation::FRAME ) ); + pFlyFormat->SetFormatAttr( SwFormatVertOrient( aPos.getY(),text::VertOrientation::NONE, text::RelOrientation::FRAME ) ); + } + + const Point aPt( rDestShell.GetCursorDocPos() ); + + if( bIsMove ) + GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pOldFormat ); + + // only select if it can be shifted/copied in the same shell + if( bSelectInsert ) + { + SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pFlyFormat)->GetFrame( &aPt ); + if( pFlyFrame ) + { + //JP 12.05.98: should this be in SelectFlyFrame??? + rDestShell.Imp()->GetDrawView()->UnmarkAll(); + rDestShell.SelectFlyFrame( *pFlyFrame ); + } + } + + if (this != &rDestShell && !rDestShell.HasShellFocus()) + rDestShell.Imp()->GetDrawView()->hideMarkHandles(); + } + } + else if ( IsObjSelected() ) + bRet = CopyDrawSel( rDestShell, rSttPt, rInsPt, bIsMove, bSelectInsert ); + else if( IsTableMode() ) + { + // Copy parts from a table: create a table with the same + // width as the original and copy the selected boxes. + // Sizes will be corrected by percentage. + + // find boxes via the layout + SwSelBoxes aBoxes; + GetTableSel( *this, aBoxes ); + SwTableNode const*const pTableNd( + aBoxes.empty() ? nullptr : aBoxes[0]->GetSttNd()->FindTableNode()); + if (nullptr != pTableNd) + { + std::unique_ptr<SwPosition> pDstPos; + if( this == &rDestShell ) + { + // same shell? Then create new Cursor at the + // DocumentPosition passed + pDstPos.reset(new SwPosition( *GetCursor()->GetPoint() )); + Point aPt( rInsPt ); + GetLayout()->GetModelPositionForViewPoint( pDstPos.get(), aPt ); + if( !pDstPos->nNode.GetNode().IsNoTextNode() ) + bRet = true; + } + else if( !rDestShell.GetCursor()->GetNode().IsNoTextNode() ) + { + pDstPos.reset(new SwPosition( *rDestShell.GetCursor()->GetPoint() )); + bRet = true; + } + + if( bRet ) + { + if( GetDoc() == rDestShell.GetDoc() ) + ParkTableCursor(); + + bRet = rDestShell.GetDoc()->InsCopyOfTable( *pDstPos, aBoxes,nullptr, + bIsMove && this == &rDestShell && + aBoxes.size() == pTableNd->GetTable(). + GetTabSortBoxes().size(), + this != &rDestShell ); + + if( this != &rDestShell ) + *rDestShell.GetCursor()->GetPoint() = *pDstPos; + + // create all parked Cursor? + if( GetDoc() == rDestShell.GetDoc() ) + GetCursor(); + + // JP 16.04.99: Bug 64908 - Set InsPos, to assure the parked + // Cursor is positioned at the insert position + if( this == &rDestShell ) + GetCursorDocPos() = rInsPt; + } + } + } + else + { + bRet = true; + if( this == &rDestShell ) + { + // same shell? then request the position + // at the passed document position + SwPosition aPos( *GetCursor()->GetPoint() ); + Point aPt( rInsPt ); + GetLayout()->GetModelPositionForViewPoint( &aPos, aPt ); + bRet = !aPos.nNode.GetNode().IsNoTextNode(); + } + else if( rDestShell.GetCursor()->GetNode().IsNoTextNode() ) + bRet = false; + + if( bRet ) + bRet = SwEditShell::Copy( rDestShell ); + } + + rDestShell.GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOldRedlMode ); + mxDoc->SetCopyIsMove( bCopyIsMove ); + + // have new table formulas been inserted? + if( pTableFieldTyp->HasWriterListeners() ) + { + // finish old actions: the table frames are created and + // a selection can be made + sal_uInt16 nActCnt; + for( nActCnt = 0; rDestShell.ActionPend(); ++nActCnt ) + rDestShell.EndAllAction(); + + for( ; nActCnt; --nActCnt ) + rDestShell.StartAllAction(); + } + rDestShell.GetDoc()->getIDocumentFieldsAccess().UnlockExpFields(); + rDestShell.GetDoc()->getIDocumentFieldsAccess().UpdateFields(false); + + rDestShell.EndAllAction(); + return bRet; +} + +// Paste for the internal clipboard. Copy the content of the clipboard +// in the document +namespace { + typedef std::shared_ptr<SwPaM> PaMPtr; + typedef std::shared_ptr<SwPosition> PositionPtr; + typedef std::pair< PaMPtr, PositionPtr > Insertion; + + bool PamHasSelection(const SwPaM& rPaM) + { + return rPaM.HasMark() && *rPaM.GetPoint() != *rPaM.GetMark(); + } + + /// Is pFormat anchored in a fly frame which has an associated draw format? + bool IsInTextBox(const SwFrameFormat* pFormat) + { + const SwFormatAnchor& rAnchor = pFormat->GetAnchor(); + const SwPosition* pPosition = rAnchor.GetContentAnchor(); + if (!pPosition) + { + return false; + } + + const SwStartNode* pFlyNode = pPosition->nNode.GetNode().FindFlyStartNode(); + if (!pFlyNode) + { + return false; + } + + for ( const auto& pSpzFormat : *pFormat->GetDoc()->GetSpzFrameFormats() ) + { + if (pSpzFormat->Which() != RES_FLYFRMFMT) + { + continue; + } + + const SwNodeIndex* pIdx = pSpzFormat->GetContent().GetContentIdx(); + if (!pIdx || pFlyNode != &pIdx->GetNode()) + { + continue; + } + + return SwTextBoxHelper::isTextBox(pSpzFormat, RES_FLYFRMFMT); + } + + return false; + } +} + +namespace { + SwFrameFormat* lcl_PasteFlyOrDrawFormat(SwPaM& rPaM, SwFrameFormat* pCpyFormat, SwFEShell& rSh) + { + auto& rImp = *rSh.Imp(); + auto& rDoc = *rSh.GetDoc(); + auto& rDrawView = *rImp.GetDrawView(); + if(rDrawView.IsGroupEntered() && + RES_DRAWFRMFMT == pCpyFormat->Which() && + (RndStdIds::FLY_AS_CHAR != pCpyFormat->GetAnchor().GetAnchorId())) + { + const SdrObject* pSdrObj = pCpyFormat->FindSdrObject(); + if(pSdrObj) + { + SdrObject* pNew = rDoc.CloneSdrObj(*pSdrObj, false, false); + // Insert object sets any anchor position to 0. + // Therefore we calculate the absolute position here + // and after the insert the anchor of the object + // is set to the anchor of the group object. + tools::Rectangle aSnapRect = pNew->GetSnapRect(); + if(pNew->GetAnchorPos().X() || pNew->GetAnchorPos().Y()) + { + const Point aPoint(0, 0); + // OD 2004-04-05 #i26791# - direct drawing object + // positioning for group members + pNew->NbcSetAnchorPos(aPoint); + pNew->NbcSetSnapRect(aSnapRect); + } + + rDrawView.InsertObjectAtView(pNew, *rImp.GetPageView()); + + Point aGrpAnchor(0, 0); + SdrObjList* pList = pNew->getParentSdrObjListFromSdrObject(); + if(pList) + { + SdrObjGroup* pOwner(dynamic_cast<SdrObjGroup*>(pList->getSdrObjectFromSdrObjList())); + + if(nullptr != pOwner) + aGrpAnchor = pOwner->GetAnchorPos(); + } + + // OD 2004-04-05 #i26791# - direct drawing object + // positioning for group members + pNew->NbcSetAnchorPos(aGrpAnchor); + pNew->SetSnapRect(aSnapRect); + return nullptr; + } + } + SwFormatAnchor aAnchor(pCpyFormat->GetAnchor()); + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + SwPosition* pPos = rPaM.GetPoint(); + // allow shapes (no controls) in header/footer + if(RES_DRAWFRMFMT == pCpyFormat->Which() && rDoc.IsInHeaderFooter(pPos->nNode)) + { + const SdrObject *pCpyObj = pCpyFormat->FindSdrObject(); + if(pCpyObj && CheckControlLayer(pCpyObj)) + return nullptr; + } + else if(pCpyFormat->Which() == RES_FLYFRMFMT && IsInTextBox(pCpyFormat)) + { + // This is a fly frame which is anchored in a TextBox, ignore it as + // it's already copied as part of copying the content of the + // TextBox. + return nullptr; + } + // Ignore TextBoxes, they are already handled in sw::DocumentLayoutManager::CopyLayoutFormat(). + if(SwTextBoxHelper::isTextBox(pCpyFormat, RES_FLYFRMFMT)) + return nullptr; + aAnchor.SetAnchor(pPos); + } + else if(RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum(rSh.GetPhyPageNum()); + } + else if(RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId()) + { + Point aPt; + (void)lcl_SetAnchor(*rPaM.GetPoint(), rPaM.GetNode(), nullptr, aPt, rSh, aAnchor, aPt, false); + } + + SwFrameFormat* pNew = rDoc.getIDocumentLayoutAccess().CopyLayoutFormat(*pCpyFormat, aAnchor, true, true); + return pNew; + } + + void lcl_SelectFlyFormat(SwFrameFormat *const pNew, SwFEShell& rSh) + { + if(!pNew) + return; + switch(pNew->Which()) + { + case RES_FLYFRMFMT: + { + assert(dynamic_cast<SwFlyFrameFormat*>(pNew)); + const Point aPt(rSh.GetCursorDocPos()); + SwFlyFrame* pFlyFrame = static_cast<SwFlyFrameFormat*>(pNew)->GetFrame(&aPt); + if(pFlyFrame) + rSh.SelectFlyFrame(*pFlyFrame); + break; + } + case RES_DRAWFRMFMT: + { + auto& rDrawView = *rSh.Imp()->GetDrawView(); + assert(dynamic_cast<SwDrawFrameFormat*>(pNew)); + SwDrawFrameFormat* pDrawFormat = static_cast<SwDrawFrameFormat*>(pNew); + // #i52780# - drawing object has to be made visible on paste. + pDrawFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREPPASTING)); + SdrObject* pObj = pDrawFormat->FindSdrObject(); + rDrawView.MarkObj(pObj, rDrawView.GetSdrPageView()); + // #i47455# - notify draw frame format + // that position attributes are already set. + pDrawFormat->PosAttrSet(); + break; + } + default: + SAL_WARN("sw.core", "unknown fly type"); + } + } +} + +bool SwFEShell::Paste(SwDoc& rClpDoc, bool bNestedTable) +{ + CurrShell aCurr( this ); + // then till end of the nodes array + SwNodeIndex aIdx( rClpDoc.GetNodes().GetEndOfExtras(), 2 ); + // select content section, whatever it may contain + SwPaM aCpyPam(aIdx, SwNodeIndex(rClpDoc.GetNodes().GetEndOfContent(), -1)); + if (SwContentNode *const pAtEnd = aCpyPam.GetNode(true).GetContentNode()) + { + pAtEnd->MakeEndIndex(&aCpyPam.GetPoint()->nContent); + } + + // If there are table formulas in the area, then display the table first + // so that the table formula can calculate a new value first + // (individual boxes in the area are retrieved via the layout) + SwFieldType* pTableFieldTyp = GetDoc()->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::Table ); + + SwTableNode *const pSrcNd = aCpyPam.GetNode(false).GetTableNode(); + + bool bRet = true; + StartAllAction(); + GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::INSGLOSSARY, nullptr ); + GetDoc()->getIDocumentFieldsAccess().LockExpFields(); + + // When the clipboard content has been created by a rectangular selection + // the pasting is more sophisticated: + // every paragraph will be inserted into another position. + // The first positions are given by the actual cursor ring, + // if there are more text portions to insert than cursor in this ring, + // the additional insert positions will be created by moving the last + // cursor position into the next line (like pressing the cursor down key) + if( rClpDoc.IsColumnSelection() && !IsTableMode() ) + { + // Creation of the list of insert positions + std::vector< Insertion > aCopyVector; + // The number of text portions of the rectangular selection + const SwNodeOffset nSelCount = aCpyPam.GetPoint()->nNode.GetIndex() + - aCpyPam.GetMark()->nNode.GetIndex(); + SwNodeOffset nCount = nSelCount; + SwNodeIndex aClpIdx( aIdx ); + SwPaM* pStartCursor = GetCursor(); + SwPaM* pCurrCursor = pStartCursor; + SwNodeOffset nCursorCount( pStartCursor->GetRingContainer().size() ); + // If the target selection is a multi-selection, often the last and first + // cursor of the ring points to identical document positions. Then + // we should avoid double insertion of text portions... + while( nCursorCount > SwNodeOffset(1) && *pCurrCursor->GetPoint() == + *(pCurrCursor->GetPrev()->GetPoint()) ) + { + --nCursorCount; + pCurrCursor = pCurrCursor->GetNext(); + pStartCursor = pCurrCursor; + } + SwPosition aStartPos( *pStartCursor->GetPoint() ); + SwPosition aInsertPos( aStartPos ); // first insertion position + bool bCompletePara = false; + sal_uInt16 nMove = 0; + while( nCount ) + { + --nCount; + OSL_ENSURE( aIdx.GetNode().GetContentNode(), "Who filled the clipboard?!" ); + if( aIdx.GetNode().GetContentNode() ) // robust + { + Insertion aInsertion( std::make_shared<SwPaM>( aIdx ), + std::make_shared<SwPosition>( aInsertPos ) ); + ++aIdx; + aInsertion.first->SetMark(); + if( pStartCursor == pCurrCursor->GetNext() ) + { // Now we have to look for insertion positions... + if( !nMove ) // Annotate the last given insert position + aStartPos = aInsertPos; + SwCursor aCursor( aStartPos, nullptr); + // Check if we find another insert position by moving + // down the last given position + if (aCursor.UpDown(false, ++nMove, nullptr, 0, *GetLayout())) + aInsertPos = *aCursor.GetPoint(); + else // if there is no paragraph we have to create it + bCompletePara = nCount > SwNodeOffset(0); + nCursorCount = SwNodeOffset(0); + } + else // as long as we find more insert positions in the cursor ring + { // we'll take them + pCurrCursor = pCurrCursor->GetNext(); + aInsertPos = *pCurrCursor->GetPoint(); + --nCursorCount; + } + // If there are no more paragraphs e.g. at the end of a document, + // we insert complete paragraphs instead of text portions + if( bCompletePara ) + aInsertion.first->GetPoint()->nNode = aIdx; + else + aInsertion.first->GetPoint()->nContent = + aInsertion.first->GetContentNode()->Len(); + aCopyVector.push_back( aInsertion ); + } + // If there are no text portions left but there are some more + // cursor positions to fill we have to restart with the first + // text portion + if( !nCount && nCursorCount ) + { + nCount = min( nSelCount, nCursorCount ); + aIdx = aClpIdx; // Start of clipboard content + } + } + for (auto const& item : aCopyVector) + { + SwPosition& rInsPos = *item.second; + SwPaM& rCopy = *item.first; + const SwStartNode* pBoxNd = rInsPos.nNode.GetNode().FindTableBoxStartNode(); + if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() - pBoxNd->GetIndex() && + rCopy.GetPoint()->nNode != rCopy.GetMark()->nNode ) + { + // if more than one node will be copied into a cell + // the box attributes have to be removed + GetDoc()->ClearBoxNumAttrs( rInsPos.nNode ); + } + { + SwNodeIndex aIndexBefore(rInsPos.nNode); + --aIndexBefore; + rClpDoc.getIDocumentContentOperations().CopyRange(rCopy, rInsPos, SwCopyFlags::CheckPosInFly); + { + ++aIndexBefore; + SwPaM aPaM(SwPosition(aIndexBefore), + SwPosition(rInsPos.nNode)); + aPaM.GetDoc().MakeUniqueNumRules(aPaM); + } + } + SaveTableBoxContent( &rInsPos ); + } + } + else + { + bool bDelTable = true; + + for(SwPaM& rPaM : GetCursor()->GetRingContainer()) + { + + SwTableNode *const pDestNd(GetDoc()->IsIdxInTable(rPaM.GetPoint()->nNode)); + if (pSrcNd && nullptr != pDestNd && + // not a forced nested table insertion + !bNestedTable && + // Heuristics to allow copying table rows or nesting tables without + // using Edit -> Paste Special -> Paste as Nested Table: + // Using table cursor, or if the text selection starts in the + // first paragraph, or if there is no selection and the text cursor + // is there in the first paragraph, overwrite content of the cell(s) + // (else insert a nested table later, i.e. if nothing selected and + // the cursor is not in the first paragraph, or the selected text + // doesn't contain the first paragraph of the cell) + rPaM.GetNode().GetIndex() == rPaM.GetNode().FindTableBoxStartNode()->GetIndex() + 1) + { + SwPosition aDestPos( *rPaM.GetPoint() ); + + bool bParkTableCursor = false; + const SwStartNode* pSttNd = rPaM.GetNode().FindTableBoxStartNode(); + + // TABLE IN TABLE: copy table in table + // search boxes via the layout + SwSelBoxes aBoxes; + if( IsTableMode() ) // table selection? + { + GetTableSel( *this, aBoxes ); + ParkTableCursor(); + bParkTableCursor = true; + } + else if( !PamHasSelection(rPaM) && rPaM.GetNext() == &rPaM && + ( !pSrcNd->GetTable().IsTableComplex() || + pDestNd->GetTable().IsNewModel() ) ) + { + // make relative table copy + SwTableBox* pBox = pDestNd->GetTable().GetTableBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "Box is not in this table" ); + aBoxes.insert( pBox ); + } + + SwNodeIndex aNdIdx( *pDestNd->EndOfSectionNode()); + if( !bParkTableCursor ) + { + // exit first the complete table + // ???? what about only table in a frame ????? + SwContentNode* pCNd = GetDoc()->GetNodes().GoNext( &aNdIdx ); + SwPosition aPos( aNdIdx, SwIndex( pCNd, 0 )); + // #i59539: Don't remove all redline + SwPaM const tmpPaM(*pDestNd, *pDestNd->EndOfSectionNode()); + ::PaMCorrAbs(tmpPaM, aPos); + } + + bRet = GetDoc()->InsCopyOfTable( aDestPos, aBoxes, &pSrcNd->GetTable() ); + + if( bParkTableCursor ) + GetCursor(); + else + { + // return to the box + aNdIdx = *pSttNd; + SwContentNode* pCNd = GetDoc()->GetNodes().GoNext( &aNdIdx ); + SwPosition aPos( aNdIdx, SwIndex( pCNd, 0 )); + // #i59539: Don't remove all redline + SwNode & rNode(rPaM.GetPoint()->nNode.GetNode()); + SwContentNode *const pContentNode( rNode.GetContentNode() ); + SwPaM const tmpPam(rNode, 0, + rNode, pContentNode ? pContentNode->Len() : 0); + ::PaMCorrAbs(tmpPam, aPos); + } + + break; // exit the "while-loop" + } + else if(*aCpyPam.GetPoint() == *aCpyPam.GetMark() && !rClpDoc.GetSpzFrameFormats()->empty()) + { + // we need a DrawView + if(!Imp()->GetDrawView()) + MakeDrawView(); + ::std::vector<SwFrameFormat*> inserted; + for (auto const pFlyFormat : *rClpDoc.GetSpzFrameFormats()) + { + // if anchored inside other fly, will be copied when copying + // top-level fly, so skip here! (other non-body anchor + // shouldn't happen here) + SwFormatAnchor const& rAnchor(pFlyFormat->GetAnchor()); + if (RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId() + || rClpDoc.GetNodes().GetEndOfExtras().GetIndex() < rAnchor.GetContentAnchor()->nNode.GetIndex()) + { + inserted.emplace_back( + lcl_PasteFlyOrDrawFormat(rPaM, pFlyFormat, *this)); + } + } + for (auto const pFlyFormat : inserted) + { + lcl_SelectFlyFormat(pFlyFormat, *this); + } + } + else + { + if( bDelTable && IsTableMode() ) + { + SwEditShell::Delete(false); + bDelTable = false; + } + + SwPosition& rInsPos = *rPaM.GetPoint(); + const SwStartNode* pBoxNd = rInsPos.nNode.GetNode(). + FindTableBoxStartNode(); + if( pBoxNd && SwNodeOffset(2) == pBoxNd->EndOfSectionIndex() - + pBoxNd->GetIndex() && + aCpyPam.GetPoint()->nNode != aCpyPam.GetMark()->nNode ) + { + // Copy more than 1 node in the current box. But + // then the BoxAttribute should be removed + GetDoc()->ClearBoxNumAttrs( rInsPos.nNode ); + } + + // ** + // ** Update SwDoc::Append, if you change the following code ** + // ** + { + SwNodeIndex aIndexBefore(rInsPos.nNode); + + --aIndexBefore; + + rClpDoc.getIDocumentContentOperations().CopyRange(aCpyPam, rInsPos, SwCopyFlags::CheckPosInFly); + // Note: aCpyPam is invalid now + + ++aIndexBefore; + SwPaM aPaM(SwPosition(aIndexBefore), + SwPosition(rInsPos.nNode)); + + aPaM.GetDoc().MakeUniqueNumRules(aPaM); + + // Update the rsid of each pasted text node. + SwNodes &rDestNodes = GetDoc()->GetNodes(); + SwNodeOffset const nEndIdx = aPaM.End()->nNode.GetIndex(); + + for (SwNodeOffset nIdx = aPaM.Start()->nNode.GetIndex(); + nIdx <= nEndIdx; ++nIdx) + { + SwTextNode *const pTextNode = rDestNodes[nIdx]->GetTextNode(); + if ( pTextNode ) + { + GetDoc()->UpdateParRsid( pTextNode ); + } + } + } + + SaveTableBoxContent( &rInsPos ); + } + } + } + + GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::INSGLOSSARY, nullptr ); + + // have new table formulas been inserted? + if( pTableFieldTyp->HasWriterListeners() ) + { + // finish old action: table-frames have been created + // a selection can be made now + sal_uInt16 nActCnt; + for( nActCnt = 0; ActionPend(); ++nActCnt ) + EndAllAction(); + + for( ; nActCnt; --nActCnt ) + StartAllAction(); + } + GetDoc()->getIDocumentFieldsAccess().UnlockExpFields(); + GetDoc()->getIDocumentFieldsAccess().UpdateFields(false); + EndAllAction(); + + return bRet; +} + +void SwFEShell::PastePages( SwFEShell& rToFill, sal_uInt16 nStartPage, sal_uInt16 nEndPage) +{ + Push(); + if(!GotoPage(nStartPage)) + { + Pop(PopMode::DeleteCurrent); + return; + } + MovePage( GetThisFrame, GetFirstSub ); + ::std::optional<SwPaM> oSourcePam( *GetCursor()->GetPoint() ); + OUString sStartingPageDesc = GetPageDesc( GetCurPageDesc()).GetName(); + SwPageDesc* pDesc = rToFill.FindPageDescByName( sStartingPageDesc, true ); + if( pDesc ) + rToFill.ChgCurPageDesc( *pDesc ); + + if(!GotoPage(nEndPage)) + { + Pop(PopMode::DeleteCurrent); + return; + } + //if the page starts with a table a paragraph has to be inserted before + SwNode *const pTableNode = oSourcePam->GetNode().FindTableNode(); + if(pTableNode) + { + //insert a paragraph + StartUndo(SwUndoId::INSERT); + SwNodeIndex aTableIdx( *pTableNode, -1 ); + SwPosition aBefore(aTableIdx); + if(GetDoc()->getIDocumentContentOperations().AppendTextNode( aBefore )) + { + SwPaM aTmp(aBefore); + *oSourcePam = aTmp; + } + EndUndo(SwUndoId::INSERT); + } + + MovePage( GetThisFrame, GetLastSub ); + oSourcePam->SetMark(); + *oSourcePam->GetMark() = *GetCursor()->GetPoint(); + + CurrShell aCurr( this ); + + StartAllAction(); + GetDoc()->getIDocumentFieldsAccess().LockExpFields(); + SetSelection(*oSourcePam); + // copy the text of the selection + SwEditShell::Copy(rToFill); + oSourcePam.reset(); // delete it because Undo will remove its node! + + if(pTableNode) + { + //remove the inserted paragraph + Undo(); + //remove the paragraph in the second doc, too + SwNodeIndex aIdx( rToFill.GetDoc()->GetNodes().GetEndOfExtras(), 2 ); + SwPaM aPara( aIdx ); //DocStart + rToFill.GetDoc()->getIDocumentContentOperations().DelFullPara(aPara); + } + // now the page bound objects + // additionally copy page bound frames + if( !GetDoc()->GetSpzFrameFormats()->empty() ) + { + // create a draw view if necessary + if( !rToFill.Imp()->GetDrawView() ) + rToFill.MakeDrawView(); + + for ( auto pCpyFormat : *GetDoc()->GetSpzFrameFormats() ) + { + SwFormatAnchor aAnchor( pCpyFormat->GetAnchor() ); + if ((RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId()) && + aAnchor.GetPageNum() >= nStartPage && aAnchor.GetPageNum() <= nEndPage) + { + aAnchor.SetPageNum( aAnchor.GetPageNum() - nStartPage + 1); + } + else + continue; + rToFill.GetDoc()->getIDocumentLayoutAccess().CopyLayoutFormat( *pCpyFormat, aAnchor, true, true ); + } + } + GetDoc()->getIDocumentFieldsAccess().UnlockExpFields(); + GetDoc()->getIDocumentFieldsAccess().UpdateFields(false); + Pop(PopMode::DeleteCurrent); + EndAllAction(); +} + +comphelper::OInterfaceContainerHelper3<css::text::XPasteListener>& SwFEShell::GetPasteListeners() { return m_aPasteListeners; } + +bool SwFEShell::GetDrawObjGraphic( SotClipboardFormatId nFormat, Graphic& rGrf ) const +{ + OSL_ENSURE( Imp()->HasDrawView(), "GetDrawObjGraphic without DrawView?" ); + const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList(); + bool bConvert = true; + if( rMrkList.GetMarkCount() ) + { + if( rMrkList.GetMarkCount() == 1 && + dynamic_cast< const SwVirtFlyDrawObj* >(rMrkList.GetMark( 0 )->GetMarkedSdrObj()) != nullptr ) + { + // select frame + if( CNT_GRF == GetCntType() ) + { + const Graphic* pGrf( GetGraphic() ); + if ( pGrf ) + { + Graphic aGrf( *pGrf ); + if( SotClipboardFormatId::GDIMETAFILE == nFormat ) + { + if( GraphicType::Bitmap != aGrf.GetType() ) + { + rGrf = aGrf; + bConvert = false; + } + else if( GetWin() ) + { + Size aSz; + Point aPt; + GetGrfSize( aSz ); + + ScopedVclPtrInstance< VirtualDevice > pVirtDev; + pVirtDev->EnableOutput( false ); + + MapMode aTmp( GetWin()->GetMapMode() ); + aTmp.SetOrigin( aPt ); + pVirtDev->SetMapMode( aTmp ); + + GDIMetaFile aMtf; + aMtf.Record( pVirtDev.get() ); + aGrf.Draw(*pVirtDev, aPt, aSz); + aMtf.Stop(); + aMtf.SetPrefMapMode( aTmp ); + aMtf.SetPrefSize( aSz ); + rGrf = aMtf; + } + } + else if( GraphicType::Bitmap == aGrf.GetType() ) + { + rGrf = aGrf; + bConvert = false; + } + else + { + // Not the original size, but the current one. + // Otherwise it could happen that for vector graphics + // many MB's of memory are allocated. + const Size aSz( GetSelectedFlyFrame()->getFramePrintArea().SSize() ); + ScopedVclPtrInstance< VirtualDevice > pVirtDev(*GetWin()->GetOutDev()); + + MapMode aTmp( MapUnit::MapTwip ); + pVirtDev->SetMapMode( aTmp ); + if( pVirtDev->SetOutputSize( aSz ) ) + { + aGrf.Draw(*pVirtDev, Point(), aSz); + rGrf = pVirtDev->GetBitmapEx( Point(), aSz ); + } + else + { + rGrf = aGrf; + bConvert = false; + } + } + } + } + } + else if( SotClipboardFormatId::GDIMETAFILE == nFormat ) + rGrf = Imp()->GetDrawView()->GetMarkedObjMetaFile(); + else if( SotClipboardFormatId::BITMAP == nFormat || SotClipboardFormatId::PNG == nFormat ) + rGrf = Imp()->GetDrawView()->GetMarkedObjBitmapEx(); + } + return bConvert; +} + +// #i50824# +// replace method <lcl_RemoveOleObjsFromSdrModel> by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs> +static void lcl_ConvertSdrOle2ObjsToSdrGrafObjs( SdrModel& _rModel ) +{ + for ( sal_uInt16 nPgNum = 0; nPgNum < _rModel.GetPageCount(); ++nPgNum ) + { + // setup object iterator in order to iterate through all objects + // including objects in group objects, but exclusive group objects. + SdrObjListIter aIter(_rModel.GetPage(nPgNum)); + while( aIter.IsMore() ) + { + SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( aIter.Next() ); + if( pOle2Obj ) + { + // found an ole2 shape + SdrObjList* pObjList = pOle2Obj->getParentSdrObjListFromSdrObject(); + + // get its graphic + Graphic aGraphic; + pOle2Obj->Connect(); + const Graphic* pGraphic = pOle2Obj->GetGraphic(); + if( pGraphic ) + aGraphic = *pGraphic; + pOle2Obj->Disconnect(); + + // create new graphic shape with the ole graphic and shape size + SdrGrafObj* pGraphicObj = new SdrGrafObj( + _rModel, + aGraphic, + pOle2Obj->GetCurrentBoundRect()); + // apply layer of ole2 shape at graphic shape + pGraphicObj->SetLayer( pOle2Obj->GetLayer() ); + + // replace ole2 shape with the new graphic object and delete the ol2 shape + SdrObject* pRemovedObject = pObjList->ReplaceObject( pGraphicObj, pOle2Obj->GetOrdNum() ); + SdrObject::Free( pRemovedObject ); + } + } + } +} + +void SwFEShell::Paste( SvStream& rStrm, SwPasteSdr nAction, const Point* pPt ) +{ + CurrShell aCurr( this ); + StartAllAction(); + StartUndo(); + + std::unique_ptr< FmFormModel > pModel( + new FmFormModel( + nullptr, + GetDoc()->GetDocShell())); + + pModel->GetItemPool().FreezeIdRanges(); + + rStrm.Seek(0); + + uno::Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( rStrm ) ); + SvxDrawingLayerImport( pModel.get(), xInputStream ); + + if ( !Imp()->HasDrawView() ) + Imp()->MakeDrawView(); + + Point aPos( pPt ? *pPt : GetCharRect().Pos() ); + SdrView *pView = Imp()->GetDrawView(); + + // drop on the existing object: replace object or apply new attributes + if( pModel->GetPageCount() > 0 && + 1 == pModel->GetPage(0)->GetObjCount() && + 1 == pView->GetMarkedObjectList().GetMarkCount() ) + { + // replace a marked 'virtual' drawing object + // by its corresponding 'master' drawing object in the mark list. + SwDrawView::ReplaceMarkedDrawVirtObjs( *pView ); + + SdrObject* pClpObj = pModel->GetPage(0)->GetObj(0); + SdrObject* pOldObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj(); + + if( SwPasteSdr::SetAttr == nAction && dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr ) + nAction = SwPasteSdr::Replace; + + switch( nAction ) + { + case SwPasteSdr::Replace: + { + const SwFrameFormat* pFormat(nullptr); + const SwFrame* pAnchor(nullptr); + if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr ) + { + pFormat = FindFrameFormat( pOldObj ); + + Point aNullPt; + SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrameFormat*>(pFormat)->GetFrame( &aNullPt ); + pAnchor = pFlyFrame ? pFlyFrame->GetAnchorFrame() : nullptr; + + if (!pAnchor || pAnchor->FindFooterOrHeader()) + { + // if there is a textframe in the header/footer: + // do not replace but insert + nAction = SwPasteSdr::Insert; + break; + } + } + + SdrObject* pNewObj(pClpObj->CloneSdrObject(pOldObj->getSdrModelFromSdrObject())); + tools::Rectangle aOldObjRect( pOldObj->GetCurrentBoundRect() ); + Size aOldObjSize( aOldObjRect.GetSize() ); + tools::Rectangle aNewRect( pNewObj->GetCurrentBoundRect() ); + Size aNewSize( aNewRect.GetSize() ); + + Fraction aScaleWidth( aOldObjSize.Width(), aNewSize.Width() ); + Fraction aScaleHeight( aOldObjSize.Height(), aNewSize.Height()); + pNewObj->NbcResize( aNewRect.TopLeft(), aScaleWidth, aScaleHeight); + + Point aVec = aOldObjRect.TopLeft() - aNewRect.TopLeft(); + pNewObj->NbcMove(Size(aVec.getX(), aVec.getY())); + + if( dynamic_cast<const SdrUnoObj*>( pNewObj) != nullptr ) + pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() ); + else if( dynamic_cast<const SdrUnoObj*>( pOldObj) != nullptr ) + pNewObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() ); + else + pNewObj->SetLayer( pOldObj->GetLayer() ); + + if( dynamic_cast<const SwVirtFlyDrawObj*>( pOldObj) != nullptr ) + { + // store attributes, then set SdrObject + SfxItemSetFixed<RES_SURROUND, RES_ANCHOR> aFrameSet( mxDoc->GetAttrPool() ); + aFrameSet.Set( pFormat->GetAttrSet() ); + + Point aNullPt; + if( pAnchor->IsTextFrame() && static_cast<const SwTextFrame*>(pAnchor)->IsFollow() ) + { + const SwTextFrame* pTmp = static_cast<const SwTextFrame*>(pAnchor); + do { + pTmp = pTmp->FindMaster(); + OSL_ENSURE( pTmp, "Where's my Master?" ); + } while( pTmp->IsFollow() ); + pAnchor = pTmp; + } + if( auto pCaptionObj = dynamic_cast<SdrCaptionObj*>( pOldObj)) + aNullPt = pCaptionObj->GetTailPos(); + else + aNullPt = aOldObjRect.TopLeft(); + + Point aNewAnchor = pAnchor->GetFrameAnchorPos( ::HasWrap( pOldObj ) ); + // OD 2004-04-05 #i26791# - direct positioning of Writer + // fly frame object for <SwDoc::Insert(..)> + pNewObj->NbcSetRelativePos( aNullPt - aNewAnchor ); + pNewObj->NbcSetAnchorPos( aNewAnchor ); + + pOldObj->GetOrdNum(); + + DelSelectedObj(); + + GetDoc()->getIDocumentContentOperations().InsertDrawObj( *GetCursor(), *pNewObj, aFrameSet ); + } + else + { + // #i123922# for handling MasterObject and virtual ones correctly, SW + // wants us to call ReplaceObject at the page, but that also + // triggers the same assertion (I tried it), so stay at the view method + pView->ReplaceObjectAtView(pOldObj, *Imp()->GetPageView(), pNewObj); + } + } + break; + + case SwPasteSdr::SetAttr: + { + SfxItemSet aSet( GetAttrPool() ); + const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pClpObj); + + if(pSdrGrafObj) + { + SdrObject* pTarget = nullptr; + + if(0 != pView->GetMarkedObjectList().GetMarkCount()) + { + // try to get target (if it's at least one, take first) + SdrMark* pMark = pView->GetMarkedObjectList().GetMark(0); + + if(pMark) + { + pTarget = pMark->GetMarkedSdrObj(); + } + } + + if(pTarget) + { + // copy ItemSet from target + aSet.Set(pTarget->GetMergedItemSet()); + } + + // for SdrGrafObj, use the graphic as fill style argument + const Graphic& rGraphic = pSdrGrafObj->GetGraphic(); + + if(GraphicType::NONE != rGraphic.GetType() && GraphicType::Default != rGraphic.GetType()) + { + aSet.Put(XFillBitmapItem(OUString(), rGraphic)); + aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP)); + } + } + else + { + aSet.Put(pClpObj->GetMergedItemSet()); + } + + pView->SetAttributes( aSet ); + } + break; + + default: + nAction = SwPasteSdr::Insert; + break; + } + } + else + nAction = SwPasteSdr::Insert; + + if( SwPasteSdr::Insert == nAction ) + { + ::sw::DrawUndoGuard drawUndoGuard(GetDoc()->GetIDocumentUndoRedo()); + + bool bDesignMode = pView->IsDesignMode(); + if( !bDesignMode ) + pView->SetDesignMode(); + + // #i50824# + // method <lcl_RemoveOleObjsFromSdrModel> replaced by <lcl_ConvertSdrOle2ObjsToSdrGrafObjs> + lcl_ConvertSdrOle2ObjsToSdrGrafObjs(*pModel); + pView->Paste(*pModel, aPos, nullptr, SdrInsertFlags::NONE); + + const size_t nCnt = pView->GetMarkedObjectList().GetMarkCount(); + if( nCnt ) + { + const Point aNull( 0, 0 ); + for( size_t i=0; i < nCnt; ++i ) + { + SdrObject *pObj = pView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj(); + pObj->ImpSetAnchorPos( aNull ); + } + + pView->SetCurrentObj( SdrObjKind::Group ); + if ( nCnt > 1 ) + pView->GroupMarked(); + SdrObject *pObj = pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(); + if( dynamic_cast<const SdrUnoObj*>( pObj) != nullptr ) + { + pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetControlsId() ); + bDesignMode = true; + } + else + pObj->SetLayer( GetDoc()->getIDocumentDrawModelAccess().GetHeavenId() ); + const tools::Rectangle &rSnap = pObj->GetSnapRect(); + const Size aDiff( rSnap.GetWidth()/2, rSnap.GetHeight()/2 ); + pView->MoveMarkedObj( aDiff ); + ImpEndCreate(); + if( !bDesignMode ) + pView->SetDesignMode( false ); + } + } + EndUndo(); + EndAllAction(); +} + +bool SwFEShell::Paste(const Graphic &rGrf, const OUString& rURL) +{ + CurrShell aCurr( this ); + SdrObject* pObj = nullptr; + SdrView *pView = Imp()->GetDrawView(); + + bool bRet = 1 == pView->GetMarkedObjectList().GetMarkCount(); + if (bRet) + { + pObj = pView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj(); + bRet = pObj->IsClosedObj() && dynamic_cast<const SdrOle2Obj*>( pObj) == nullptr; + } + + if( bRet && pObj ) + { + // #i123922# added code to handle the two cases of SdrGrafObj and a fillable, non- + // OLE object in focus + SdrObject* pResult = pObj; + + if(dynamic_cast< SdrGrafObj* >(pObj)) + { + SdrGrafObj* pNewGrafObj(static_cast<SdrGrafObj*>(pObj->CloneSdrObject(pObj->getSdrModelFromSdrObject()))); + + pNewGrafObj->SetGraphic(rGrf); + + // #i123922# for handling MasterObject and virtual ones correctly, SW + // wants us to call ReplaceObject at the page, but that also + // triggers the same assertion (I tried it), so stay at the view method + pView->ReplaceObjectAtView(pObj, *pView->GetSdrPageView(), pNewGrafObj); + + // set in all cases - the Clone() will have copied an existing link (!) + pNewGrafObj->SetGraphicLink(rURL); + + pResult = pNewGrafObj; + } + else + { + pView->AddUndo(std::make_unique<SdrUndoAttrObj>(*pObj)); + + SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(pView->GetModel()->GetItemPool()); + + aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP)); + aSet.Put(XFillBitmapItem(OUString(), rGrf)); + pObj->SetMergedItemSetAndBroadcast(aSet); + } + + // we are done; mark the modified/new object + pView->MarkObj(pResult, pView->GetSdrPageView()); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |