docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / core / txtnode / atrflyin.cxx
blob5047314e926e050c8b0f1cf2da78f0369aded0dc
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 <hintids.hxx>
21 #include <doc.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <IDocumentLayoutAccess.hxx>
24 #include <pam.hxx>
25 #include <flyfrm.hxx>
26 #include <ndtxt.hxx>
27 #include <frmfmt.hxx>
28 #include <fmtflcnt.hxx>
29 #include <txtflcnt.hxx>
30 #include <fmtanchr.hxx>
31 #include <txtfrm.hxx>
32 #include <flyfrms.hxx>
33 #include <objectformatter.hxx>
34 #include <calbck.hxx>
35 #include <dcontact.hxx>
36 #include <textboxhelper.hxx>
37 #include <osl/diagnose.h>
39 SwFormatFlyCnt::SwFormatFlyCnt( SwFrameFormat *pFrameFormat )
40 : SfxPoolItem( RES_TXTATR_FLYCNT ),
41 m_pTextAttr( nullptr ),
42 m_pFormat( pFrameFormat )
44 setNonShareable();
47 bool SwFormatFlyCnt::operator==( const SfxPoolItem& rAttr ) const
49 assert(SfxPoolItem::operator==(rAttr));
50 return( m_pTextAttr && static_cast<const SwFormatFlyCnt&>(rAttr).m_pTextAttr &&
51 m_pTextAttr->GetStart() == static_cast<const SwFormatFlyCnt&>(rAttr).m_pTextAttr->GetStart() &&
52 m_pFormat == static_cast<const SwFormatFlyCnt&>(rAttr).GetFrameFormat() );
55 SwFormatFlyCnt* SwFormatFlyCnt::Clone( SfxItemPool* ) const
57 return new SwFormatFlyCnt( m_pFormat );
60 void SwFormatFlyCnt::dumpAsXml(xmlTextWriterPtr pWriter) const
62 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatFlyCnt"));
63 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
64 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("text-attr"), "%p", m_pTextAttr);
65 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("format"), "%p", m_pFormat);
67 SfxPoolItem::dumpAsXml(pWriter);
69 (void)xmlTextWriterEndElement(pWriter);
72 SwTextFlyCnt::SwTextFlyCnt(
73 const SfxPoolItemHolder& rAttr,
74 sal_Int32 nStartPos )
75 : SwTextAttr( rAttr, nStartPos )
77 SwFormatFlyCnt& rSwFormatFlyCnt(static_cast<SwFormatFlyCnt&>(GetAttr()));
78 rSwFormatFlyCnt.m_pTextAttr = this;
79 SetHasDummyChar(true);
82 /** An overview of how a new SwTextFlyCnt is created:
83 * MakeTextAttr() is called e.g. by SwTextNode::CopyText().
84 * The following steps are required to clone:
85 * 1) copying the pFormat with content, attributes etc.
86 * 2) setting the anchor
87 * 3) notification
88 * Because not all required information is available at all times,
89 * the steps are distributed variously:
90 * ad 1) MakeTextAttr() calls DocumentLayoutManager::CopyLayoutFormat()
91 * which creates the new SwFlyFrameFormat and copies the content of the
92 * fly frame.
93 * ad 2) SetAnchor() is called by SwTextNode::InsertHint() and sets the anchor
94 * position in the SwFlyFrameFormat to the SwPosition of the dummy
95 * CH_TXTATR_BREAKWORD. This cannot be done in MakeTextAttr() because it
96 * doesn't know the target text node.
97 * ad 3) GetFlyFrame_() is called during text formatting by SwTextFormatter
98 * and searches for the SwFlyFrame for the dummy char of the current
99 * SwTextFrame. If none is found, a new SwFlyInContentFrame is created.
100 * Important: pTextFrame->AppendFly() immediately triggers a reformat
101 * of pTextFrame. However, the recursion is blocked by the lock mechanism
102 * in SwTextFrame::Format().
103 * The advantage of all this is that it's not necessary to explicitly iterate
104 * over all SwTextFrames that depend on the SwTextNode to create the
105 * SwFlyInContentFrame - this is done automatically already.
108 void SwTextFlyCnt::CopyFlyFormat( SwDoc& rDoc )
110 SwFrameFormat* pFormat = GetFlyCnt().GetFrameFormat();
111 assert(pFormat);
112 // The FlyFrameFormat must be copied - CopyLayoutFormat
113 // (DocumentLayoutManager.cxx) creates the FlyFrameFormat and copies the
114 // content.
116 // disable undo while copying attribute
117 ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
118 SwFormatAnchor aAnchor( pFormat->GetAnchor() );
119 if ((RndStdIds::FLY_AT_PAGE != aAnchor.GetAnchorId()) &&
120 (&rDoc != pFormat->GetDoc())) // different documents?
122 // JP 03.06.96: ensure that the copied anchor points to valid content!
123 // setting it to the correct position is done later.
124 SwNodeIndex aIdx( rDoc.GetNodes().GetEndOfExtras(), +2 );
125 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
126 if( !pCNd )
127 pCNd = SwNodes::GoNext(&aIdx);
129 SwPosition pos(aIdx.GetNode());
130 aAnchor.SetAnchor( &pos );
133 SwFrameFormat* pNew = rDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, false, false );
134 const_cast<SwFormatFlyCnt&>(GetFlyCnt()).SetFlyFormat( pNew );
137 /** SetAnchor() is called by SwTextNode::InsertHint() and sets the anchor
138 * position in the SwFlyFrameFormat to the SwPosition of the dummy
139 * CH_TXTATR_BREAKWORD. This cannot be done in MakeTextAttr() because it
140 * doesn't know the target text node.
142 void SwTextFlyCnt::SetAnchor( const SwTextNode *pNode )
144 // for Undo, the new anchor must be known already!
146 SwDoc& rDoc = const_cast<SwDoc&>(pNode->GetDoc());
148 SwFrameFormat* pFormat = GetFlyCnt().GetFrameFormat();
149 SwFormatAnchor aAnchor( pFormat->GetAnchor() );
150 SwNode *const pOldNode(aAnchor.GetAnchorNode());
152 std::optional<SwPosition> oPos;
153 if (!pOldNode || !pOldNode->GetNodes().IsDocNodes() ||
154 pOldNode != static_cast<SwNode const *>(pNode))
156 oPos.emplace( *pNode, GetStart() );
158 else
160 oPos.emplace( *pOldNode, pOldNode->GetContentNode(), GetStart() );
163 aAnchor.SetType( RndStdIds::FLY_AS_CHAR ); // default!
164 aAnchor.SetAnchor( &*oPos );
166 // in case of anchor change, delete all FlyFrames
167 // JP 25.04.95: if the Frames can be moved within SplitNode, they don't
168 // need to be deleted
169 if( ( !pNode->GetpSwpHints() || !pNode->GetpSwpHints()->IsInSplitNode() )
170 && RES_DRAWFRMFMT != pFormat->Which() )
171 pFormat->DelFrames();
173 // copy into a different document?
174 if( &rDoc != pFormat->GetDoc() )
176 // disable undo while copying attribute
177 ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
178 SwFrameFormat* pNew = rDoc.getIDocumentLayoutAccess().CopyLayoutFormat( *pFormat, aAnchor, false, false );
180 ::sw::UndoGuard const undoGuardFormat(
181 pFormat->GetDoc()->GetIDocumentUndoRedo());
182 pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat( pFormat );
183 const_cast<SwFormatFlyCnt&>(GetFlyCnt()).SetFlyFormat( pNew );
185 else if( pNode->GetpSwpHints() &&
186 pNode->GetpSwpHints()->IsInSplitNode() &&
187 RES_DRAWFRMFMT != pFormat->Which() )
189 pFormat->LockModify();
190 pFormat->SetFormatAttr( aAnchor ); // only set the anchor
191 // tdf#91228 must notify the anchor nodes despite LockModify
192 assert(pOldNode);
193 pOldNode->RemoveAnchoredFly(pFormat);
194 oPos->GetNode().AddAnchoredFly(pFormat);
195 pFormat->UnlockModify();
197 else
199 assert(!pFormat->IsModifyLocked()); // need to notify anchor node
200 if (RES_DRAWFRMFMT == pFormat->Which())
202 if (SdrObject const*const pObj = pFormat->FindSdrObject())
203 { // tdf#123259 disconnect with *old* anchor position
204 if (SwDrawContact* pContact = static_cast<SwDrawContact*>(::GetUserCall( pObj )))
205 pContact->DisconnectFromLayout(false);
208 pFormat->SetFormatAttr( aAnchor ); // only set the anchor
210 // If the draw format has a TextBox, then set its anchor as well.
211 if (SwFrameFormat* pTextBox
212 = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
214 SwFormatAnchor aTextBoxAnchor(pTextBox->GetAnchor());
215 aTextBoxAnchor.SetAnchor(aAnchor.GetContentAnchor());
217 // SwFlyAtContentFrame::SwClientNotify() assumes the anchor has a matching layout frame, which
218 // may not be the case when we're in the process of a node split, so block
219 // notifications.
220 bool bIsInSplitNode = pNode->GetpSwpHints() && pNode->GetpSwpHints()->IsInSplitNode();
221 if (bIsInSplitNode)
223 pTextBox->LockModify();
225 else
227 // Otherwise delete fly frames on anchor change.
228 pTextBox->DelFrames();
231 pTextBox->SetFormatAttr(aTextBoxAnchor);
233 if (bIsInSplitNode)
235 pOldNode->RemoveAnchoredFly(pTextBox);
236 oPos->GetNode().AddAnchoredFly(pTextBox);
237 pTextBox->UnlockModify();
239 else
241 pTextBox->MakeFrames();
246 // The node may have several SwTextFrames - for every SwTextFrame a
247 // SwFlyInContentFrame is created.
251 /** GetFlyFrame_() is called during text formatting by SwTextFormatter
252 * and searches for the SwFlyFrame for the dummy char of the current
253 * SwTextFrame. If none is found, a new SwFlyInContentFrame is created.
255 SwFlyInContentFrame *SwTextFlyCnt::GetFlyFrame_( const SwFrame *pCurrFrame )
257 SwFrameFormat* pFrameFormat = GetFlyCnt().GetFrameFormat();
258 if( RES_DRAWFRMFMT == pFrameFormat->Which() )
260 OSL_ENSURE( false, "SwTextFlyCnt::GetFlyFrame_: DrawInCnt-under construction!" );
261 return nullptr;
264 SwIterator<SwFlyFrame,SwFormat> aIter( *GetFlyCnt().m_pFormat );
265 assert(pCurrFrame->IsTextFrame());
266 SwFrame* pFrame = aIter.First();
267 if ( pFrame )
269 SwTextFrame *pFirst = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCurrFrame));
270 while ( pFirst->IsFollow() )
271 pFirst = pFirst->FindMaster();
274 SwTextFrame *pTmp = pFirst;
276 { if( static_cast<SwFlyFrame*>(pFrame)->GetAnchorFrame() == static_cast<SwFrame*>(pTmp) )
278 if ( pTmp != pCurrFrame )
280 pTmp->RemoveFly( static_cast<SwFlyFrame*>(pFrame) );
281 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCurrFrame))->AppendFly( static_cast<SwFlyFrame*>(pFrame) );
283 return static_cast<SwFlyInContentFrame*>(pFrame);
285 pTmp = pTmp->GetFollow();
286 } while ( pTmp );
288 pFrame = aIter.Next();
290 } while( pFrame );
293 // We did not find a matching FlyFrame, so create a new one.
294 // AppendFly() triggers a reformat of pCurrentFrame. However, the
295 // recursion is blocked by the lock mechanism in SwTextFrame::Format().
296 SwFrame* pCurrentFrame = const_cast<SwFrame*>(pCurrFrame);
297 SwFlyInContentFrame *pFly = new SwFlyInContentFrame(static_cast<SwFlyFrameFormat*>(pFrameFormat), pCurrentFrame, pCurrentFrame);
298 pCurrentFrame->AppendFly(pFly);
299 pFly->RegistFlys();
301 // We must ensure that the content of the FlyInCnt is fully formatted
302 // right after construction.
303 // #i26945# - Use new object formatter to format Writer
304 // fly frame and its content.
305 SwObjectFormatter::FormatObj( *pFly, const_cast<SwFrame*>(pCurrFrame),
306 pCurrFrame->FindPageFrame() );
308 return pFly;
311 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */