diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/undo/undobj1.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/undo/undobj1.cxx')
-rw-r--r-- | sw/source/core/undo/undobj1.cxx | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx new file mode 100644 index 0000000000..f0430b965b --- /dev/null +++ b/sw/source/core/undo/undobj1.cxx @@ -0,0 +1,720 @@ +/* -*- 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 <libxml/xmlwriter.h> + +#include <svl/itemiter.hxx> +#include <svx/svdundo.hxx> +#include <osl/diagnose.h> +#include <hintids.hxx> +#include <hints.hxx> +#include <fmtflcnt.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <txtflcnt.hxx> +#include <frmfmt.hxx> +#include <UndoCore.hxx> +#include <rolbck.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <rootfrm.hxx> +#include <swundo.hxx> +#include <pam.hxx> +#include <mvsave.hxx> +#include <ndtxt.hxx> +#include <ndole.hxx> +#include <frameformats.hxx> +#include <svx/svdobj.hxx> + +SwUndoFlyBase::SwUndoFlyBase( SwFrameFormat* pFormat, SwUndoId nUndoId ) + : SwUndo(nUndoId, pFormat->GetDoc()) + , m_pFrameFormat(pFormat) + , m_nNodePagePos(0) + , m_nContentPos(0) + , m_nRndId(RndStdIds::FLY_AT_PARA) + , m_bDelFormat(false) +{ +} + +SwUndoFlyBase::~SwUndoFlyBase() +{ + if( m_bDelFormat ) // delete during an Undo? + { + if (const auto& pTextBoxes = m_pFrameFormat->GetOtherTextBoxFormats()) + { + // Clear and unregister before release. + if (m_pFrameFormat->Which() == RES_FLYFRMFMT) + pTextBoxes->DelTextBox(m_pFrameFormat); + + if (m_pFrameFormat->Which() == RES_DRAWFRMFMT) + pTextBoxes->ClearAll(); + + // clear that before delete + m_pFrameFormat->SetOtherTextBoxFormats(nullptr); + } + delete m_pFrameFormat; + } +} + +void SwUndoFlyBase::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoFlyBase")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nNodePagePos"), + BAD_CAST(OString::number(sal_Int32(m_nNodePagePos)).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nContentPos"), + BAD_CAST(OString::number(m_nContentPos).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nRndId"), + BAD_CAST(OString::number(static_cast<int>(m_nRndId)).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_bDelFormat"), + BAD_CAST(OString::boolean(m_bDelFormat).getStr())); + + SwUndo::dumpAsXml(pWriter); + SwUndoSaveSection::dumpAsXml(pWriter); + + if (m_pFrameFormat) + { + m_pFrameFormat->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + + // add again into array + sw::SpzFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats(); + rFlyFormats.push_back( static_cast<sw::SpzFrameFormat*>(m_pFrameFormat)); + + // OD 26.06.2003 #108784# - insert 'master' drawing object into drawing page + if ( RES_DRAWFRMFMT == m_pFrameFormat->Which() ) + m_pFrameFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREP_INSERT_FLY)); + + SwFormatAnchor aAnchor( m_nRndId ); + + if (RndStdIds::FLY_AT_PAGE == m_nRndId) + { + aAnchor.SetPageNum( o3tl::narrowing<sal_uInt16>(sal_Int32(m_nNodePagePos)) ); + } + else + { + SwPosition aNewPos(*pDoc->GetNodes()[m_nNodePagePos]); + if ((RndStdIds::FLY_AS_CHAR == m_nRndId) || (RndStdIds::FLY_AT_CHAR == m_nRndId)) + { + aNewPos.SetContent( m_nContentPos ); + } + aAnchor.SetAnchor( &aNewPos ); + } + + m_pFrameFormat->SetFormatAttr( aAnchor ); // reset anchor + + if( RES_DRAWFRMFMT != m_pFrameFormat->Which() ) + { + // get Content and reset ContentAttribute + SwNodeIndex aIdx( pDoc->GetNodes() ); + RestoreSection( pDoc, &aIdx, SwFlyStartNode ); + m_pFrameFormat->SetFormatAttr( SwFormatContent( aIdx.GetNode().GetStartNode() )); + } + + // Set InContentAttribute not until there is content! + // Otherwise the layout would format the Fly beforehand but would not find + // content; this happened with graphics from the internet. + if (RndStdIds::FLY_AS_CHAR == m_nRndId) + { + // there must be at least the attribute in a TextNode + SwContentNode* pCNd = aAnchor.GetAnchorNode()->GetContentNode(); + OSL_ENSURE( pCNd->IsTextNode(), "no Text Node at position." ); + SwFormatFlyCnt aFormat( m_pFrameFormat ); + pCNd->GetTextNode()->InsertItem(aFormat, m_nContentPos, m_nContentPos, SetAttrMode::NOHINTEXPAND); + } + + if (m_pFrameFormat->GetOtherTextBoxFormats()) + { + // recklessly assume that this thing will live longer than the + // SwUndoFlyBase - not sure what could be done if that isn't the case... + m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats( + m_pFrameFormat->GetOtherTextBoxFormats()); + + SdrObject* pSdrObject + = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->FindSdrObject(); + if (pSdrObject && m_pFrameFormat->Which() == RES_FLYFRMFMT) + m_pFrameFormat->GetOtherTextBoxFormats()->AddTextBox(pSdrObject, m_pFrameFormat); + + if (m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->Which() == RES_DRAWFRMFMT) + { + + if (pSdrObject) + { + // Make sure the old UNO wrapper is no longer cached after changing the shape + + // textframe pair. Otherwise we would have a wrapper which doesn't know about its + // textframe, even if it's there. + pSdrObject->setUnoShape(nullptr); + } + } + if (m_pFrameFormat->Which() == RES_FLYFRMFMT) + { + SwFrameFormat* pShapeFormat = m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape(); + pShapeFormat->SetFormatAttr(m_pFrameFormat->GetContent()); + } + } + + m_pFrameFormat->MakeFrames(); + + if( bShowSelFrame ) + { + rContext.SetSelections(m_pFrameFormat, nullptr); + } + + if( GetHistory() ) + GetHistory()->Rollback( pDoc ); + + switch( m_nRndId ) + { + case RndStdIds::FLY_AS_CHAR: + case RndStdIds::FLY_AT_CHAR: + { + const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor(); + m_nNodePagePos = rAnchor.GetAnchorNode()->GetIndex(); + m_nContentPos = rAnchor.GetAnchorContentOffset(); + } + break; + case RndStdIds::FLY_AT_PARA: + case RndStdIds::FLY_AT_FLY: + { + const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor(); + m_nNodePagePos = rAnchor.GetAnchorNode()->GetIndex(); + } + break; + case RndStdIds::FLY_AT_PAGE: + break; + default: break; + } + m_bDelFormat = false; +} + +void SwUndoFlyBase::DelFly( SwDoc* pDoc ) +{ + m_bDelFormat = true; // delete Format in DTOR + m_pFrameFormat->DelFrames(); // destroy Frames + + if (m_pFrameFormat->GetOtherTextBoxFormats()) + { // tdf#108867 clear that pointer + m_pFrameFormat->GetOtherTextBoxFormats()->GetOwnerShape()->SetOtherTextBoxFormats(nullptr); + } + + // all Uno objects should now log themselves off + m_pFrameFormat->RemoveAllUnos(); + + if ( RES_DRAWFRMFMT != m_pFrameFormat->Which() ) + { + // if there is content than save it + const SwFormatContent& rContent = m_pFrameFormat->GetContent(); + OSL_ENSURE( rContent.GetContentIdx(), "Fly without content" ); + + SaveSection( *rContent.GetContentIdx() ); + const_cast<SwFormatContent&>(rContent).SetNewContentIdx( nullptr ); + } + // OD 02.07.2003 #108784# - remove 'master' drawing object from drawing page + else + m_pFrameFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::PREP_DELETE_FLY)); + + const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor(); + SwNode* pAnchorNode = rAnchor.GetAnchorNode(); + // The positions in Nodes array got shifted. + m_nRndId = rAnchor.GetAnchorId(); + if (RndStdIds::FLY_AS_CHAR == m_nRndId) + { + m_nNodePagePos = pAnchorNode->GetIndex(); + m_nContentPos = rAnchor.GetAnchorContentOffset(); + SwTextNode *const pTextNd = pAnchorNode->GetTextNode(); + OSL_ENSURE( pTextNd, "No Textnode found" ); + SwTextFlyCnt* const pAttr = static_cast<SwTextFlyCnt*>( + pTextNd->GetTextAttrForCharAt( m_nContentPos, RES_TXTATR_FLYCNT ) ); + // attribute is still in TextNode, delete + if( pAttr && pAttr->GetFlyCnt().GetFrameFormat() == m_pFrameFormat ) + { + // Pointer to 0, do not delete + const_cast<SwFormatFlyCnt&>(pAttr->GetFlyCnt()).SetFlyFormat(); + pTextNd->EraseText( *rAnchor.GetContentAnchor(), 1 ); + } + } + else if (RndStdIds::FLY_AT_CHAR == m_nRndId) + { + m_nNodePagePos = pAnchorNode->GetIndex(); + m_nContentPos = rAnchor.GetAnchorContentOffset(); + } + else if ((RndStdIds::FLY_AT_PARA == m_nRndId) || (RndStdIds::FLY_AT_FLY == m_nRndId)) + { + m_nNodePagePos = pAnchorNode->GetIndex(); + } + else + { + m_nNodePagePos = SwNodeOffset(rAnchor.GetPageNum()); + } + + m_pFrameFormat->ResetFormatAttr( RES_ANCHOR ); // delete anchor + + // delete from array + sw::SpzFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats(); + rFlyFormats.erase(static_cast<sw::SpzFrameFormat*>(m_pFrameFormat)); +} + +SwUndoInsLayFormat::SwUndoInsLayFormat( SwFrameFormat* pFormat, SwNodeOffset nNodeIdx, sal_Int32 nCntIdx ) + : SwUndoFlyBase( pFormat, RES_DRAWFRMFMT == pFormat->Which() ? + SwUndoId::INSDRAWFMT : SwUndoId::INSLAYFMT ), + mnCursorSaveIndexPara( nNodeIdx ), mnCursorSaveIndexPos( nCntIdx ) +{ + const SwFormatAnchor& rAnchor = m_pFrameFormat->GetAnchor(); + m_nRndId = rAnchor.GetAnchorId(); + m_bDelFormat = false; + // note: SwUndoInsLayFormat is called with the content being fully inserted + // from most places but with only an empty content section from + // CopyLayoutFormat(); it's not necessary here to init m_nNodePagePos + // because Undo will do it. +} + +SwUndoInsLayFormat::~SwUndoInsLayFormat() +{ +} + +void SwUndoInsLayFormat::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + const SwFormatContent& rContent = m_pFrameFormat->GetContent(); + if( rContent.GetContentIdx() ) // no content + { + assert(&rContent.GetContentIdx()->GetNodes() == &rDoc.GetNodes()); + if( mnCursorSaveIndexPara > SwNodeOffset(0) ) + { + SwTextNode *const pNode = + rDoc.GetNodes()[mnCursorSaveIndexPara]->GetTextNode(); + if( pNode ) + { + SwNodeIndex aIdx( rDoc.GetNodes(), + rContent.GetContentIdx()->GetIndex() ); + SwNodeIndex aEndIdx( rDoc.GetNodes(), + aIdx.GetNode().EndOfSectionIndex() ); + SwPosition aPos( *pNode, mnCursorSaveIndexPos ); + // don't delete bookmarks here, DelFly() will save them in history + ::PaMCorrAbs(SwPaM(aIdx, aEndIdx), aPos); + // TODO: is aPos actually a sensible pos for e.g. SwXText* ? + } + } + } + DelFly(& rDoc); +} + +void SwUndoInsLayFormat::RedoImpl(::sw::UndoRedoContext & rContext) +{ + InsFly(rContext); +} + +void SwUndoInsLayFormat::RepeatImpl(::sw::RepeatContext & rContext) +{ + SwDoc *const pDoc = & rContext.GetDoc(); + // get anchor and reset it + SwFormatAnchor aAnchor( m_pFrameFormat->GetAnchor() ); + if ((RndStdIds::FLY_AT_PARA == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AT_CHAR == aAnchor.GetAnchorId()) || + (RndStdIds::FLY_AS_CHAR == aAnchor.GetAnchorId())) + { + SwPosition aPos( *rContext.GetRepeatPaM().GetPoint() ); + aAnchor.SetAnchor( &aPos ); + } + else if( RndStdIds::FLY_AT_FLY == aAnchor.GetAnchorId() ) + { + SwStartNode const*const pSttNd = + rContext.GetRepeatPaM().GetPointNode().FindFlyStartNode(); + if( pSttNd ) + { + SwPosition aPos( *pSttNd ); + aAnchor.SetAnchor( &aPos ); + } + else + { + return ; + } + } + else if (RndStdIds::FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum( pDoc->getIDocumentLayoutAccess().GetCurrentLayout()->GetCurrPage( &rContext.GetRepeatPaM() )); + } + else { + OSL_FAIL( "What kind of anchor is this?" ); + } + + (void) pDoc->getIDocumentLayoutAccess().CopyLayoutFormat( *m_pFrameFormat, aAnchor, true, true ); +} + +OUString SwUndoInsLayFormat::GetComment() const +{ + OUString aResult; + + // HACK: disable caching: + // the SfxUndoManager calls GetComment() too early: the pFrameFormat does not + // have a SwDrawContact yet, so it will fall back to SwUndo::GetComment(), + // which sets pComment to a wrong value. +// if (! pComment) + if ((true)) + { + /* + If frame format is present and has an SdrObject use the undo + comment of the SdrObject. Otherwise use the default comment. + */ + bool bDone = false; + if (m_pFrameFormat) + { + const SdrObject * pSdrObj = m_pFrameFormat->FindSdrObject(); + if ( pSdrObj ) + { + aResult = SdrUndoNewObj::GetComment( *pSdrObj ); + bDone = true; + } + } + + if (! bDone) + aResult = SwUndo::GetComment(); + } + else + aResult = *maComment; + + return aResult; +} + +static SwUndoId +lcl_GetSwUndoId(SwFrameFormat const *const pFrameFormat) +{ + if (RES_DRAWFRMFMT != pFrameFormat->Which()) + { + const SwFormatContent& rContent = pFrameFormat->GetContent(); + OSL_ENSURE( rContent.GetContentIdx(), "Fly without content" ); + + SwNodeIndex firstNode(*rContent.GetContentIdx(), 1); + SwNoTextNode *const pNoTextNode(firstNode.GetNode().GetNoTextNode()); + if (pNoTextNode && pNoTextNode->IsGrfNode()) + { + return SwUndoId::DELGRF; + } + else if (pNoTextNode && pNoTextNode->IsOLENode()) + { + // surprisingly not SwUndoId::DELOLE, which does not seem to work + return SwUndoId::DELETE; + } + } + return SwUndoId::DELLAYFMT; +} + +SwUndoDelLayFormat::SwUndoDelLayFormat( SwFrameFormat* pFormat ) + : SwUndoFlyBase( pFormat, lcl_GetSwUndoId(pFormat) ) + , m_bShowSelFrame( true ) +{ + SwDoc* pDoc = pFormat->GetDoc(); + DelFly( pDoc ); +} + +SwRewriter SwUndoDelLayFormat::GetRewriter() const +{ + SwRewriter aRewriter; + + SwDoc * pDoc = m_pFrameFormat->GetDoc(); + + if (pDoc) + { + const SwNodeIndex* pIdx = GetMvSttIdx(); + if( SwNodeOffset(1) == GetMvNodeCnt() && pIdx) + { + SwNode *const pNd = & pIdx->GetNode(); + + if ( pNd->IsNoTextNode() && pNd->IsOLENode()) + { + SwOLENode * pOLENd = pNd->GetOLENode(); + + aRewriter.AddRule(UndoArg1, pOLENd->GetDescription()); + } + } + } + + return aRewriter; +} + +void SwUndoDelLayFormat::UndoImpl(::sw::UndoRedoContext & rContext) +{ + InsFly( rContext, m_bShowSelFrame ); +} + +void SwUndoDelLayFormat::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc(rContext.GetDoc()); + const SwFormatContent& rContent = m_pFrameFormat->GetContent(); + if( rContent.GetContentIdx() ) // no content + { + RemoveIdxFromSection(rDoc, rContent.GetContentIdx()->GetIndex()); + } + + DelFly(& rDoc); +} + +void SwUndoDelLayFormat::RedoForRollback() +{ + const SwFormatContent& rContent = m_pFrameFormat->GetContent(); + if( rContent.GetContentIdx() ) // no content + RemoveIdxFromSection( *m_pFrameFormat->GetDoc(), + rContent.GetContentIdx()->GetIndex() ); + + DelFly( m_pFrameFormat->GetDoc() ); +} + +SwUndoSetFlyFormat::SwUndoSetFlyFormat( SwFrameFormat& rFlyFormat, const SwFrameFormat& rNewFrameFormat ) + : SwUndo( SwUndoId::SETFLYFRMFMT, rFlyFormat.GetDoc() ), SwClient( &rFlyFormat ), m_pFrameFormat( &rFlyFormat ), + m_DerivedFromFormatName( rFlyFormat.IsDefault() ? "" : rFlyFormat.DerivedFrom()->GetName() ), + m_NewFormatName( rNewFrameFormat.GetName() ), + m_oItemSet( std::in_place, *rFlyFormat.GetAttrSet().GetPool(), + rFlyFormat.GetAttrSet().GetRanges() ), + m_nOldNode( 0 ), m_nNewNode( 0 ), + m_nOldContent( 0 ), m_nNewContent( 0 ), + m_nOldAnchorType( RndStdIds::FLY_AT_PARA ), m_nNewAnchorType( RndStdIds::FLY_AT_PARA ), m_bAnchorChanged( false ) +{ +} + +SwRewriter SwUndoSetFlyFormat::GetRewriter() const +{ + SwRewriter aRewriter; + + aRewriter.AddRule(UndoArg1, m_NewFormatName); + + return aRewriter; +} + +SwUndoSetFlyFormat::~SwUndoSetFlyFormat() +{ +} + +void SwUndoSetFlyFormat::GetAnchor( SwFormatAnchor& rAnchor, + SwNodeOffset nNode, sal_Int32 nContent ) +{ + RndStdIds nAnchorTyp = rAnchor.GetAnchorId(); + if (RndStdIds::FLY_AT_PAGE != nAnchorTyp) + { + SwNode* pNd = m_pFrameFormat->GetDoc()->GetNodes()[ nNode ]; + + if( RndStdIds::FLY_AT_FLY == nAnchorTyp + ? ( !pNd->IsStartNode() || SwFlyStartNode != + static_cast<SwStartNode*>(pNd)->GetStartNodeType() ) + : !pNd->IsTextNode() ) + { + pNd = nullptr; // invalid position + } + else + { + SwPosition aPos( *pNd ); + if ((RndStdIds::FLY_AS_CHAR == nAnchorTyp) || + (RndStdIds::FLY_AT_CHAR == nAnchorTyp)) + { + if (nContent > pNd->GetTextNode()->GetText().getLength()) + { + pNd = nullptr; // invalid position + } + else + { + aPos.SetContent(nContent); + } + } + if ( pNd ) + { + rAnchor.SetAnchor( &aPos ); + } + } + + if( !pNd ) + { + // invalid position - assign first page + rAnchor.SetType( RndStdIds::FLY_AT_PAGE ); + rAnchor.SetPageNum( 1 ); + } + } + else + rAnchor.SetPageNum( nContent ); +} + +void SwUndoSetFlyFormat::UndoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + // Is the new Format still existent? + SwFrameFormat* pDerivedFromFrameFormat = rDoc.FindFrameFormatByName(m_DerivedFromFormatName); + if (!pDerivedFromFrameFormat) + return; + + if( m_bAnchorChanged ) + m_pFrameFormat->DelFrames(); + + if( m_pFrameFormat->DerivedFrom() != pDerivedFromFrameFormat) + m_pFrameFormat->SetDerivedFrom(pDerivedFromFrameFormat); + + SfxItemIter aIter( *m_oItemSet ); + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + if( IsInvalidItem( pItem )) + m_pFrameFormat->ResetFormatAttr( m_oItemSet->GetWhichByOffset( + aIter.GetCurPos() )); + else + m_pFrameFormat->SetFormatAttr( *pItem ); + } + + if( m_bAnchorChanged ) + { + const SwFormatAnchor& rOldAnch = m_pFrameFormat->GetAnchor(); + if (RndStdIds::FLY_AS_CHAR == rOldAnch.GetAnchorId()) + { + // With InContents it's tricky: the text attribute needs to be + // deleted. Unfortunately, this not only destroys the Frames but + // also the format. To prevent that, first detach the + // connection between attribute and format. + SwNode *pAnchorNode = rOldAnch.GetAnchorNode(); + SwTextNode *pTextNode = pAnchorNode->GetTextNode(); + OSL_ENSURE( pTextNode->HasHints(), "Missing FlyInCnt-Hint." ); + const sal_Int32 nIdx = rOldAnch.GetAnchorContentOffset(); + SwTextAttr * pHint = pTextNode->GetTextAttrForCharAt( + nIdx, RES_TXTATR_FLYCNT ); + assert(pHint && "Missing Hint."); + OSL_ENSURE( pHint->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + OSL_ENSURE( pHint->GetFlyCnt().GetFrameFormat() == m_pFrameFormat, + "Wrong TextFlyCnt-Hint." ); + const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()).SetFlyFormat(); + + // Connection is now detached, therefore the attribute can be + // deleted + pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); + } + + // reposition anchor + SwFormatAnchor aNewAnchor( m_nOldAnchorType ); + GetAnchor( aNewAnchor, m_nOldNode, m_nOldContent ); + m_pFrameFormat->SetFormatAttr( aNewAnchor ); + + if (RndStdIds::FLY_AS_CHAR == aNewAnchor.GetAnchorId()) + { + SwNode* pAnchorNode = aNewAnchor.GetAnchorNode(); + SwFormatFlyCnt aFormat( m_pFrameFormat ); + pAnchorNode->GetTextNode()->InsertItem( aFormat, + m_nOldContent, 0 ); + } + + m_pFrameFormat->MakeFrames(); + } + rContext.SetSelections(m_pFrameFormat, nullptr); +} + +void SwUndoSetFlyFormat::RedoImpl(::sw::UndoRedoContext & rContext) +{ + SwDoc & rDoc = rContext.GetDoc(); + + // Is the new Format still existent? + SwFrameFormat* pNewFrameFormat = rDoc.FindFrameFormatByName(m_NewFormatName); + if (!pNewFrameFormat) + return; + + if( m_bAnchorChanged ) + { + SwFormatAnchor aNewAnchor( m_nNewAnchorType ); + GetAnchor( aNewAnchor, m_nNewNode, m_nNewContent ); + SfxItemSet aSet( rDoc.GetAttrPool(), aFrameFormatSetRange ); + aSet.Put( aNewAnchor ); + rDoc.SetFrameFormatToFly( *m_pFrameFormat, *pNewFrameFormat, &aSet ); + } + else + rDoc.SetFrameFormatToFly( *m_pFrameFormat, *pNewFrameFormat); + + rContext.SetSelections(m_pFrameFormat, nullptr); +} + +void SwUndoSetFlyFormat::PutAttr( sal_uInt16 nWhich, const SfxPoolItem* pItem ) +{ + if( pItem && !SfxPoolItem::areSame(pItem, GetDfltAttr( nWhich ) ) ) + { + // Special treatment for this anchor + if( RES_ANCHOR == nWhich ) + { + // only keep the first change + OSL_ENSURE( !m_bAnchorChanged, "multiple changes of an anchor are not allowed!" ); + + m_bAnchorChanged = true; + + const SwFormatAnchor* pAnchor = static_cast<const SwFormatAnchor*>(pItem); + m_nOldAnchorType = pAnchor->GetAnchorId(); + switch( m_nOldAnchorType ) + { + case RndStdIds::FLY_AS_CHAR: + case RndStdIds::FLY_AT_CHAR: + m_nOldContent = pAnchor->GetAnchorContentOffset(); + [[fallthrough]]; + case RndStdIds::FLY_AT_PARA: + case RndStdIds::FLY_AT_FLY: + m_nOldNode = pAnchor->GetAnchorNode()->GetIndex(); + break; + + default: + m_nOldContent = pAnchor->GetPageNum(); + } + + pAnchor = &m_pFrameFormat->GetAnchor(); + m_nNewAnchorType = pAnchor->GetAnchorId(); + switch( m_nNewAnchorType ) + { + case RndStdIds::FLY_AS_CHAR: + case RndStdIds::FLY_AT_CHAR: + m_nNewContent = pAnchor->GetAnchorContentOffset(); + [[fallthrough]]; + case RndStdIds::FLY_AT_PARA: + case RndStdIds::FLY_AT_FLY: + m_nNewNode = pAnchor->GetAnchorNode()->GetIndex(); + break; + + default: + m_nNewContent = pAnchor->GetPageNum(); + } + } + else + m_oItemSet->Put( *pItem ); + } + else + m_oItemSet->InvalidateItem( nWhich ); +} + +void SwUndoSetFlyFormat::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (rHint.GetId() != SfxHintId::SwLegacyModify) + return; + auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint); + if(!pLegacy->m_pOld) + return; + const sal_uInt16 nWhich = pLegacy->m_pOld->Which(); + if(nWhich < POOLATTR_END) + PutAttr(nWhich, pLegacy->m_pOld); + else if(RES_ATTRSET_CHG == nWhich) + { + SfxItemIter aIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet()); + for(const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + PutAttr(pItem->Which(), pItem); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |