diff options
Diffstat (limited to 'sw/source/core/txtnode/atrflyin.cxx')
-rw-r--r-- | sw/source/core/txtnode/atrflyin.cxx | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/sw/source/core/txtnode/atrflyin.cxx b/sw/source/core/txtnode/atrflyin.cxx new file mode 100644 index 000000000..4e61e568e --- /dev/null +++ b/sw/source/core/txtnode/atrflyin.cxx @@ -0,0 +1,297 @@ +/* -*- 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 <hintids.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <pam.hxx> +#include <flyfrm.hxx> +#include <ndtxt.hxx> +#include <frmfmt.hxx> +#include <fmtflcnt.hxx> +#include <txtflcnt.hxx> +#include <fmtanchr.hxx> +#include <txtfrm.hxx> +#include <flyfrms.hxx> +#include <objectformatter.hxx> +#include <calbck.hxx> +#include <dcontact.hxx> +#include <textboxhelper.hxx> + +SwFormatFlyCnt::SwFormatFlyCnt( SwFrameFormat *pFrameFormat ) + : SfxPoolItem( RES_TXTATR_FLYCNT ), + m_pTextAttr( nullptr ), + m_pFormat( pFrameFormat ) +{ +} + +bool SwFormatFlyCnt::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + return( m_pTextAttr && static_cast<const SwFormatFlyCnt&>(rAttr).m_pTextAttr && + m_pTextAttr->GetStart() == static_cast<const SwFormatFlyCnt&>(rAttr).m_pTextAttr->GetStart() && + m_pFormat == static_cast<const SwFormatFlyCnt&>(rAttr).GetFrameFormat() ); +} + +SwFormatFlyCnt* SwFormatFlyCnt::Clone( SfxItemPool* ) const +{ + return new SwFormatFlyCnt( m_pFormat ); +} + +SwTextFlyCnt::SwTextFlyCnt( SwFormatFlyCnt& rAttr, sal_Int32 nStartPos ) + : SwTextAttr( rAttr, nStartPos ) +{ + rAttr.m_pTextAttr = this; + SetHasDummyChar(true); +} + +/** An overview of how a new SwTextFlyCnt is created: + * MakeTextAttr() is called e.g. by SwTextNode::CopyText(). + * The following steps are required to clone: + * 1) copying the pFormat with content, attributes etc. + * 2) setting the anchor + * 3) notification + * Because not all required information is available at all times, + * the steps are distributed variously: + * ad 1) MakeTextAttr() calls DocumentLayoutManager::CopyLayoutFormat() + * which creates the new SwFlyFrameFormat and copies the content of the + * fly frame. + * ad 2) SetAnchor() is called by SwTextNode::InsertHint() and sets the anchor + * position in the SwFlyFrameFormat to the SwPosition of the dummy + * CH_TXTATR_BREAKWORD. This cannot be done in MakeTextAttr() because it + * doesn't know the target text node. + * ad 3) GetFlyFrame_() is called during text formatting by SwTextFormatter + * and searches for the SwFlyFrame for the dummy char of the current + * SwTextFrame. If none is found, a new SwFlyInContentFrame is created. + * Important: pTextFrame->AppendFly() immediately triggers a reformat + * of pTextFrame. However, the recursion is blocked by the lock mechanism + * in SwTextFrame::Format(). + * The advantage of all this is that it's not necessary to explicitly iterate + * over all SwTextFrames that depend on the SwTextNode to create the + * SwFlyInContentFrame - this is done automatically already. + */ + +void SwTextFlyCnt::CopyFlyFormat( SwDoc* pDoc ) +{ + SwFrameFormat* pFormat = GetFlyCnt().GetFrameFormat(); + assert(pFormat); + // The FlyFrameFormat must be copied - CopyLayoutFormat + // (DocumentLayoutManager.cxx) creates the FlyFrameFormat and copies the + // content. + + // disable undo while copying attribute + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + SwFormatAnchor aAnchor( pFormat->GetAnchor() ); + if ((RndStdIds::FLY_AT_PAGE != aAnchor.GetAnchorId()) && + (pDoc != pFormat->GetDoc())) // different documents? + { + // JP 03.06.96: ensure that the copied anchor points to valid content! + // setting it to the correct position is done later. + SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), +2 ); + SwContentNode* pCNd = aIdx.GetNode().GetContentNode(); + if( !pCNd ) + pCNd = pDoc->GetNodes().GoNext( &aIdx ); + + SwPosition pos = *aAnchor.GetContentAnchor(); + pos.nNode = aIdx; + if (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()) + { + pos.nContent.Assign( pCNd, 0 ); + } + else + { + pos.nContent.Assign( nullptr, 0 ); + assert(false); + } + aAnchor.SetAnchor( &pos ); + } + + SwFrameFormat* pNew = pDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, false, false ); + const_cast<SwFormatFlyCnt&>(GetFlyCnt()).SetFlyFormat( pNew ); +} + +/** SetAnchor() is called by SwTextNode::InsertHint() and sets the anchor + * position in the SwFlyFrameFormat to the SwPosition of the dummy + * CH_TXTATR_BREAKWORD. This cannot be done in MakeTextAttr() because it + * doesn't know the target text node. + */ +void SwTextFlyCnt::SetAnchor( const SwTextNode *pNode ) +{ + // for Undo, the new anchor must be known already! + + SwDoc* pDoc = const_cast<SwDoc*>(pNode->GetDoc()); + + SwIndex aIdx( const_cast<SwTextNode*>(pNode), GetStart() ); + SwPosition aPos( *pNode->StartOfSectionNode(), aIdx ); + SwFrameFormat* pFormat = GetFlyCnt().GetFrameFormat(); + SwFormatAnchor aAnchor( pFormat->GetAnchor() ); + SwNode *const pOldNode(aAnchor.GetContentAnchor() + ? &aAnchor.GetContentAnchor()->nNode.GetNode() + : nullptr); + + if (!pOldNode || !pOldNode->GetNodes().IsDocNodes() || + pOldNode != static_cast<SwNode const *>(pNode)) + { + aPos.nNode = *pNode; + } + else + { + aPos.nNode = *pOldNode; + } + + aAnchor.SetType( RndStdIds::FLY_AS_CHAR ); // default! + aAnchor.SetAnchor( &aPos ); + + // in case of anchor change, delete all FlyFrames + // JP 25.04.95: if the Frames can be moved within SplitNode, they don't + // need to be deleted + if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() ) + && RES_DRAWFRMFMT != pFormat->Which() ) + pFormat->DelFrames(); + + // copy into a different document? + if( pDoc != pFormat->GetDoc() ) + { + // disable undo while copying attribute + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + SwFrameFormat* pNew = pDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, false, false ); + + ::sw::UndoGuard const undoGuardFormat( + pFormat->GetDoc()->GetIDocumentUndoRedo()); + pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); + const_cast<SwFormatFlyCnt&>(GetFlyCnt()).SetFlyFormat( pNew ); + } + else if( pNode->GetpSwpHints() && + pNode->GetpSwpHints()->IsInSplitNode() && + RES_DRAWFRMFMT != pFormat->Which() ) + { + pFormat->LockModify(); + pFormat->SetFormatAttr( aAnchor ); // only set the anchor + // tdf#91228 must notify the anchor nodes despite LockModify + assert(pOldNode); + pOldNode->RemoveAnchoredFly(pFormat); + aPos.nNode.GetNode().AddAnchoredFly(pFormat); + pFormat->UnlockModify(); + } + else + { + assert(!pFormat->IsModifyLocked()); // need to notify anchor node + if (RES_DRAWFRMFMT == pFormat->Which()) + { + if (SdrObject const*const pObj = pFormat->FindSdrObject()) + { // tdf#123259 disconnect with *old* anchor position + static_cast<SwDrawContact*>(::GetUserCall(pObj))->DisconnectFromLayout(false); + } + } + pFormat->SetFormatAttr( aAnchor ); // only set the anchor + + // If the draw format has a TextBox, then set its anchor as well. + if (SwFrameFormat* pTextBox + = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT)) + { + SwFormatAnchor aTextBoxAnchor(pTextBox->GetAnchor()); + aTextBoxAnchor.SetAnchor(aAnchor.GetContentAnchor()); + + // SwFlyAtContentFrame::Modify() assumes the anchor has a matching layout frame, which + // may not be the case when we're in the process of a node split, so block + // notifications. + bool bIsInSplitNode = pNode->GetpSwpHints() && pNode->GetpSwpHints()->IsInSplitNode(); + if (bIsInSplitNode) + { + pTextBox->LockModify(); + } + + pTextBox->SetFormatAttr(aTextBoxAnchor); + + if (bIsInSplitNode) + { + pOldNode->RemoveAnchoredFly(pTextBox); + aPos.nNode.GetNode().AddAnchoredFly(pTextBox); + pTextBox->UnlockModify(); + } + } + } + + // The node may have several SwTextFrames - for every SwTextFrame a + // SwFlyInContentFrame is created. +} + + +/** GetFlyFrame_() is called during text formatting by SwTextFormatter + * and searches for the SwFlyFrame for the dummy char of the current + * SwTextFrame. If none is found, a new SwFlyInContentFrame is created. + */ +SwFlyInContentFrame *SwTextFlyCnt::GetFlyFrame_( const SwFrame *pCurrFrame ) +{ + SwFrameFormat* pFrameFormat = GetFlyCnt().GetFrameFormat(); + if( RES_DRAWFRMFMT == pFrameFormat->Which() ) + { + OSL_ENSURE( false, "SwTextFlyCnt::GetFlyFrame_: DrawInCnt-under construction!" ); + return nullptr; + } + + SwIterator<SwFlyFrame,SwFormat> aIter( *GetFlyCnt().m_pFormat ); + assert(pCurrFrame->IsTextFrame()); + SwFrame* pFrame = aIter.First(); + if ( pFrame ) + { + SwTextFrame *pFirst = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCurrFrame)); + while ( pFirst->IsFollow() ) + pFirst = pFirst->FindMaster(); + do + { + SwTextFrame *pTmp = pFirst; + do + { if( static_cast<SwFlyFrame*>(pFrame)->GetAnchorFrame() == static_cast<SwFrame*>(pTmp) ) + { + if ( pTmp != pCurrFrame ) + { + pTmp->RemoveFly( static_cast<SwFlyFrame*>(pFrame) ); + const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCurrFrame))->AppendFly( static_cast<SwFlyFrame*>(pFrame) ); + } + return static_cast<SwFlyInContentFrame*>(pFrame); + } + pTmp = pTmp->GetFollow(); + } while ( pTmp ); + + pFrame = aIter.Next(); + + } while( pFrame ); + } + + // We did not find a matching FlyFrame, so create a new one. + // AppendFly() triggers a reformat of pCurrentFrame. However, the + // recursion is blocked by the lock mechanism in SwTextFrame::Format(). + SwFrame* pCurrentFrame = const_cast<SwFrame*>(pCurrFrame); + SwFlyInContentFrame *pFly = new SwFlyInContentFrame(static_cast<SwFlyFrameFormat*>(pFrameFormat), pCurrentFrame, pCurrentFrame); + pCurrentFrame->AppendFly(pFly); + pFly->RegistFlys(); + + // We must ensure that the content of the FlyInCnt is fully formatted + // right after construction. + // #i26945# - Use new object formatter to format Writer + // fly frame and its content. + SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrame*>(pCurrFrame), + pCurrFrame->FindPageFrame() ); + + return pFly; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |