ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / core / undo / undobj1.cxx
blob6d6c641a353f233475f24a391bb08b4bb188dae1
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 <libxml/xmlwriter.h>
22 #include <svl/itemiter.hxx>
23 #include <svx/svdundo.hxx>
24 #include <osl/diagnose.h>
25 #include <hintids.hxx>
26 #include <hints.hxx>
27 #include <fmtflcnt.hxx>
28 #include <fmtanchr.hxx>
29 #include <fmtcntnt.hxx>
30 #include <txtflcnt.hxx>
31 #include <frmfmt.hxx>
32 #include <UndoCore.hxx>
33 #include <rolbck.hxx>
34 #include <doc.hxx>
35 #include <IDocumentLayoutAccess.hxx>
36 #include <rootfrm.hxx>
37 #include <swundo.hxx>
38 #include <pam.hxx>
39 #include <mvsave.hxx>
40 #include <ndtxt.hxx>
41 #include <ndole.hxx>
42 #include <frameformats.hxx>
43 #include <svx/svdobj.hxx>
45 SwUndoFlyBase::SwUndoFlyBase( SwFrameFormat* pFormat, SwUndoId nUndoId )
46 : SwUndo(nUndoId, pFormat->GetDoc())
47 , m_pFrameFormat(pFormat)
48 , m_nNodePagePos(0)
49 , m_nContentPos(0)
50 , m_nRndId(RndStdIds::FLY_AT_PARA)
51 , m_bDelFormat(false)
55 SwUndoFlyBase::~SwUndoFlyBase()
57 if( m_bDelFormat ) // delete during an Undo?
59 if (const auto& pTextBoxes = m_pFrameFormat->GetOtherTextBoxFormats())
61 // Clear and unregister before release.
62 if (m_pFrameFormat->Which() == RES_FLYFRMFMT)
63 pTextBoxes->DelTextBox(m_pFrameFormat);
65 if (m_pFrameFormat->Which() == RES_DRAWFRMFMT)
66 pTextBoxes->ClearAll();
68 // clear that before delete
69 m_pFrameFormat->SetOtherTextBoxFormats(nullptr);
71 delete m_pFrameFormat;
75 void SwUndoFlyBase::dumpAsXml(xmlTextWriterPtr pWriter) const
77 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoFlyBase"));
78 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nNodePagePos"),
79 BAD_CAST(OString::number(sal_Int32(m_nNodePagePos)).getStr()));
80 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nContentPos"),
81 BAD_CAST(OString::number(m_nContentPos).getStr()));
82 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nRndId"),
83 BAD_CAST(OString::number(static_cast<int>(m_nRndId)).getStr()));
84 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_bDelFormat"),
85 BAD_CAST(OString::boolean(m_bDelFormat).getStr()));
87 SwUndo::dumpAsXml(pWriter);
88 SwUndoSaveSection::dumpAsXml(pWriter);
90 if (m_pFrameFormat)
92 m_pFrameFormat->dumpAsXml(pWriter);
95 (void)xmlTextWriterEndElement(pWriter);
98 void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame)
100 SwDoc *const pDoc = & rContext.GetDoc();
102 // add again into array
103 sw::SpzFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats();
104 rFlyFormats.push_back( static_cast<sw::SpzFrameFormat*>(m_pFrameFormat));
106 // OD 26.06.2003 #108784# - insert 'master' drawing object into drawing page
107 if ( RES_DRAWFRMFMT == m_pFrameFormat->Which() )
108 m_pFrameFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREP_INSERT_FLY));
110 SwFormatAnchor aAnchor( m_nRndId );
112 if (RndStdIds::FLY_AT_PAGE == m_nRndId)
114 aAnchor.SetPageNum( o3tl::narrowing<sal_uInt16>(sal_Int32(m_nNodePagePos)) );
116 else
118 SwPosition aNewPos(*pDoc->GetNodes()[m_nNodePagePos]);
119 if ((RndStdIds::FLY_AS_CHAR == m_nRndId) || (RndStdIds::FLY_AT_CHAR == m_nRndId))
121 aNewPos.SetContent( m_nContentPos );
123 aAnchor.SetAnchor( &aNewPos );
126 m_pFrameFormat->SetFormatAttr( aAnchor ); // reset anchor
128 if( RES_DRAWFRMFMT != m_pFrameFormat->Which() )
130 // get Content and reset ContentAttribute
131 SwNodeIndex aIdx( pDoc->GetNodes() );
132 RestoreSection( pDoc, &aIdx, SwFlyStartNode );
133 m_pFrameFormat->SetFormatAttr( SwFormatContent( aIdx.GetNode().GetStartNode() ));
136 // Set InContentAttribute not until there is content!
137 // Otherwise the layout would format the Fly beforehand but would not find
138 // content; this happened with graphics from the internet.
139 if (RndStdIds::FLY_AS_CHAR == m_nRndId)
141 // there must be at least the attribute in a TextNode
142 SwContentNode* pCNd = aAnchor.GetAnchorNode()->GetContentNode();
143 OSL_ENSURE( pCNd->IsTextNode(), "no Text Node at position." );
144 SwFormatFlyCnt aFormat( m_pFrameFormat );
145 pCNd->GetTextNode()->InsertItem(aFormat, m_nContentPos, m_nContentPos, SetAttrMode::NOHINTEXPAND);
148 if (m_pFrameFormat->GetOtherTextBoxFormats())
150 // recklessly assume that this thing will live longer than the
151 // SwUndoFlyBase - not sure what could be done if that isn't the case...
152 m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats(
153 m_pFrameFormat->GetOtherTextBoxFormats());
155 SdrObject* pSdrObject
156 = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->FindSdrObject();
157 if (pSdrObject && m_pFrameFormat->Which() == RES_FLYFRMFMT)
158 m_pFrameFormat->GetOtherTextBoxFormats()->AddTextBox(pSdrObject, m_pFrameFormat);
160 if (m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->Which() == RES_DRAWFRMFMT)
163 if (pSdrObject)
165 // Make sure the old UNO wrapper is no longer cached after changing the shape +
166 // textframe pair. Otherwise we would have a wrapper which doesn't know about its
167 // textframe, even if it's there.
168 pSdrObject->setUnoShape(nullptr);
171 if (m_pFrameFormat->Which() == RES_FLYFRMFMT)
173 SwFrameFormat* pShapeFormat = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape();
174 pShapeFormat->SetFormatAttr(m_pFrameFormat->GetContent());
178 m_pFrameFormat->MakeFrames();
180 if( bShowSelFrame )
182 rContext.SetSelections(m_pFrameFormat, nullptr);
185 if( GetHistory() )
186 GetHistory()->Rollback( pDoc );
188 switch( m_nRndId )
190 case RndStdIds::FLY_AS_CHAR:
191 case RndStdIds::FLY_AT_CHAR:
193 const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor();
194 m_nNodePagePos = rAnchor.GetAnchorNode()->GetIndex();
195 m_nContentPos = rAnchor.GetAnchorContentOffset();
197 break;
198 case RndStdIds::FLY_AT_PARA:
199 case RndStdIds::FLY_AT_FLY:
201 const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor();
202 m_nNodePagePos = rAnchor.GetAnchorNode()->GetIndex();
204 break;
205 case RndStdIds::FLY_AT_PAGE:
206 break;
207 default: break;
209 m_bDelFormat = false;
212 void SwUndoFlyBase::DelFly( SwDoc* pDoc )
214 m_bDelFormat = true; // delete Format in DTOR
215 m_pFrameFormat->DelFrames(); // destroy Frames
217 if (m_pFrameFormat->GetOtherTextBoxFormats())
218 { // tdf#108867 clear that pointer
219 m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats(nullptr);
222 // all Uno objects should now log themselves off
223 m_pFrameFormat->RemoveAllUnos();
225 if ( RES_DRAWFRMFMT != m_pFrameFormat->Which() )
227 // if there is content than save it
228 const SwFormatContent& rContent = m_pFrameFormat->GetContent();
229 OSL_ENSURE( rContent.GetContentIdx(), "Fly without content" );
231 SaveSection( *rContent.GetContentIdx() );
232 const_cast<SwFormatContent&>(rContent).SetNewContentIdx( nullptr );
234 // OD 02.07.2003 #108784# - remove 'master' drawing object from drawing page
235 else
236 m_pFrameFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREP_DELETE_FLY));
238 const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor();
239 SwNode* pAnchorNode = rAnchor.GetAnchorNode();
240 // The positions in Nodes array got shifted.
241 m_nRndId = rAnchor.GetAnchorId();
242 if (RndStdIds::FLY_AS_CHAR == m_nRndId)
244 m_nNodePagePos = pAnchorNode->GetIndex();
245 m_nContentPos = rAnchor.GetAnchorContentOffset();
246 SwTextNode *const pTextNd = pAnchorNode->GetTextNode();
247 assert(pTextNd && "No Textnode found");
248 SwTextFlyCnt* const pAttr = static_cast<SwTextFlyCnt*>(
249 pTextNd->GetTextAttrForCharAt( m_nContentPos, RES_TXTATR_FLYCNT ) );
250 // attribute is still in TextNode, delete
251 if( pAttr && pAttr->GetFlyCnt().GetFrameFormat() == m_pFrameFormat )
253 // Pointer to 0, do not delete
254 const_cast<SwFormatFlyCnt&>(pAttr->GetFlyCnt()).SetFlyFormat();
255 pTextNd->EraseText( *rAnchor.GetContentAnchor(), 1 );
258 else if (RndStdIds::FLY_AT_CHAR == m_nRndId)
260 m_nNodePagePos = pAnchorNode->GetIndex();
261 m_nContentPos = rAnchor.GetAnchorContentOffset();
263 else if ((RndStdIds::FLY_AT_PARA == m_nRndId) || (RndStdIds::FLY_AT_FLY == m_nRndId))
265 m_nNodePagePos = pAnchorNode->GetIndex();
267 else
269 m_nNodePagePos = SwNodeOffset(rAnchor.GetPageNum());
272 m_pFrameFormat->ResetFormatAttr( RES_ANCHOR ); // delete anchor
274 // delete from array
275 sw::SpzFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats();
276 rFlyFormats.erase(static_cast<sw::SpzFrameFormat*>(m_pFrameFormat));
279 SwUndoInsLayFormat::SwUndoInsLayFormat( SwFrameFormat* pFormat, SwNodeOffset nNodeIdx, sal_Int32 nCntIdx )
280 : SwUndoFlyBase( pFormat, RES_DRAWFRMFMT == pFormat->Which() ?
281 SwUndoId::INSDRAWFMT : SwUndoId::INSLAYFMT ),
282 mnCursorSaveIndexPara( nNodeIdx ), mnCursorSaveIndexPos( nCntIdx )
284 const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor();
285 m_nRndId = rAnchor.GetAnchorId();
286 m_bDelFormat = false;
287 // note: SwUndoInsLayFormat is called with the content being fully inserted
288 // from most places but with only an empty content section from
289 // CopyLayoutFormat(); it's not necessary here to init m_nNodePagePos
290 // because Undo will do it.
293 SwUndoInsLayFormat::~SwUndoInsLayFormat()
297 void SwUndoInsLayFormat::UndoImpl(::sw::UndoRedoContext & rContext)
299 SwDoc & rDoc(rContext.GetDoc());
300 const SwFormatContent& rContent = m_pFrameFormat->GetContent();
301 if( rContent.GetContentIdx() ) // no content
303 assert(&rContent.GetContentIdx()->GetNodes() == &rDoc.GetNodes());
304 if( mnCursorSaveIndexPara > SwNodeOffset(0) )
306 SwTextNode *const pNode =
307 rDoc.GetNodes()[mnCursorSaveIndexPara]->GetTextNode();
308 if( pNode )
310 SwNodeIndex aIdx( rDoc.GetNodes(),
311 rContent.GetContentIdx()->GetIndex() );
312 SwNodeIndex aEndIdx( rDoc.GetNodes(),
313 aIdx.GetNode().EndOfSectionIndex() );
314 SwPosition aPos( *pNode, mnCursorSaveIndexPos );
315 // don't delete bookmarks here, DelFly() will save them in history
316 ::PaMCorrAbs(SwPaM(aIdx, aEndIdx), aPos);
317 // TODO: is aPos actually a sensible pos for e.g. SwXText* ?
321 DelFly(& rDoc);
324 void SwUndoInsLayFormat::RedoImpl(::sw::UndoRedoContext & rContext)
326 InsFly(rContext);
329 void SwUndoInsLayFormat::RepeatImpl(::sw::RepeatContext & rContext)
331 SwDoc *const pDoc = & rContext.GetDoc();
332 // get anchor and reset it
333 SwFormatAnchor aAnchor( m_pFrameFormat->GetAnchor() );
334 if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) ||
335 (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
336 (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId()))
338 SwPosition aPos( *rContext.GetRepeatPaM().GetPoint() );
339 aAnchor.SetAnchor( &aPos );
341 else if( RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId() )
343 SwStartNode const*const pSttNd =
344 rContext.GetRepeatPaM().GetPointNode().FindFlyStartNode();
345 if( pSttNd )
347 SwPosition aPos( *pSttNd );
348 aAnchor.SetAnchor( &aPos );
350 else
352 return ;
355 else if (RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId())
357 aAnchor.SetPageNum( pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetCurrPage( &rContext.GetRepeatPaM() ));
359 else {
360 OSL_FAIL( "What kind of anchor is this?" );
363 (void) pDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *m_pFrameFormat, aAnchor, true, true );
366 OUString SwUndoInsLayFormat::GetComment() const
368 OUString aResult;
370 // HACK: disable caching:
371 // the SfxUndoManager calls GetComment() too early: the pFrameFormat does not
372 // have a SwDrawContact yet, so it will fall back to SwUndo::GetComment(),
373 // which sets pComment to a wrong value.
374 // if (! pComment)
375 if ((true))
378 If frame format is present and has an SdrObject use the undo
379 comment of the SdrObject. Otherwise use the default comment.
381 bool bDone = false;
382 if (m_pFrameFormat)
384 const SdrObject * pSdrObj = m_pFrameFormat->FindSdrObject();
385 if ( pSdrObj )
387 aResult = SdrUndoNewObj::GetComment( *pSdrObj );
388 bDone = true;
392 if (! bDone)
393 aResult = SwUndo::GetComment();
395 else
396 aResult = *maComment;
398 return aResult;
401 static SwUndoId
402 lcl_GetSwUndoId(SwFrameFormat const *const pFrameFormat)
404 if (RES_DRAWFRMFMT != pFrameFormat->Which())
406 const SwFormatContent& rContent = pFrameFormat->GetContent();
407 OSL_ENSURE( rContent.GetContentIdx(), "Fly without content" );
409 SwNodeIndex firstNode(*rContent.GetContentIdx(), 1);
410 SwNoTextNode *const pNoTextNode(firstNode.GetNode().GetNoTextNode());
411 if (pNoTextNode && pNoTextNode->IsGrfNode())
413 return SwUndoId::DELGRF;
415 else if (pNoTextNode && pNoTextNode->IsOLENode())
417 // surprisingly not SwUndoId::DELOLE, which does not seem to work
418 return SwUndoId::DELETE;
421 return SwUndoId::DELLAYFMT;
424 SwUndoDelLayFormat::SwUndoDelLayFormat( SwFrameFormat* pFormat )
425 : SwUndoFlyBase( pFormat, lcl_GetSwUndoId(pFormat) )
426 , m_bShowSelFrame( true )
428 SwDoc* pDoc = pFormat->GetDoc();
429 DelFly( pDoc );
432 SwRewriter SwUndoDelLayFormat::GetRewriter() const
434 SwRewriter aRewriter;
436 SwDoc * pDoc = m_pFrameFormat->GetDoc();
438 if (pDoc)
440 const SwNodeIndex* pIdx = GetMvSttIdx();
441 if( SwNodeOffset(1) == GetMvNodeCnt() && pIdx)
443 SwNode *const pNd = & pIdx->GetNode();
445 if ( pNd->IsNoTextNode() && pNd->IsOLENode())
447 SwOLENode * pOLENd = pNd->GetOLENode();
449 aRewriter.AddRule(UndoArg1, pOLENd->GetDescription());
454 return aRewriter;
457 void SwUndoDelLayFormat::UndoImpl(::sw::UndoRedoContext & rContext)
459 InsFly( rContext, m_bShowSelFrame );
462 void SwUndoDelLayFormat::RedoImpl(::sw::UndoRedoContext & rContext)
464 SwDoc & rDoc(rContext.GetDoc());
465 const SwFormatContent& rContent = m_pFrameFormat->GetContent();
466 if( rContent.GetContentIdx() ) // no content
468 RemoveIdxFromSection(rDoc, rContent.GetContentIdx()->GetIndex());
471 DelFly(& rDoc);
474 void SwUndoDelLayFormat::RedoForRollback()
476 const SwFormatContent& rContent = m_pFrameFormat->GetContent();
477 if( rContent.GetContentIdx() ) // no content
478 RemoveIdxFromSection( *m_pFrameFormat->GetDoc(),
479 rContent.GetContentIdx()->GetIndex() );
481 DelFly( m_pFrameFormat->GetDoc() );
484 SwUndoSetFlyFormat::SwUndoSetFlyFormat( SwFrameFormat& rFlyFormat, const SwFrameFormat& rNewFrameFormat )
485 : SwUndo( SwUndoId::SETFLYFRMFMT, rFlyFormat.GetDoc() ), SwClient( &rFlyFormat ), m_pFrameFormat( &rFlyFormat ),
486 m_DerivedFromFormatName( rFlyFormat.IsDefault() ? u""_ustr : rFlyFormat.DerivedFrom()->GetName() ),
487 m_NewFormatName( rNewFrameFormat.GetName() ),
488 m_oItemSet( std::in_place, *rFlyFormat.GetAttrSet().GetPool(),
489 rFlyFormat.GetAttrSet().GetRanges() ),
490 m_nOldNode( 0 ), m_nNewNode( 0 ),
491 m_nOldContent( 0 ), m_nNewContent( 0 ),
492 m_nOldAnchorType( RndStdIds::FLY_AT_PARA ), m_nNewAnchorType( RndStdIds::FLY_AT_PARA ), m_bAnchorChanged( false )
496 SwRewriter SwUndoSetFlyFormat::GetRewriter() const
498 SwRewriter aRewriter;
500 aRewriter.AddRule(UndoArg1, m_NewFormatName);
502 return aRewriter;
505 SwUndoSetFlyFormat::~SwUndoSetFlyFormat()
509 void SwUndoSetFlyFormat::GetAnchor( SwFormatAnchor& rAnchor,
510 SwNodeOffset nNode, sal_Int32 nContent )
512 RndStdIds nAnchorTyp = rAnchor.GetAnchorId();
513 if (RndStdIds::FLY_AT_PAGE != nAnchorTyp)
515 SwNode* pNd = m_pFrameFormat->GetDoc()->GetNodes()[ nNode ];
517 if( RndStdIds::FLY_AT_FLY == nAnchorTyp
518 ? ( !pNd->IsStartNode() || SwFlyStartNode !=
519 static_cast<SwStartNode*>(pNd)->GetStartNodeType() )
520 : !pNd->IsTextNode() )
522 pNd = nullptr; // invalid position
524 else
526 SwPosition aPos( *pNd );
527 if ((RndStdIds::FLY_AS_CHAR == nAnchorTyp) ||
528 (RndStdIds::FLY_AT_CHAR == nAnchorTyp))
530 if (nContent > pNd->GetTextNode()->GetText().getLength())
532 pNd = nullptr; // invalid position
534 else
536 aPos.SetContent(nContent);
539 if ( pNd )
541 rAnchor.SetAnchor( &aPos );
545 if( !pNd )
547 // invalid position - assign first page
548 rAnchor.SetType( RndStdIds::FLY_AT_PAGE );
549 rAnchor.SetPageNum( 1 );
552 else
553 rAnchor.SetPageNum( nContent );
556 void SwUndoSetFlyFormat::UndoImpl(::sw::UndoRedoContext & rContext)
558 SwDoc & rDoc = rContext.GetDoc();
560 // Is the new Format still existent?
561 SwFrameFormat* pDerivedFromFrameFormat = rDoc.FindFrameFormatByName(m_DerivedFromFormatName);
562 if (!pDerivedFromFrameFormat)
563 return;
565 if( m_bAnchorChanged )
566 m_pFrameFormat->DelFrames();
568 if( m_pFrameFormat->DerivedFrom() != pDerivedFromFrameFormat)
569 m_pFrameFormat->SetDerivedFrom(pDerivedFromFrameFormat);
571 SfxItemIter aIter( *m_oItemSet );
572 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
574 if( IsInvalidItem( pItem ))
575 m_pFrameFormat->ResetFormatAttr( aIter.GetCurWhich() );
576 else
577 m_pFrameFormat->SetFormatAttr( *pItem );
580 if( m_bAnchorChanged )
582 const SwFormatAnchor& rOldAnch = m_pFrameFormat->GetAnchor();
583 if (RndStdIds::FLY_AS_CHAR == rOldAnch.GetAnchorId())
585 // With InContents it's tricky: the text attribute needs to be
586 // deleted. Unfortunately, this not only destroys the Frames but
587 // also the format. To prevent that, first detach the
588 // connection between attribute and format.
589 SwNode *pAnchorNode = rOldAnch.GetAnchorNode();
590 SwTextNode *pTextNode = pAnchorNode->GetTextNode();
591 OSL_ENSURE( pTextNode->HasHints(), "Missing FlyInCnt-Hint." );
592 const sal_Int32 nIdx = rOldAnch.GetAnchorContentOffset();
593 SwTextAttr * pHint = pTextNode->GetTextAttrForCharAt(
594 nIdx, RES_TXTATR_FLYCNT );
595 assert(pHint && "Missing Hint.");
596 OSL_ENSURE( pHint->Which() == RES_TXTATR_FLYCNT,
597 "Missing FlyInCnt-Hint." );
598 OSL_ENSURE( pHint->GetFlyCnt().GetFrameFormat() == m_pFrameFormat,
599 "Wrong TextFlyCnt-Hint." );
600 const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()).SetFlyFormat();
602 // Connection is now detached, therefore the attribute can be
603 // deleted
604 pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
607 // reposition anchor
608 SwFormatAnchor aNewAnchor( m_nOldAnchorType );
609 GetAnchor( aNewAnchor, m_nOldNode, m_nOldContent );
610 m_pFrameFormat->SetFormatAttr( aNewAnchor );
612 if (RndStdIds::FLY_AS_CHAR == aNewAnchor.GetAnchorId())
614 SwNode* pAnchorNode = aNewAnchor.GetAnchorNode();
615 SwFormatFlyCnt aFormat( m_pFrameFormat );
616 pAnchorNode->GetTextNode()->InsertItem( aFormat,
617 m_nOldContent, 0 );
620 m_pFrameFormat->MakeFrames();
622 rContext.SetSelections(m_pFrameFormat, nullptr);
625 void SwUndoSetFlyFormat::RedoImpl(::sw::UndoRedoContext & rContext)
627 SwDoc & rDoc = rContext.GetDoc();
629 // Is the new Format still existent?
630 SwFrameFormat* pNewFrameFormat = rDoc.FindFrameFormatByName(m_NewFormatName);
631 if (!pNewFrameFormat)
632 return;
634 if( m_bAnchorChanged )
636 SwFormatAnchor aNewAnchor( m_nNewAnchorType );
637 GetAnchor( aNewAnchor, m_nNewNode, m_nNewContent );
638 SfxItemSet aSet( rDoc.GetAttrPool(), aFrameFormatSetRange );
639 aSet.Put( aNewAnchor );
640 rDoc.SetFrameFormatToFly( *m_pFrameFormat, *pNewFrameFormat, &aSet );
642 else
643 rDoc.SetFrameFormatToFly( *m_pFrameFormat, *pNewFrameFormat);
645 rContext.SetSelections(m_pFrameFormat, nullptr);
648 void SwUndoSetFlyFormat::PutAttr( sal_uInt16 nWhich, const SfxPoolItem* pItem )
650 if( pItem && !SfxPoolItem::areSame(pItem, GetDfltAttr( nWhich ) ) )
652 // Special treatment for this anchor
653 if( RES_ANCHOR == nWhich )
655 // only keep the first change
656 OSL_ENSURE( !m_bAnchorChanged, "multiple changes of an anchor are not allowed!" );
658 m_bAnchorChanged = true;
660 const SwFormatAnchor* pAnchor = static_cast<const SwFormatAnchor*>(pItem);
661 m_nOldAnchorType = pAnchor->GetAnchorId();
662 switch( m_nOldAnchorType )
664 case RndStdIds::FLY_AS_CHAR:
665 case RndStdIds::FLY_AT_CHAR:
666 m_nOldContent = pAnchor->GetAnchorContentOffset();
667 [[fallthrough]];
668 case RndStdIds::FLY_AT_PARA:
669 case RndStdIds::FLY_AT_FLY:
670 m_nOldNode = pAnchor->GetAnchorNode()->GetIndex();
671 break;
673 default:
674 m_nOldContent = pAnchor->GetPageNum();
677 pAnchor = &m_pFrameFormat->GetAnchor();
678 m_nNewAnchorType = pAnchor->GetAnchorId();
679 switch( m_nNewAnchorType )
681 case RndStdIds::FLY_AS_CHAR:
682 case RndStdIds::FLY_AT_CHAR:
683 m_nNewContent = pAnchor->GetAnchorContentOffset();
684 [[fallthrough]];
685 case RndStdIds::FLY_AT_PARA:
686 case RndStdIds::FLY_AT_FLY:
687 m_nNewNode = pAnchor->GetAnchorNode()->GetIndex();
688 break;
690 default:
691 m_nNewContent = pAnchor->GetPageNum();
694 else
695 m_oItemSet->Put( *pItem );
697 else
698 m_oItemSet->InvalidateItem( nWhich );
701 void SwUndoSetFlyFormat::SwClientNotify(const SwModify&, const SfxHint& rHint)
703 if (rHint.GetId() != SfxHintId::SwLegacyModify)
704 return;
705 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
706 if(!pLegacy->m_pOld)
707 return;
708 const sal_uInt16 nWhich = pLegacy->m_pOld->Which();
709 if(nWhich < POOLATTR_END)
710 PutAttr(nWhich, pLegacy->m_pOld);
711 else if(RES_ATTRSET_CHG == nWhich)
713 SfxItemIter aIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet());
714 for(const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
715 PutAttr(pItem->Which(), pItem);
719 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */