android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / undo / unattr.cxx
blob9b6a12a437076db1899b1d90232dfa89367d94b5
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 <sal/config.h>
22 #include <utility>
24 #include <UndoAttribute.hxx>
25 #include <svl/itemiter.hxx>
26 #include <editeng/tstpitem.hxx>
27 #include <svx/svdobj.hxx>
28 #include <osl/diagnose.h>
29 #include <hintids.hxx>
30 #include <fmtflcnt.hxx>
31 #include <txtftn.hxx>
32 #include <fmtanchr.hxx>
33 #include <fmtfsize.hxx>
34 #include <frmfmt.hxx>
35 #include <fmtcntnt.hxx>
36 #include <ftnidx.hxx>
37 #include <doc.hxx>
38 #include <IDocumentLayoutAccess.hxx>
39 #include <IDocumentRedlineAccess.hxx>
40 #include <IDocumentState.hxx>
41 #include <IDocumentUndoRedo.hxx>
42 #include <IShellCursorSupplier.hxx>
43 #include <docary.hxx>
44 #include <swcrsr.hxx>
45 #include <swundo.hxx>
46 #include <pam.hxx>
47 #include <ndtxt.hxx>
48 #include <swtable.hxx>
49 #include <swtblfmt.hxx>
50 #include <UndoCore.hxx>
51 #include <hints.hxx>
52 #include <rolbck.hxx>
53 #include <ndnotxt.hxx>
54 #include <ftninfo.hxx>
55 #include <redline.hxx>
56 #include <section.hxx>
57 #include <charfmt.hxx>
58 #include <calbck.hxx>
59 #include <frameformats.hxx>
60 #include <editsh.hxx>
62 SwUndoFormatAttrHelper::SwUndoFormatAttrHelper(SwFormat& rFormat, bool bSvDrwPt)
63 : SwClient(&rFormat)
64 , m_rFormat(rFormat)
65 , m_bSaveDrawPt(bSvDrwPt)
69 void SwUndoFormatAttrHelper::SwClientNotify(const SwModify&, const SfxHint& rHint)
71 if (rHint.GetId() != SfxHintId::SwLegacyModify)
72 return;
73 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
74 if(!pLegacy->m_pOld)
75 return;
76 assert(pLegacy->m_pOld->Which() != RES_OBJECTDYING);
77 if(!pLegacy->m_pNew)
78 return;
79 const SwDoc& rDoc = *m_rFormat.GetDoc();
80 auto pOld = pLegacy->m_pOld;
81 if(POOLATTR_END >= pLegacy->m_pOld->Which()) {
82 if(!GetUndo())
83 m_pUndo.reset(new SwUndoFormatAttr(*pOld, m_rFormat, m_bSaveDrawPt));
84 else
85 m_pUndo->PutAttr(*pOld, rDoc);
86 } else if(RES_ATTRSET_CHG == pOld->Which()) {
87 auto& rChgSet = *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet();
88 if(!GetUndo())
89 m_pUndo.reset(new SwUndoFormatAttr(SfxItemSet(rChgSet), m_rFormat, m_bSaveDrawPt));
90 else {
91 SfxItemIter aIter(rChgSet);
92 for(auto pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
93 m_pUndo->PutAttr(*pItem, rDoc);
98 SwDocModifyAndUndoGuard::SwDocModifyAndUndoGuard(SwFormat& format)
99 : doc(format.GetName().isEmpty() ? nullptr : format.GetDoc())
100 , helper(doc ? new SwUndoFormatAttrHelper(format) : nullptr)
104 SwDocModifyAndUndoGuard::~SwDocModifyAndUndoGuard()
106 if (helper && helper->GetUndo())
108 // helper tracks changes, even when DoesUndo is false, to detect modified state
109 if (doc->GetIDocumentUndoRedo().DoesUndo())
110 doc->GetIDocumentUndoRedo().AppendUndo(helper->ReleaseUndo());
112 doc->getIDocumentState().SetModified();
116 SwUndoFormatAttr::SwUndoFormatAttr( SfxItemSet&& rOldSet,
117 SwFormat& rChgFormat,
118 bool bSaveDrawPt )
119 : SwUndo( SwUndoId::INSFMTATTR, rChgFormat.GetDoc() )
120 , m_sFormatName ( rChgFormat.GetName() )
121 // #i56253#
122 , m_oOldSet( std::move( rOldSet ) )
123 , m_nAnchorContentOffset( 0 )
124 , m_nNodeIndex( 0 )
125 , m_nFormatWhich( rChgFormat.Which() )
126 , m_bSaveDrawPt( bSaveDrawPt )
128 assert(m_sFormatName.getLength());
130 Init( rChgFormat );
133 SwUndoFormatAttr::SwUndoFormatAttr( const SfxPoolItem& rItem, SwFormat& rChgFormat,
134 bool bSaveDrawPt )
135 : SwUndo( SwUndoId::INSFMTATTR, rChgFormat.GetDoc() )
136 , m_sFormatName(rChgFormat.GetName())
137 , m_oOldSet( rChgFormat.GetAttrSet().CloneAsValue( false ) )
138 , m_nAnchorContentOffset( 0 )
139 , m_nNodeIndex( 0 )
140 , m_nFormatWhich( rChgFormat.Which() )
141 , m_bSaveDrawPt( bSaveDrawPt )
143 assert(m_sFormatName.getLength());
145 m_oOldSet->Put( rItem );
146 Init( rChgFormat );
149 void SwUndoFormatAttr::Init( const SwFormat & rFormat )
151 // tdf#126017 never save SwNodeIndex, it will go stale
152 m_oOldSet->ClearItem(RES_CNTNT);
153 // treat change of anchor specially
154 if ( SfxItemState::SET == m_oOldSet->GetItemState( RES_ANCHOR, false )) {
155 SaveFlyAnchor( &rFormat, m_bSaveDrawPt );
156 } else if ( RES_FRMFMT == m_nFormatWhich ) {
157 const SwDoc* pDoc = rFormat.GetDoc();
158 auto pTableFormat = dynamic_cast<const SwTableFormat*>(&rFormat);
159 if (pTableFormat && pDoc->GetTableFrameFormats()->ContainsFormat(const_cast<SwTableFormat*>(pTableFormat)))
161 // Table Format: save table position, table formats are volatile!
162 SwTable * pTable = SwIterator<SwTable,SwFormat>( rFormat ).First();
163 if ( pTable ) {
164 m_nNodeIndex = pTable->GetTabSortBoxes()[ 0 ]->GetSttNd()
165 ->FindTableNode()->GetIndex();
167 } else if (dynamic_cast<const SwSectionFormat*>(&rFormat)) {
168 if (auto pContentIndex = rFormat.GetContent().GetContentIdx())
169 m_nNodeIndex = pContentIndex->GetIndex();
170 } else if(auto pBoxFormat = dynamic_cast<const SwTableBoxFormat*>(&rFormat))
172 auto pTableBox = pBoxFormat->GetTableBox();
173 if(pTableBox)
174 m_nNodeIndex = pTableBox->GetSttIdx();
179 SwUndoFormatAttr::~SwUndoFormatAttr()
183 void SwUndoFormatAttr::UndoImpl(::sw::UndoRedoContext & rContext)
185 // OD 2004-10-26 #i35443#
186 // Important note: <Undo(..)> also called by <ReDo(..)>
188 if (!m_oOldSet)
189 return;
191 SwFormat * pFormat = GetFormat(rContext.GetDoc());
192 if (!pFormat)
193 return;
195 // #i35443# - If anchor attribute has been successful
196 // restored, all other attributes are also restored.
197 // Thus, keep track of its restoration
198 bool bAnchorAttrRestored( false );
199 if ( SfxItemState::SET == m_oOldSet->GetItemState( RES_ANCHOR, false )) {
200 bAnchorAttrRestored = RestoreFlyAnchor(rContext);
201 if ( bAnchorAttrRestored ) {
202 // Anchor attribute successful restored.
203 // Thus, keep anchor position for redo
204 SaveFlyAnchor(pFormat);
205 } else {
206 // Anchor attribute not restored due to invalid anchor position.
207 // Thus, delete anchor attribute.
208 m_oOldSet->ClearItem( RES_ANCHOR );
212 if ( bAnchorAttrRestored ) return;
214 SwUndoFormatAttrHelper aTmp( *pFormat, m_bSaveDrawPt );
215 pFormat->SetFormatAttr( *m_oOldSet );
216 if ( aTmp.GetUndo() ) {
217 // transfer ownership of helper object's old set
218 if (aTmp.GetUndo()->m_oOldSet)
219 m_oOldSet.emplace(std::move(*aTmp.GetUndo()->m_oOldSet));
220 else
221 m_oOldSet.reset();
222 } else {
223 m_oOldSet->ClearItem();
226 if ( RES_FLYFRMFMT == m_nFormatWhich || RES_DRAWFRMFMT == m_nFormatWhich ) {
227 rContext.SetSelections(static_cast<SwFrameFormat*>(pFormat), nullptr);
231 // Check if it is still in Doc
232 SwFormat* SwUndoFormatAttr::GetFormat( const SwDoc& rDoc )
234 switch (m_nFormatWhich)
236 case RES_TXTFMTCOLL:
237 case RES_CONDTXTFMTCOLL:
238 return rDoc.FindTextFormatCollByName(m_sFormatName);
240 case RES_GRFFMTCOLL:
241 return rDoc.GetGrfFormatColls()->FindFormatByName(m_sFormatName);
243 case RES_CHRFMT:
244 return rDoc.FindCharFormatByName(m_sFormatName);
246 case RES_FRMFMT:
247 if (m_nNodeIndex && (m_nNodeIndex < rDoc.GetNodes().Count()))
249 SwNode* pNd = rDoc.GetNodes()[m_nNodeIndex];
250 if (pNd->IsTableNode())
252 return static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat();
254 else if (pNd->IsSectionNode())
256 return static_cast<SwSectionNode*>(pNd)->GetSection().GetFormat();
258 else if (pNd->IsStartNode() && (SwTableBoxStartNode ==
259 static_cast<SwStartNode*>(pNd)->GetStartNodeType()))
261 SwTableNode* pTableNode = pNd->FindTableNode();
262 if (pTableNode)
264 SwTableBox* pBox = pTableNode->GetTable().GetTableBox(m_nNodeIndex);
265 if (pBox)
267 return pBox->GetFrameFormat();
272 [[fallthrough]];
273 case RES_DRAWFRMFMT:
274 case RES_FLYFRMFMT:
276 auto it = rDoc.GetSpzFrameFormats()->findByTypeAndName( m_nFormatWhich, m_sFormatName );
277 if( it != rDoc.GetSpzFrameFormats()->typeAndNameEnd() )
278 return *it;
279 SwFormat* pFormat = rDoc.GetFrameFormats()->FindFormatByName(m_sFormatName);
280 if (pFormat)
281 return pFormat;
283 break;
286 return nullptr;
289 void SwUndoFormatAttr::RedoImpl(::sw::UndoRedoContext & rContext)
291 // #i35443# - Because the undo stores the attributes for
292 // redo, the same code as for <Undo(..)> can be applied for <Redo(..)>
293 UndoImpl(rContext);
296 void SwUndoFormatAttr::RepeatImpl(::sw::RepeatContext & rContext)
298 if (!m_oOldSet)
299 return;
301 SwDoc & rDoc(rContext.GetDoc());
303 SwFormat * pFormat = GetFormat(rDoc);
304 if (!pFormat)
305 return;
307 switch ( m_nFormatWhich ) {
308 case RES_GRFFMTCOLL: {
309 SwNoTextNode *const pNd =
310 rContext.GetRepeatPaM().GetPointNode().GetNoTextNode();
311 if( pNd ) {
312 rDoc.SetAttr( pFormat->GetAttrSet(), *pNd->GetFormatColl() );
315 break;
317 case RES_TXTFMTCOLL:
318 case RES_CONDTXTFMTCOLL:
320 SwTextNode *const pNd =
321 rContext.GetRepeatPaM().GetPointNode().GetTextNode();
322 if( pNd ) {
323 rDoc.SetAttr( pFormat->GetAttrSet(), *pNd->GetFormatColl() );
326 break;
328 case RES_FLYFRMFMT: {
329 // Check if the cursor is in a flying frame
330 // Steps: search in all FlyFrameFormats for the FlyContent attribute
331 // and validate if the cursor is in the respective section
332 SwFrameFormat *const pFly =
333 rContext.GetRepeatPaM().GetPointNode().GetFlyFormat();
334 if( pFly ) {
335 // Bug 43672: do not set all attributes!
336 if (SfxItemState::SET ==
337 pFormat->GetAttrSet().GetItemState( RES_CNTNT )) {
338 SfxItemSet aTmpSet( pFormat->GetAttrSet() );
339 aTmpSet.ClearItem( RES_CNTNT );
340 if( aTmpSet.Count() ) {
341 rDoc.SetAttr( aTmpSet, *pFly );
343 } else {
344 rDoc.SetAttr( pFormat->GetAttrSet(), *pFly );
347 break;
352 SwRewriter SwUndoFormatAttr::GetRewriter() const
354 SwRewriter aRewriter;
356 aRewriter.AddRule(UndoArg1, m_sFormatName);
358 return aRewriter;
361 void SwUndoFormatAttr::PutAttr( const SfxPoolItem& rItem, const SwDoc& rDoc )
363 if (RES_CNTNT == rItem.Which())
365 return; // tdf#126017 never save SwNodeIndex, it will go stale
367 m_oOldSet->Put( rItem );
368 if ( RES_ANCHOR == rItem.Which() )
370 SwFormat * pFormat = GetFormat( rDoc );
371 SaveFlyAnchor( pFormat, m_bSaveDrawPt );
375 void SwUndoFormatAttr::SaveFlyAnchor( const SwFormat * pFormat, bool bSvDrwPt )
377 // Format is valid, otherwise you would not reach this point here
378 if( bSvDrwPt ) {
379 if ( RES_DRAWFRMFMT == pFormat->Which() ) {
380 Point aPt( static_cast<const SwFrameFormat*>(pFormat)->FindSdrObject()
381 ->GetRelativePos() );
382 // store old value as attribute, to keep SwUndoFormatAttr small
383 m_oOldSet->Put( SwFormatFrameSize( SwFrameSize::Variable, aPt.X(), aPt.Y() ) );
387 const SwFormatAnchor& rAnchor =
388 m_oOldSet->Get( RES_ANCHOR, false );
389 if( !rAnchor.GetAnchorNode() || rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
390 return;
392 switch( rAnchor.GetAnchorId() ) {
393 case RndStdIds::FLY_AS_CHAR:
394 case RndStdIds::FLY_AT_CHAR:
395 m_nAnchorContentOffset = rAnchor.GetAnchorContentOffset();
396 [[fallthrough]];
397 case RndStdIds::FLY_AT_PARA:
398 case RndStdIds::FLY_AT_FLY:
399 m_nNodeIndex = rAnchor.GetAnchorNode()->GetIndex();
400 break;
401 default:
402 assert(false);
405 SwFormatAnchor aAnchor( rAnchor.GetAnchorId(), 0 );
406 m_oOldSet->Put( aAnchor );
409 // #i35443# - Add return value, type <bool>.
410 // Return value indicates, if anchor attribute is restored.
411 // Note: If anchor attribute is restored, all other existing attributes
412 // are also restored.
413 bool SwUndoFormatAttr::RestoreFlyAnchor(::sw::UndoRedoContext & rContext)
415 SwDoc *const pDoc = & rContext.GetDoc();
416 SwFrameFormat* pFrameFormat = static_cast<SwFrameFormat*>( GetFormat( *pDoc ) );
417 const SwFormatAnchor& rAnchor =
418 m_oOldSet->Get( RES_ANCHOR, false );
420 SwFormatAnchor aNewAnchor( rAnchor.GetAnchorId() );
421 if (RndStdIds::FLY_AT_PAGE != rAnchor.GetAnchorId()) {
422 SwNode* pNd = pDoc->GetNodes()[ m_nNodeIndex ];
424 if ( (RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId())
425 ? ( !pNd->IsStartNode() || (SwFlyStartNode !=
426 static_cast<SwStartNode*>(pNd)->GetStartNodeType()) )
427 : !pNd->IsTextNode() ) {
428 // #i35443# - invalid position.
429 // Thus, anchor attribute not restored
430 return false;
433 SwPosition aPos( *pNd );
434 if ((RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()) ||
435 (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId())) {
436 aPos.SetContent( m_nAnchorContentOffset );
437 if ( aPos.GetContentIndex() > pNd->GetTextNode()->GetText().getLength()) {
438 // #i35443# - invalid position.
439 // Thus, anchor attribute not restored
440 return false;
443 aNewAnchor.SetAnchor( &aPos );
444 } else
445 aNewAnchor.SetPageNum( rAnchor.GetPageNum() );
447 Point aDrawSavePt, aDrawOldPt;
448 if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ) {
449 if( RES_DRAWFRMFMT == pFrameFormat->Which() ) {
450 // get the old cached value
451 const SwFormatFrameSize& rOldSize = m_oOldSet->Get( RES_FRM_SIZE );
452 aDrawSavePt.setX( rOldSize.GetWidth() );
453 aDrawSavePt.setY( rOldSize.GetHeight() );
454 m_oOldSet->ClearItem( RES_FRM_SIZE );
456 // write the current value into cache
457 aDrawOldPt = pFrameFormat->FindSdrObject()->GetRelativePos();
458 } else {
459 pFrameFormat->DelFrames(); // delete Frames
463 const SwFormatAnchor &rOldAnch = pFrameFormat->GetAnchor();
464 // #i54336#
465 // Consider case, that as-character anchored object has moved its anchor position.
466 if (RndStdIds::FLY_AS_CHAR == rOldAnch.GetAnchorId()) {
467 // With InContents it's tricky: the text attribute needs to be deleted.
468 // Unfortunately, this not only destroys the Frames but also the format.
469 // To prevent that, first detach the connection between attribute and
470 // format.
471 SwTextNode *pTextNode = static_cast<SwTextNode*>(rOldAnch.GetAnchorNode());
472 OSL_ENSURE( pTextNode->HasHints(), "Missing FlyInCnt-Hint." );
473 const sal_Int32 nIdx = rOldAnch.GetAnchorContentOffset();
474 SwTextAttr * const pHint =
475 pTextNode->GetTextAttrForCharAt( nIdx, RES_TXTATR_FLYCNT );
476 assert(pHint && "Missing Hint.");
477 OSL_ENSURE( pHint->Which() == RES_TXTATR_FLYCNT,
478 "Missing FlyInCnt-Hint." );
479 OSL_ENSURE( pHint->GetFlyCnt().GetFrameFormat() == pFrameFormat,
480 "Wrong TextFlyCnt-Hint." );
481 const_cast<SwFormatFlyCnt&>(pHint->GetFlyCnt()).SetFlyFormat();
483 // Connection is now detached, therefore the attribute can be deleted
484 pTextNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
488 m_oOldSet->Put( aNewAnchor );
489 SwUndoFormatAttrHelper aTmp( *pFrameFormat, m_bSaveDrawPt );
490 pFrameFormat->SetFormatAttr( *m_oOldSet );
491 if ( aTmp.GetUndo() ) {
492 m_nNodeIndex = aTmp.GetUndo()->m_nNodeIndex;
493 // transfer ownership of helper object's old set
494 if (aTmp.GetUndo()->m_oOldSet)
495 m_oOldSet.emplace(std::move(*aTmp.GetUndo()->m_oOldSet));
496 else
497 m_oOldSet.reset();
498 } else {
499 m_oOldSet->ClearItem();
503 if ( RES_DRAWFRMFMT == pFrameFormat->Which() )
505 // The Draw model also prepared an Undo object for its right positioning
506 // which unfortunately is relative. Therefore block here a position
507 // change of the Contact object by setting the anchor.
508 const SwFormatVertOrient& rVertOrient = pFrameFormat->GetVertOrient();
509 const SwFormatHoriOrient& rHoriOrient = pFrameFormat->GetHoriOrient();
510 Point aFormatPos(rHoriOrient.GetPos(), rVertOrient.GetPos());
511 if (aDrawSavePt != aFormatPos)
513 // If the position would be the same, then skip the call: either it would do nothing or
514 // it would just go wrong.
515 pFrameFormat->CallSwClientNotify(sw::RestoreFlyAnchorHint(aDrawSavePt));
518 // cache the old value again
519 m_oOldSet->Put(SwFormatFrameSize(SwFrameSize::Variable, aDrawOldPt.X(), aDrawOldPt.Y()));
522 if (RndStdIds::FLY_AS_CHAR == aNewAnchor.GetAnchorId()) {
523 SwTextNode* pTextNd = aNewAnchor.GetAnchorNode()->GetTextNode();
524 OSL_ENSURE( pTextNd, "no Text Node at position." );
525 SwFormatFlyCnt aFormat( pFrameFormat );
526 pTextNd->InsertItem( aFormat, aNewAnchor.GetAnchorContentOffset(), 0 );
529 if (RES_DRAWFRMFMT != pFrameFormat->Which())
530 pFrameFormat->MakeFrames();
531 else
533 pFrameFormat->CallSwClientNotify(sw::DrawFrameFormatHint(sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR));
536 rContext.SetSelections(pFrameFormat, nullptr);
538 // #i35443# - anchor attribute restored.
539 return true;
542 SwUndoFormatResetAttr::SwUndoFormatResetAttr( SwFormat& rChangedFormat,
543 const sal_uInt16 nWhichId )
544 : SwUndo( SwUndoId::RESETATTR, rChangedFormat.GetDoc() )
545 , m_pChangedFormat( &rChangedFormat )
546 , m_nWhichId( nWhichId )
548 const SfxPoolItem* pItem = nullptr;
549 if (rChangedFormat.GetItemState(nWhichId, false, &pItem ) == SfxItemState::SET && pItem) {
550 m_pOldItem.reset( pItem->Clone() );
554 SwUndoFormatResetAttr::~SwUndoFormatResetAttr()
558 void SwUndoFormatResetAttr::UndoImpl(::sw::UndoRedoContext &)
560 if (m_pOldItem)
562 m_pChangedFormat->SetFormatAttr( *m_pOldItem );
566 void SwUndoFormatResetAttr::RedoImpl(::sw::UndoRedoContext &)
568 if (m_pOldItem)
570 m_pChangedFormat->ResetFormatAttr( m_nWhichId );
574 SwUndoResetAttr::SwUndoResetAttr( const SwPaM& rRange, sal_uInt16 nFormatId )
575 : SwUndo( SwUndoId::RESETATTR, &rRange.GetDoc() ), SwUndRng( rRange )
576 , m_pHistory( new SwHistory )
577 , m_nFormatId( nFormatId )
581 SwUndoResetAttr::SwUndoResetAttr( const SwPosition& rPos, sal_uInt16 nFormatId )
582 : SwUndo( SwUndoId::RESETATTR, &rPos.GetDoc() )
583 , m_pHistory( new SwHistory )
584 , m_nFormatId( nFormatId )
586 m_nSttNode = m_nEndNode = rPos.GetNodeIndex();
587 m_nSttContent = m_nEndContent = rPos.GetContentIndex();
590 SwUndoResetAttr::~SwUndoResetAttr()
594 void SwUndoResetAttr::UndoImpl(::sw::UndoRedoContext & rContext)
596 // reset old values
597 SwDoc & rDoc = rContext.GetDoc();
598 m_pHistory->TmpRollback( &rDoc, 0 );
599 m_pHistory->SetTmpEnd( m_pHistory->Count() );
601 if ((RES_CONDTXTFMTCOLL == m_nFormatId) &&
602 (m_nSttNode == m_nEndNode) && (m_nSttContent == m_nEndContent)) {
603 SwTextNode* pTNd = rDoc.GetNodes()[ m_nSttNode ]->GetTextNode();
604 if( pTNd )
605 pTNd->DontExpandFormat( m_nSttContent, false );
607 else if (m_nFormatId == RES_TXTATR_REFMARK)
609 rDoc.GetEditShell()->SwViewShell::UpdateFields();
612 AddUndoRedoPaM(rContext);
615 void SwUndoResetAttr::RedoImpl(::sw::UndoRedoContext & rContext)
617 SwDoc & rDoc = rContext.GetDoc();
618 SwPaM & rPam = AddUndoRedoPaM(rContext);
620 switch ( m_nFormatId ) {
621 case RES_CHRFMT:
622 rDoc.RstTextAttrs(rPam);
623 break;
624 case RES_TXTFMTCOLL:
625 rDoc.ResetAttrs(rPam, false, m_Ids );
626 break;
627 case RES_CONDTXTFMTCOLL:
628 rDoc.ResetAttrs(rPam, true, m_Ids );
630 break;
631 case RES_TXTATR_TOXMARK:
632 // special treatment for TOXMarks
634 SwTOXMarks aArr;
635 SwNodeIndex aIdx( rDoc.GetNodes(), m_nSttNode );
636 SwPosition aPos( aIdx, aIdx.GetNode().GetContentNode(), m_nSttContent );
638 sal_uInt16 nCnt = SwDoc::GetCurTOXMark( aPos, aArr );
639 if( nCnt ) {
640 if( 1 < nCnt ) {
641 // search for the right one
642 SwHistoryHint* pHHint = (GetHistory())[ 0 ];
643 if( pHHint && HSTRY_SETTOXMARKHNT == pHHint->Which() ) {
644 while( nCnt ) {
645 if ( static_cast<SwHistorySetTOXMark*>(pHHint)
646 ->IsEqual( *aArr[ --nCnt ] ) ) {
647 ++nCnt;
648 break;
651 } else
652 nCnt = 0;
654 // found one, thus delete it
655 if( nCnt-- ) {
656 rDoc.DeleteTOXMark( aArr[ nCnt ] );
660 break;
661 case RES_TXTATR_REFMARK:
663 SfxItemPool::Item2Range aRange = rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK);
664 SwHistoryHint* pHistoryHint = GetHistory()[0];
665 if (pHistoryHint && HSTRY_SETREFMARKHNT == pHistoryHint->Which())
667 for (const SfxPoolItem* pItem : aRange)
669 assert(dynamic_cast<const SwFormatRefMark*>(pItem));
670 const auto pFormatRefMark = static_cast<const SwFormatRefMark*>(pItem);
671 if (static_cast<SwHistorySetRefMark*>(pHistoryHint)->GetRefName() ==
672 pFormatRefMark->GetRefName())
674 rDoc.DeleteFormatRefMark(pFormatRefMark);
675 rDoc.GetEditShell()->SwViewShell::UpdateFields();
676 break;
681 break;
685 void SwUndoResetAttr::RepeatImpl(::sw::RepeatContext & rContext)
687 if (m_nFormatId < RES_FMT_BEGIN) {
688 return;
691 switch ( m_nFormatId ) {
692 case RES_CHRFMT:
693 rContext.GetDoc().RstTextAttrs(rContext.GetRepeatPaM());
694 break;
695 case RES_TXTFMTCOLL:
696 rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), false, m_Ids);
697 break;
698 case RES_CONDTXTFMTCOLL:
699 rContext.GetDoc().ResetAttrs(rContext.GetRepeatPaM(), true, m_Ids);
700 break;
704 void SwUndoResetAttr::SetAttrs( o3tl::sorted_vector<sal_uInt16> && rAttrs )
706 m_Ids = std::move(rAttrs);
709 SwUndoAttr::SwUndoAttr( const SwPaM& rRange, const SfxPoolItem& rAttr,
710 const SetAttrMode nFlags )
711 : SwUndo( SwUndoId::INSATTR, &rRange.GetDoc() ), SwUndRng( rRange )
712 , m_AttrSet( rRange.GetDoc().GetAttrPool(), rAttr.Which(), rAttr.Which() )
713 , m_pHistory( new SwHistory )
714 , m_nNodeIndex( NODE_OFFSET_MAX )
715 , m_nInsertFlags( nFlags )
717 m_AttrSet.Put( rAttr );
719 // Save character style as a style name, not as a reference
720 const SfxPoolItem* pItem = m_AttrSet.GetItem(RES_TXTATR_CHARFMT);
721 if (pItem)
723 uno::Any aValue;
724 pItem->QueryValue(aValue, RES_TXTATR_CHARFMT);
725 aValue >>= m_aChrFormatName;
729 SwUndoAttr::SwUndoAttr( const SwPaM& rRange, SfxItemSet aSet,
730 const SetAttrMode nFlags )
731 : SwUndo( SwUndoId::INSATTR, &rRange.GetDoc() ), SwUndRng( rRange )
732 , m_AttrSet(std::move( aSet ))
733 , m_pHistory( new SwHistory )
734 , m_nNodeIndex( NODE_OFFSET_MAX )
735 , m_nInsertFlags( nFlags )
737 // Save character style as a style name, not as a reference
738 const SfxPoolItem* pItem = m_AttrSet.GetItem(RES_TXTATR_CHARFMT);
739 if (pItem)
741 uno::Any aValue;
742 pItem->QueryValue(aValue, RES_TXTATR_CHARFMT);
743 aValue >>= m_aChrFormatName;
747 SwUndoAttr::~SwUndoAttr()
751 void SwUndoAttr::SaveRedlineData( const SwPaM& rPam, bool bIsContent )
753 SwDoc& rDoc = rPam.GetDoc();
754 if ( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) {
755 m_pRedlineData.reset( new SwRedlineData( bIsContent
756 ? RedlineType::Insert
757 : RedlineType::Format,
758 rDoc.getIDocumentRedlineAccess().GetRedlineAuthor() ) );
761 m_pRedlineSaveData.reset( new SwRedlineSaveDatas );
762 if ( !FillSaveDataForFormat( rPam, *m_pRedlineSaveData ))
763 m_pRedlineSaveData.reset();
765 SetRedlineFlags( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() );
766 if ( bIsContent ) {
767 m_nNodeIndex = rPam.GetPoint()->GetNodeIndex();
771 void SwUndoAttr::UndoImpl(::sw::UndoRedoContext & rContext)
773 SwDoc *const pDoc = & rContext.GetDoc();
775 RemoveIdx( *pDoc );
777 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) ) {
778 SwPaM aPam(pDoc->GetNodes().GetEndOfContent());
779 if ( NODE_OFFSET_MAX != m_nNodeIndex ) {
780 aPam.DeleteMark();
781 aPam.GetPoint()->Assign( m_nNodeIndex, m_nSttContent );
782 aPam.SetMark();
783 aPam.GetPoint()->AdjustContent(+1);
784 pDoc->getIDocumentRedlineAccess().DeleteRedline(aPam, false, RedlineType::Any);
785 } else {
786 // remove all format redlines, will be recreated if needed
787 SetPaM(aPam);
788 pDoc->getIDocumentRedlineAccess().DeleteRedline(aPam, false, RedlineType::Format);
789 if (m_pRedlineSaveData)
791 SetSaveData( *pDoc, *m_pRedlineSaveData );
796 const bool bToLast = (1 == m_AttrSet.Count())
797 && (RES_TXTATR_FIELD <= m_AttrSet.GetRanges()[0].first)
798 && (m_AttrSet.GetRanges()[0].first <= RES_TXTATR_ANNOTATION);
800 // restore old values
801 m_pHistory->TmpRollback( pDoc, 0, !bToLast );
802 m_pHistory->SetTmpEnd( m_pHistory->Count() );
804 // set cursor onto Undo area
805 if (!(m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE))
806 AddUndoRedoPaM(rContext);
809 void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext)
811 // RefMarks are not repeat capable
812 if ( SfxItemState::SET != m_AttrSet.GetItemState( RES_TXTATR_REFMARK, false ) ) {
813 rContext.GetDoc().getIDocumentContentOperations().InsertItemSet( rContext.GetRepeatPaM(),
814 m_AttrSet, m_nInsertFlags );
815 } else if ( 1 < m_AttrSet.Count() ) {
816 SfxItemSet aTmpSet( m_AttrSet );
817 aTmpSet.ClearItem( RES_TXTATR_REFMARK );
818 rContext.GetDoc().getIDocumentContentOperations().InsertItemSet( rContext.GetRepeatPaM(),
819 aTmpSet, m_nInsertFlags );
823 void SwUndoAttr::redoAttribute(SwPaM& rPam, sw::UndoRedoContext & rContext)
825 SwDoc & rDoc = rContext.GetDoc();
827 // Restore pointer to char format from name
828 if (!m_aChrFormatName.isEmpty())
830 SwCharFormat* pCharFormat = rDoc.FindCharFormatByName(m_aChrFormatName);
831 if (pCharFormat)
833 SwFormatCharFormat aFormat(pCharFormat);
834 m_AttrSet.Put(aFormat);
838 if ( m_pRedlineData &&
839 IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) ) {
840 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
841 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags::Ignore );
842 rDoc.getIDocumentContentOperations().InsertItemSet( rPam, m_AttrSet, m_nInsertFlags );
844 if ( NODE_OFFSET_MAX != m_nNodeIndex ) {
845 rPam.SetMark();
846 if ( rPam.Move( fnMoveBackward ) ) {
847 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( *m_pRedlineData, rPam ),
848 true);
850 rPam.DeleteMark();
851 } else {
852 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( *m_pRedlineData, rPam ), true);
855 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
856 } else {
857 rDoc.getIDocumentContentOperations().InsertItemSet( rPam, m_AttrSet, m_nInsertFlags );
861 void SwUndoAttr::RedoImpl(sw::UndoRedoContext & rContext)
863 if (m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE)
865 SwPaM aPam(rContext.GetDoc().GetNodes().GetEndOfContent());
866 SetPaM(aPam, false);
867 redoAttribute(aPam, rContext);
869 else
871 SwPaM& rPam = AddUndoRedoPaM(rContext);
872 redoAttribute(rPam, rContext);
876 void SwUndoAttr::RemoveIdx( SwDoc& rDoc )
878 if ( SfxItemState::SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, false ))
879 return ;
881 SwNodes& rNds = rDoc.GetNodes();
882 for ( sal_uInt16 n = 0; n < m_pHistory->Count(); ++n ) {
883 sal_Int32 nContent = 0;
884 SwNodeOffset nNode(0);
885 SwHistoryHint* pHstHint = (*m_pHistory)[ n ];
886 switch ( pHstHint->Which() ) {
887 case HSTRY_RESETTXTHNT: {
888 SwHistoryResetText * pHistoryHint
889 = static_cast<SwHistoryResetText*>(pHstHint);
890 if ( RES_TXTATR_FTN == pHistoryHint->GetWhich() ) {
891 nNode = pHistoryHint->GetNode();
892 nContent = pHistoryHint->GetContent();
895 break;
897 default:
898 break;
901 if( nNode ) {
902 SwTextNode* pTextNd = rNds[ nNode ]->GetTextNode();
903 if( pTextNd ) {
904 SwTextAttr *const pTextHt =
905 pTextNd->GetTextAttrForCharAt(nContent, RES_TXTATR_FTN);
906 if( pTextHt ) {
907 // ok, so get values
908 SwTextFootnote* pFootnote = static_cast<SwTextFootnote*>(pTextHt);
909 RemoveIdxFromSection( rDoc, pFootnote->GetStartNode()->GetIndex() );
910 return ;
917 SwUndoDefaultAttr::SwUndoDefaultAttr( const SfxItemSet& rSet, const SwDoc& rDoc )
918 : SwUndo( SwUndoId::SETDEFTATTR, &rDoc )
920 const SvxTabStopItem* pItem = rSet.GetItemIfSet( RES_PARATR_TABSTOP, false );
921 if( pItem )
923 // store separately, because it may change!
924 m_pTabStop.reset(pItem->Clone());
925 if ( 1 != rSet.Count() ) { // are there more attributes?
926 m_oOldSet.emplace( rSet );
928 } else {
929 m_oOldSet.emplace( rSet );
933 SwUndoDefaultAttr::~SwUndoDefaultAttr()
937 void SwUndoDefaultAttr::UndoImpl(::sw::UndoRedoContext & rContext)
939 SwDoc & rDoc = rContext.GetDoc();
940 if (m_oOldSet)
942 SwUndoFormatAttrHelper aTmp(
943 *rDoc.GetDfltTextFormatColl() );
944 rDoc.SetDefault( *m_oOldSet );
945 m_oOldSet.reset();
946 if ( aTmp.GetUndo() ) {
947 // transfer ownership of helper object's old set
948 if (aTmp.GetUndo()->m_oOldSet)
949 m_oOldSet.emplace(std::move(*aTmp.GetUndo()->m_oOldSet));
952 if (m_pTabStop)
954 std::unique_ptr<SvxTabStopItem> pOld(rDoc.GetDefault(RES_PARATR_TABSTOP).Clone());
955 rDoc.SetDefault( *m_pTabStop );
956 m_pTabStop = std::move( pOld );
960 void SwUndoDefaultAttr::RedoImpl(::sw::UndoRedoContext & rContext)
962 UndoImpl(rContext);
965 SwUndoMoveLeftMargin::SwUndoMoveLeftMargin(
966 const SwPaM& rPam, bool bFlag, bool bMod )
967 : SwUndo( bFlag ? SwUndoId::INC_LEFTMARGIN : SwUndoId::DEC_LEFTMARGIN, &rPam.GetDoc() )
968 , SwUndRng( rPam )
969 , m_pHistory( new SwHistory )
970 , m_bModulus( bMod )
974 SwUndoMoveLeftMargin::~SwUndoMoveLeftMargin()
978 void SwUndoMoveLeftMargin::UndoImpl(::sw::UndoRedoContext & rContext)
980 SwDoc & rDoc = rContext.GetDoc();
982 // restore old values
983 m_pHistory->TmpRollback( & rDoc, 0 );
984 m_pHistory->SetTmpEnd( m_pHistory->Count() );
986 AddUndoRedoPaM(rContext);
989 void SwUndoMoveLeftMargin::RedoImpl(::sw::UndoRedoContext & rContext)
991 SwDoc & rDoc = rContext.GetDoc();
992 SwPaM & rPam = AddUndoRedoPaM(rContext);
994 rDoc.MoveLeftMargin( rPam,
995 GetId() == SwUndoId::INC_LEFTMARGIN, m_bModulus,
996 rDoc.getIDocumentLayoutAccess().GetCurrentLayout() );
999 void SwUndoMoveLeftMargin::RepeatImpl(::sw::RepeatContext & rContext)
1001 SwDoc & rDoc = rContext.GetDoc();
1002 rDoc.MoveLeftMargin(rContext.GetRepeatPaM(), GetId() == SwUndoId::INC_LEFTMARGIN,
1003 m_bModulus, rDoc.getIDocumentLayoutAccess().GetCurrentLayout());
1006 SwUndoChangeFootNote::SwUndoChangeFootNote(
1007 const SwPaM& rRange, OUString aText,
1008 bool const bIsEndNote)
1009 : SwUndo( SwUndoId::CHGFTN, &rRange.GetDoc() ), SwUndRng( rRange )
1010 , m_pHistory( new SwHistory() )
1011 , m_Text(std::move( aText ))
1012 , m_bEndNote( bIsEndNote )
1016 SwUndoChangeFootNote::~SwUndoChangeFootNote()
1020 void SwUndoChangeFootNote::UndoImpl(::sw::UndoRedoContext & rContext)
1022 SwDoc & rDoc = rContext.GetDoc();
1024 m_pHistory->TmpRollback( &rDoc, 0 );
1025 m_pHistory->SetTmpEnd( m_pHistory->Count() );
1027 rDoc.GetFootnoteIdxs().UpdateAllFootnote();
1029 AddUndoRedoPaM(rContext);
1032 void SwUndoChangeFootNote::RedoImpl(::sw::UndoRedoContext & rContext)
1034 SwDoc & rDoc( rContext.GetDoc() );
1035 SwPaM & rPaM = AddUndoRedoPaM(rContext);
1036 rDoc.SetCurFootnote(rPaM, m_Text, m_bEndNote);
1037 SetPaM(rPaM);
1040 void SwUndoChangeFootNote::RepeatImpl(::sw::RepeatContext & rContext)
1042 SwDoc & rDoc = rContext.GetDoc();
1043 rDoc.SetCurFootnote(rContext.GetRepeatPaM(), m_Text, m_bEndNote);
1046 SwUndoFootNoteInfo::SwUndoFootNoteInfo( const SwFootnoteInfo &rInfo, const SwDoc& rDoc )
1047 : SwUndo( SwUndoId::FTNINFO, &rDoc )
1048 , m_pFootNoteInfo( new SwFootnoteInfo( rInfo ) )
1052 SwUndoFootNoteInfo::~SwUndoFootNoteInfo()
1056 void SwUndoFootNoteInfo::UndoImpl(::sw::UndoRedoContext & rContext)
1058 SwDoc & rDoc = rContext.GetDoc();
1059 SwFootnoteInfo *pInf = new SwFootnoteInfo( rDoc.GetFootnoteInfo() );
1060 rDoc.SetFootnoteInfo( *m_pFootNoteInfo );
1061 m_pFootNoteInfo.reset( pInf );
1064 void SwUndoFootNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext)
1066 SwDoc & rDoc = rContext.GetDoc();
1067 SwFootnoteInfo *pInf = new SwFootnoteInfo( rDoc.GetFootnoteInfo() );
1068 rDoc.SetFootnoteInfo( *m_pFootNoteInfo );
1069 m_pFootNoteInfo.reset( pInf );
1072 SwUndoEndNoteInfo::SwUndoEndNoteInfo( const SwEndNoteInfo &rInfo, const SwDoc& rDoc )
1073 : SwUndo( SwUndoId::FTNINFO, &rDoc )
1074 , m_pEndNoteInfo( new SwEndNoteInfo( rInfo ) )
1078 SwUndoEndNoteInfo::~SwUndoEndNoteInfo()
1082 void SwUndoEndNoteInfo::UndoImpl(::sw::UndoRedoContext & rContext)
1084 SwDoc & rDoc = rContext.GetDoc();
1085 SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() );
1086 rDoc.SetEndNoteInfo( *m_pEndNoteInfo );
1087 m_pEndNoteInfo.reset( pInf );
1090 void SwUndoEndNoteInfo::RedoImpl(::sw::UndoRedoContext & rContext)
1092 SwDoc & rDoc = rContext.GetDoc();
1093 SwEndNoteInfo *pInf = new SwEndNoteInfo( rDoc.GetEndNoteInfo() );
1094 rDoc.SetEndNoteInfo( *m_pEndNoteInfo );
1095 m_pEndNoteInfo.reset( pInf );
1098 SwUndoDontExpandFormat::SwUndoDontExpandFormat( const SwPosition& rPos )
1099 : SwUndo( SwUndoId::DONTEXPAND, &rPos.GetDoc() )
1100 , m_nNodeIndex( rPos.GetNodeIndex() )
1101 , m_nContentIndex( rPos.GetContentIndex() )
1105 void SwUndoDontExpandFormat::UndoImpl(::sw::UndoRedoContext & rContext)
1107 SwCursor *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
1108 SwDoc *const pDoc = & rContext.GetDoc();
1110 SwPosition& rPos = *pPam->GetPoint();
1111 rPos.Assign( m_nNodeIndex, m_nContentIndex );
1112 pDoc->DontExpandFormat( rPos, false );
1115 void SwUndoDontExpandFormat::RedoImpl(::sw::UndoRedoContext & rContext)
1117 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
1118 SwDoc *const pDoc = & rContext.GetDoc();
1120 SwPosition& rPos = *pPam->GetPoint();
1121 rPos.Assign( m_nNodeIndex, m_nContentIndex );
1122 pDoc->DontExpandFormat( rPos );
1125 void SwUndoDontExpandFormat::RepeatImpl(::sw::RepeatContext & rContext)
1127 SwPaM & rPam = rContext.GetRepeatPaM();
1128 SwDoc & rDoc = rContext.GetDoc();
1129 rDoc.DontExpandFormat( *rPam.GetPoint() );
1132 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */