android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / undo / untbl.cxx
blob3092df0c2fd32a1aba3042cdbb227a101d9c7a39
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 <UndoTable.hxx>
23 #include <UndoRedline.hxx>
24 #include <UndoDelete.hxx>
25 #include <UndoSplitMove.hxx>
26 #include <UndoCore.hxx>
27 #include <fesh.hxx>
28 #include <fmtpdsc.hxx>
29 #include <hintids.hxx>
30 #include <hints.hxx>
31 #include <doc.hxx>
32 #include <docredln.hxx>
33 #include <IDocumentUndoRedo.hxx>
34 #include <IDocumentChartDataProviderAccess.hxx>
35 #include <IDocumentRedlineAccess.hxx>
36 #include <IDocumentFieldsAccess.hxx>
37 #include <IDocumentStylePoolAccess.hxx>
38 #include <IDocumentLayoutAccess.hxx>
39 #include <rootfrm.hxx>
40 #include <editsh.hxx>
41 #include <docary.hxx>
42 #include <ndtxt.hxx>
43 #include <swtable.hxx>
44 #include <pam.hxx>
45 #include <tblsel.hxx>
46 #include <swundo.hxx>
47 #include <rolbck.hxx>
48 #include <ddefld.hxx>
49 #include <tabfrm.hxx>
50 #include <tblafmt.hxx>
51 #include <poolfmt.hxx>
52 #include <mvsave.hxx>
53 #include <cellatr.hxx>
54 #include <swtblfmt.hxx>
55 #include <swddetbl.hxx>
56 #include <redline.hxx>
57 #include <node2lay.hxx>
58 #include <tblrwcl.hxx>
59 #include <fmtanchr.hxx>
60 #include <strings.hrc>
61 #include <unochart.hxx>
62 #include <calbck.hxx>
63 #include <frameformats.hxx>
64 #include <editeng/formatbreakitem.hxx>
65 #include <osl/diagnose.h>
66 #include <docsh.hxx>
68 #include <memory>
69 #include <utility>
70 #include <vector>
72 #ifdef DBG_UTIL
73 #define CHECK_TABLE(t) (t).CheckConsistency();
74 #else
75 #define CHECK_TABLE(t)
76 #endif
78 #ifdef DBG_UTIL
79 #define DEBUG_REDLINE( pDoc ) sw_DebugRedline( pDoc );
80 #else
81 #define DEBUG_REDLINE( pDoc )
82 #endif
84 typedef std::vector<std::shared_ptr<SfxItemSet> > SfxItemSets;
86 struct UndoTableCpyTable_Entry
88 SwNodeOffset nBoxIdx, nOffset;
89 std::unique_ptr<SfxItemSet> pBoxNumAttr;
90 std::unique_ptr<SwUndo> pUndo;
92 // Was the last paragraph of the new and the first paragraph of the old content joined?
93 bool bJoin; // For redlining only
95 explicit UndoTableCpyTable_Entry( const SwTableBox& rBox );
97 void dumpAsXml(xmlTextWriterPtr pWriter) const;
100 namespace {
102 class SaveBox;
103 class SaveLine;
105 void KillEmptyFrameFormat(SwFrameFormat& rFormat)
107 if(!rFormat.HasWriterListeners())
108 delete &rFormat;
113 class SaveTable
115 friend SaveBox;
116 friend SaveLine;
117 SfxItemSet m_aTableSet;
118 std::unique_ptr<SaveLine> m_pLine;
119 const SwTable* m_pSwTable;
120 SfxItemSets m_aSets;
121 SwFrameFormatsV m_aFrameFormats;
122 sal_uInt16 m_nLineCount;
123 bool m_bModifyBox : 1;
124 bool m_bSaveFormula : 1;
125 bool m_bNewModel : 1;
127 SaveTable(const SaveTable&) = delete;
128 SaveTable& operator=(const SaveTable&) = delete;
129 SwFrameFormat& CreateNewFormat(SwFrameFormat& rFormat, sal_uInt16 nFormatPos);
131 public:
132 SaveTable( const SwTable& rTable, sal_uInt16 nLnCnt = USHRT_MAX,
133 bool bSaveFormula = true );
135 sal_uInt16 AddFormat( SwFrameFormat* pFormat, bool bIsLine );
136 void NewFrameFormatForLine(const SwTableLine&, sal_uInt16 nFormatPos, SwFrameFormat* pOldFormat);
137 void NewFrameFormatForBox(const SwTableBox&, sal_uInt16 nFormatPos, SwFrameFormat* pOldFormat);
139 void RestoreAttr( SwTable& rTable, bool bModifyBox = false );
140 void SaveContentAttrs( SwDoc* pDoc );
141 void CreateNew( SwTable& rTable, bool bCreateFrames = true,
142 bool bRestoreChart = true );
143 bool IsNewModel() const { return m_bNewModel; }
146 namespace {
148 class SaveLine
150 friend SaveTable;
151 friend class SaveBox;
153 SaveLine* m_pNext;
154 SaveBox* m_pBox;
155 sal_uInt16 m_nItemSet;
157 SaveLine(const SaveLine&) = delete;
158 SaveLine& operator=(const SaveLine&) = delete;
160 public:
161 SaveLine( SaveLine* pPrev, const SwTableLine& rLine, SaveTable& rSTable );
162 ~SaveLine();
164 void RestoreAttr( SwTableLine& rLine, SaveTable& rSTable );
165 void SaveContentAttrs( SwDoc* pDoc );
167 void CreateNew( SwTable& rTable, SwTableBox& rParent, SaveTable& rSTable );
170 class SaveBox
172 friend class SaveLine;
174 SaveBox* m_pNext;
175 SwNodeOffset m_nStartNode;
176 sal_Int32 m_nRowSpan;
177 sal_uInt16 m_nItemSet;
178 union
180 SfxItemSets* pContentAttrs;
181 SaveLine* pLine;
182 } m_Ptrs;
184 public:
185 SaveBox( SaveBox* pPrev, const SwTableBox& rBox, SaveTable& rSTable );
186 ~SaveBox();
188 void RestoreAttr( SwTableBox& rBox, SaveTable& rSTable );
189 void SaveContentAttrs( SwDoc* pDoc );
191 void CreateNew( SwTable& rTable, SwTableLine& rParent, SaveTable& rSTable );
196 #if OSL_DEBUG_LEVEL > 0
197 static void CheckTable( const SwTable& );
198 #define CHECKTABLE(t) CheckTable( t );
199 #else
200 #define CHECKTABLE(t)
201 #endif
203 /* #130880: Crash in undo of table to text when the table has (freshly) merged cells
204 The order of cell content nodes in the nodes array is not given by the recursive table structure.
205 The algorithm must not rely on this even it holds for a fresh loaded table in odt file format.
206 So we need to remember not only the start node position but the end node position as well.
209 struct SwTableToTextSave
211 SwNodeOffset m_nSttNd;
212 SwNodeOffset m_nEndNd;
213 sal_Int32 m_nContent;
214 std::unique_ptr<SwHistory> m_pHstry;
215 // metadata references for first and last paragraph in cell
216 std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart;
217 std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd;
219 SwTableToTextSave( SwDoc& rDoc, SwNodeOffset nNd, SwNodeOffset nEndIdx, sal_Int32 nContent );
221 private:
222 SwTableToTextSave(const SwTableToTextSave&) = delete;
223 SwTableToTextSave& operator=(const SwTableToTextSave&) = delete;
227 WhichRangesContainer const aSave_BoxContentSet(svl::Items<
228 RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT,
229 RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
230 RES_CHRATR_POSTURE, RES_CHRATR_POSTURE,
231 RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT,
232 RES_PARATR_ADJUST, RES_PARATR_ADJUST>);
234 SwUndoInsTable::SwUndoInsTable( const SwPosition& rPos, sal_uInt16 nCl, sal_uInt16 nRw,
235 sal_uInt16 nAdj, const SwInsertTableOptions& rInsTableOpts,
236 const SwTableAutoFormat* pTAFormat,
237 const std::vector<sal_uInt16> *pColArr,
238 const OUString & rName)
239 : SwUndo( SwUndoId::INSTABLE, &rPos.GetDoc() ),
240 m_aInsTableOptions( rInsTableOpts ),
241 m_nStartNode( rPos.GetNodeIndex() ), m_nRows( nRw ), m_nColumns( nCl ), m_nAdjust( nAdj )
243 if( pColArr )
245 m_oColumnWidth.emplace( *pColArr );
247 if( pTAFormat )
248 m_pAutoFormat.reset( new SwTableAutoFormat( *pTAFormat ) );
250 // consider redline
251 SwDoc& rDoc = rPos.GetNode().GetDoc();
252 if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() )
254 m_pRedlineData.reset( new SwRedlineData( RedlineType::Insert, rDoc.getIDocumentRedlineAccess().GetRedlineAuthor() ) );
255 SetRedlineFlags( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() );
258 m_sTableName = rName;
261 SwUndoInsTable::~SwUndoInsTable()
263 m_pDDEFieldType.reset();
264 m_oColumnWidth.reset();
265 m_pRedlineData.reset();
266 m_pAutoFormat.reset();
269 void SwUndoInsTable::UndoImpl(::sw::UndoRedoContext & rContext)
271 SwDoc & rDoc = rContext.GetDoc();
272 SwNodeIndex aIdx( rDoc.GetNodes(), m_nStartNode );
274 SwTableNode* pTableNd = aIdx.GetNode().GetTableNode();
275 OSL_ENSURE( pTableNd, "no TableNode" );
276 pTableNd->DelFrames();
278 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ))
279 rDoc.getIDocumentRedlineAccess().DeleteRedline( *pTableNd, true, RedlineType::Any );
280 RemoveIdxFromSection( rDoc, m_nStartNode );
282 // move hard page breaks into next node
283 SwContentNode* pNextNd = rDoc.GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]->GetContentNode();
284 if( pNextNd )
286 SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
288 if( const SwFormatPageDesc* pItem = pTableFormat->GetItemIfSet( RES_PAGEDESC,
289 false ) )
290 pNextNd->SetAttr( *pItem );
292 if( const SvxFormatBreakItem* pItem = pTableFormat->GetItemIfSet( RES_BREAK,
293 false ) )
294 pNextNd->SetAttr( *pItem );
296 ::sw::NotifyTableCollapsedParagraph(pNextNd, nullptr);
299 m_sTableName = pTableNd->GetTable().GetFrameFormat()->GetName();
300 if( auto pDDETable = dynamic_cast<const SwDDETable *>(&pTableNd->GetTable()) )
301 m_pDDEFieldType.reset(static_cast<SwDDEFieldType*>(pDDETable->GetDDEFieldType()->Copy().release()));
303 rDoc.GetNodes().Delete( aIdx, pTableNd->EndOfSectionIndex() -
304 aIdx.GetIndex() + 1 );
306 SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() );
307 rPam.DeleteMark();
308 rPam.GetPoint()->Assign(aIdx);
311 void SwUndoInsTable::RedoImpl(::sw::UndoRedoContext & rContext)
313 SwDoc & rDoc = rContext.GetDoc();
315 SwEditShell *const pEditShell(rDoc.GetEditShell());
316 OSL_ENSURE(pEditShell, "SwUndoInsTable::RedoImpl needs a SwEditShell!");
317 if (!pEditShell)
319 throw uno::RuntimeException();
322 SwPosition const aPos(rDoc.GetNodes(), m_nStartNode);
323 const SwTable* pTable = rDoc.InsertTable( m_aInsTableOptions, aPos, m_nRows, m_nColumns,
324 m_nAdjust,
325 m_pAutoFormat.get(),
326 m_oColumnWidth ? &*m_oColumnWidth : nullptr );
327 pEditShell->MoveTable( GotoPrevTable, fnTableStart );
328 static_cast<SwFrameFormat*>(pTable->GetFrameFormat())->SetFormatName( m_sTableName );
329 SwTableNode* pTableNode = rDoc.GetNodes()[m_nStartNode]->GetTableNode();
331 if( m_pDDEFieldType )
333 SwDDEFieldType* pNewType = static_cast<SwDDEFieldType*>(rDoc.getIDocumentFieldsAccess().InsertFieldType(
334 *m_pDDEFieldType));
335 std::unique_ptr<SwDDETable> pDDETable(new SwDDETable( pTableNode->GetTable(), pNewType ));
336 pTableNode->SetNewTable( std::move(pDDETable) );
337 m_pDDEFieldType.reset();
340 if( !((m_pRedlineData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() )) ||
341 ( !( RedlineFlags::Ignore & GetRedlineFlags() ) &&
342 !rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() )))
343 return;
345 SwPaM aPam( *pTableNode->EndOfSectionNode(), *pTableNode, SwNodeOffset(1) );
347 if( m_pRedlineData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) )
349 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
350 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld & ~RedlineFlags::Ignore);
352 rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( *m_pRedlineData, aPam ), true);
353 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
355 else
356 rDoc.getIDocumentRedlineAccess().SplitRedline( aPam );
359 void SwUndoInsTable::RepeatImpl(::sw::RepeatContext & rContext)
361 rContext.GetDoc().InsertTable(
362 m_aInsTableOptions, *rContext.GetRepeatPaM().GetPoint(),
363 m_nRows, m_nColumns, m_nAdjust, m_pAutoFormat.get(),
364 m_oColumnWidth ? &*m_oColumnWidth : nullptr );
367 SwRewriter SwUndoInsTable::GetRewriter() const
369 SwRewriter aRewriter;
371 aRewriter.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
372 aRewriter.AddRule(UndoArg2, m_sTableName);
373 aRewriter.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
375 return aRewriter;
378 SwTableToTextSave::SwTableToTextSave( SwDoc& rDoc, SwNodeOffset nNd, SwNodeOffset nEndIdx, sal_Int32 nCnt )
379 : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nContent( nCnt )
381 // keep attributes of the joined node
382 SwTextNode* pNd = rDoc.GetNodes()[ nNd ]->GetTextNode();
383 if( pNd )
385 m_pHstry.reset( new SwHistory );
387 m_pHstry->Add( pNd->GetTextColl(), nNd, SwNodeType::Text );
388 if ( pNd->GetpSwpHints() )
390 m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0,
391 pNd->GetText().getLength(), false );
393 if( pNd->HasSwAttrSet() )
394 m_pHstry->CopyFormatAttr( *pNd->GetpSwAttrSet(), nNd );
396 if( !m_pHstry->Count() )
398 m_pHstry.reset();
401 // METADATA: store
402 m_pMetadataUndoStart = pNd->CreateUndo();
405 // we also need to store the metadata reference of the _last_ paragraph
406 // we subtract 1 to account for the removed cell start/end node pair
407 // (after SectionUp, the end of the range points to the node after the cell)
408 if ( nEndIdx - 1 > nNd )
410 SwTextNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTextNode() );
411 if( pLastNode )
413 // METADATA: store
414 m_pMetadataUndoEnd = pLastNode->CreateUndo();
419 SwUndoTableToText::SwUndoTableToText( const SwTable& rTable, sal_Unicode cCh )
420 : SwUndo( SwUndoId::TABLETOTEXT, rTable.GetFrameFormat()->GetDoc() ),
421 m_sTableName( rTable.GetFrameFormat()->GetName() ),
422 m_nStartNode( 0 ), m_nEndNode( 0 ),
423 m_cSeparator( cCh ), m_nHeadlineRepeat( rTable.GetRowsToRepeat() )
425 m_pTableSave.reset( new SaveTable( rTable ) );
426 m_vBoxSaves.reserve(rTable.GetTabSortBoxes().size());
428 if( auto pDDETable = dynamic_cast<const SwDDETable *>(&rTable) )
429 m_pDDEFieldType.reset(static_cast<SwDDEFieldType*>(pDDETable->GetDDEFieldType()->Copy().release()));
431 m_bCheckNumFormat = rTable.GetFrameFormat()->GetDoc()->IsInsTableFormatNum();
433 m_pHistory.reset(new SwHistory);
434 const SwTableNode* pTableNd = rTable.GetTableNode();
435 SwNodeOffset nTableStt = pTableNd->GetIndex(), nTableEnd = pTableNd->EndOfSectionIndex();
437 for(sw::SpzFrameFormat* pFormat: *pTableNd->GetDoc().GetSpzFrameFormats())
439 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
440 SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
441 if (pAnchorNode &&
442 ((RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
443 (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId())) &&
444 nTableStt <= pAnchorNode->GetIndex() &&
445 pAnchorNode->GetIndex() < nTableEnd )
447 m_pHistory->AddChangeFlyAnchor(*pFormat);
451 if( !m_pHistory->Count() )
453 m_pHistory.reset();
457 SwUndoTableToText::~SwUndoTableToText()
459 m_pDDEFieldType.reset();
460 m_pTableSave.reset();
461 m_vBoxSaves.clear();
462 m_pHistory.reset();
465 void SwUndoTableToText::UndoImpl(::sw::UndoRedoContext & rContext)
467 SwDoc & rDoc = rContext.GetDoc();
468 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
470 SwNodeIndex aFrameIdx( rDoc.GetNodes(), m_nStartNode );
471 SwNodeIndex aEndIdx( rDoc.GetNodes(), m_nEndNode );
473 pPam->GetPoint()->Assign( aFrameIdx );
474 pPam->SetMark();
475 pPam->GetPoint()->Assign( aEndIdx );
476 rDoc.DelNumRules( *pPam );
477 pPam->DeleteMark();
479 // now collect all Uppers
480 SwNode2LayoutSaveUpperFrames aNode2Layout(aFrameIdx.GetNode());
482 // create TableNode structure
483 SwTableNode* pTableNd = rDoc.GetNodes().UndoTableToText( m_nStartNode, m_nEndNode, m_vBoxSaves );
484 pTableNd->GetTable().SetTableModel( m_pTableSave->IsNewModel() );
485 SwTableFormat* pTableFormat = rDoc.MakeTableFrameFormat( m_sTableName, rDoc.GetDfltFrameFormat() );
486 pTableNd->GetTable().RegisterToFormat( *pTableFormat );
487 pTableNd->GetTable().SetRowsToRepeat( m_nHeadlineRepeat );
489 // create old table structure
490 m_pTableSave->CreateNew( pTableNd->GetTable() );
492 if( m_pDDEFieldType )
494 SwDDEFieldType* pNewType = static_cast<SwDDEFieldType*>(rDoc.getIDocumentFieldsAccess().InsertFieldType(
495 *m_pDDEFieldType));
496 std::unique_ptr<SwDDETable> pDDETable( new SwDDETable( pTableNd->GetTable(), pNewType ) );
497 pTableNd->SetNewTable( std::move(pDDETable), false );
498 m_pDDEFieldType.reset();
501 if( m_bCheckNumFormat )
503 SwTableSortBoxes& rBxs = pTableNd->GetTable().GetTabSortBoxes();
504 for (size_t nBoxes = rBxs.size(); nBoxes; )
506 rDoc.ChkBoxNumFormat( *rBxs[ --nBoxes ], false );
510 if( m_pHistory )
512 sal_uInt16 nTmpEnd = m_pHistory->GetTmpEnd();
513 m_pHistory->TmpRollback( &rDoc, 0 );
514 m_pHistory->SetTmpEnd( nTmpEnd );
517 aNode2Layout.RestoreUpperFrames( rDoc.GetNodes(),
518 pTableNd->GetIndex(), pTableNd->GetIndex()+1 );
520 // Is a table selection requested?
521 pPam->DeleteMark();
522 pPam->GetPoint()->Assign( *pTableNd->EndOfSectionNode() );
523 pPam->SetMark();
524 pPam->GetPoint()->Assign( *pPam->GetPointNode().StartOfSectionNode() );
525 pPam->Move( fnMoveForward, GoInContent );
526 pPam->Exchange();
527 pPam->Move( fnMoveBackward, GoInContent );
529 ClearFEShellTabCols(rDoc, nullptr);
532 // located in untbl.cxx and only an Undo object is allowed to call it
533 SwTableNode* SwNodes::UndoTableToText( SwNodeOffset nSttNd, SwNodeOffset nEndNd,
534 const SwTableToTextSaves& rSavedData )
536 SwNodeIndex aSttIdx( *this, nSttNd );
537 SwNodeIndex aEndIdx( *this, nEndNd+1 );
539 SwTableNode * pTableNd = new SwTableNode( aSttIdx.GetNode() );
540 SwEndNode* pEndNd = new SwEndNode( aEndIdx.GetNode(), *pTableNd );
542 aEndIdx = *pEndNd;
544 /* Set pTableNd as start of section for all nodes in [nSttNd, nEndNd].
545 Delete all Frames attached to the nodes in that range. */
546 SwNode* pNd;
548 SwNodeOffset n, nTmpEnd = aEndIdx.GetIndex();
549 for( n = pTableNd->GetIndex() + 1; n < nTmpEnd; ++n )
551 pNd = (*this)[n];
552 if (pNd->IsContentNode())
554 static_cast<SwContentNode*>(pNd)->DelFrames(nullptr);
556 // tdf#147938 reset merge flag in nodes
557 pNd->SetRedlineMergeFlag(SwNode::Merge::None);
558 pNd->m_pStartOfSection = pTableNd;
562 // than create table structure partially. First a single line that contains
563 // all boxes. The correct structure is then taken from SaveStruct.
564 SwTableBoxFormat* pBoxFormat = GetDoc().MakeTableBoxFormat();
565 SwTableLineFormat* pLineFormat = GetDoc().MakeTableLineFormat();
566 SwTableLine* pLine = new SwTableLine( pLineFormat, rSavedData.size(), nullptr );
567 pTableNd->GetTable().GetTabLines().insert( pTableNd->GetTable().GetTabLines().begin(), pLine );
569 for( size_t n = rSavedData.size(); n; )
571 const SwTableToTextSave *const pSave = rSavedData[ --n ].get();
572 // if the start node was merged with last from prev. cell,
573 // subtract 1 from index to get the merged paragraph, and split that
574 aSttIdx = pSave->m_nSttNd - ( ( SAL_MAX_INT32 != pSave->m_nContent ) ? 1 : 0);
575 SwTextNode* pTextNd = aSttIdx.GetNode().GetTextNode();
577 if( SAL_MAX_INT32 != pSave->m_nContent )
579 // split at ContentPosition, delete previous char (= separator)
580 OSL_ENSURE( pTextNd, "Where is my TextNode?" );
581 SwContentIndex aCntPos( pTextNd, pSave->m_nContent - 1 );
583 const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
584 pContentStore->Save(GetDoc(), aSttIdx.GetIndex(), aCntPos.GetIndex());
586 pTextNd->EraseText( aCntPos, 1 );
588 std::function<void (SwTextNode *, sw::mark::RestoreMode, bool)> restoreFunc(
589 [&](SwTextNode *const pNewNode, sw::mark::RestoreMode const eMode, bool)
591 if (!pContentStore->Empty())
593 pContentStore->Restore(*pNewNode, pSave->m_nContent, pSave->m_nContent + 1, eMode);
596 pTextNd->SplitContentNode(
597 SwPosition(aSttIdx, aCntPos), &restoreFunc);
600 if( pTextNd )
602 // METADATA: restore
603 pTextNd->GetTextNode()->RestoreMetadata(pSave->m_pMetadataUndoStart);
604 if( pTextNd->HasSwAttrSet() )
605 pTextNd->ResetAllAttr();
607 if( pTextNd->GetpSwpHints() )
608 pTextNd->ClearSwpHintsArr( false );
611 if( pSave->m_pHstry )
613 sal_uInt16 nTmpEnd = pSave->m_pHstry->GetTmpEnd();
614 pSave->m_pHstry->TmpRollback( &GetDoc(), 0 );
615 pSave->m_pHstry->SetTmpEnd( nTmpEnd );
618 // METADATA: restore
619 // end points to node after cell
620 if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd )
622 SwTextNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTextNode();
623 if (pLastNode)
625 pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd);
629 aEndIdx = pSave->m_nEndNd;
630 SwStartNode* pSttNd = new SwStartNode( aSttIdx.GetNode(), SwNodeType::Start,
631 SwTableBoxStartNode );
632 pSttNd->m_pStartOfSection = pTableNd;
633 new SwEndNode( aEndIdx.GetNode(), *pSttNd );
635 for( SwNodeOffset i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i )
637 pNd = (*this)[ i ];
638 pNd->m_pStartOfSection = pSttNd;
639 if( pNd->IsStartNode() )
640 i = pNd->EndOfSectionIndex();
643 SwTableBox* pBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
644 pLine->GetTabBoxes().insert( pLine->GetTabBoxes().begin(), pBox );
646 return pTableNd;
649 void SwUndoTableToText::RedoImpl(::sw::UndoRedoContext & rContext)
651 SwDoc & rDoc = rContext.GetDoc();
652 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
654 pPam->GetPoint()->Assign( m_nStartNode );
655 SwNodeIndex aSaveIdx( pPam->GetPoint()->GetNode(), -1 );
657 pPam->SetMark(); // log off all indices
658 pPam->DeleteMark();
660 SwTableNode* pTableNd = pPam->GetPointNode().GetTableNode();
661 OSL_ENSURE( pTableNd, "Could not find any TableNode" );
663 if( auto pDDETable = dynamic_cast<const SwDDETable *>(&pTableNd->GetTable()) )
664 m_pDDEFieldType.reset(static_cast<SwDDEFieldType*>(pDDETable->GetDDEFieldType()->Copy().release()));
666 rDoc.TableToText( pTableNd, m_cSeparator );
668 ++aSaveIdx;
669 SwContentNode* pCNd = aSaveIdx.GetNode().GetContentNode();
670 if( !pCNd && nullptr == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) &&
671 nullptr == ( pCNd = SwNodes::GoPrevious( &aSaveIdx )) )
673 OSL_FAIL( "Where is the TextNode now?" );
676 pPam->GetPoint()->Assign( aSaveIdx );
678 pPam->SetMark(); // log off all indices
679 pPam->DeleteMark();
682 void SwUndoTableToText::RepeatImpl(::sw::RepeatContext & rContext)
684 SwPaM *const pPam = & rContext.GetRepeatPaM();
685 SwTableNode *const pTableNd = pPam->GetPointNode().FindTableNode();
686 if( pTableNd )
688 // move cursor out of table
689 pPam->GetPoint()->Assign( *pTableNd->EndOfSectionNode() );
690 pPam->Move( fnMoveForward, GoInContent );
691 pPam->SetMark();
692 pPam->DeleteMark();
694 rContext.GetDoc().TableToText( pTableNd, m_cSeparator );
698 void SwUndoTableToText::SetRange( const SwNodeRange& rRg )
700 m_nStartNode = rRg.aStart.GetIndex();
701 m_nEndNode = rRg.aEnd.GetIndex();
704 void SwUndoTableToText::AddBoxPos( SwDoc& rDoc, SwNodeOffset nNdIdx, SwNodeOffset nEndIdx, sal_Int32 nContentIdx )
706 m_vBoxSaves.push_back(std::make_unique<SwTableToTextSave>(rDoc, nNdIdx, nEndIdx, nContentIdx));
709 SwUndoTextToTable::SwUndoTextToTable( const SwPaM& rRg,
710 const SwInsertTableOptions& rInsTableOpts,
711 sal_Unicode cCh, sal_uInt16 nAdj,
712 const SwTableAutoFormat* pAFormat )
713 : SwUndo( SwUndoId::TEXTTOTABLE, &rRg.GetDoc() ), SwUndRng( rRg ), m_aInsertTableOpts( rInsTableOpts ),
714 m_pHistory( nullptr ), m_cSeparator( cCh ), m_nAdjust( nAdj )
716 if( pAFormat )
717 m_pAutoFormat.reset( new SwTableAutoFormat( *pAFormat ) );
719 const SwPosition* pEnd = rRg.End();
720 SwNodes& rNds = rRg.GetDoc().GetNodes();
721 m_bSplitEnd = pEnd->GetContentIndex() && ( pEnd->GetContentIndex()
722 != pEnd->GetNode().GetContentNode()->Len() ||
723 pEnd->GetNodeIndex() >= rNds.GetEndOfContent().GetIndex()-1 );
726 SwUndoTextToTable::~SwUndoTextToTable()
728 m_pAutoFormat.reset();
731 void SwUndoTextToTable::UndoImpl(::sw::UndoRedoContext & rContext)
733 SwDoc & rDoc = rContext.GetDoc();
735 SwNodeOffset nTableNd = m_nSttNode;
736 if( m_nSttContent )
737 ++nTableNd; // Node was split previously
738 SwNodeIndex aIdx( rDoc.GetNodes(), nTableNd );
739 SwTableNode *const pTNd = aIdx.GetNode().GetTableNode();
740 OSL_ENSURE( pTNd, "Could not find a TableNode" );
742 RemoveIdxFromSection( rDoc, nTableNd );
744 m_sTableName = pTNd->GetTable().GetFrameFormat()->GetName();
746 if( m_pHistory )
748 m_pHistory->TmpRollback( &rDoc, 0 );
749 m_pHistory->SetTmpEnd( m_pHistory->Count() );
752 if( !mvDelBoxes.empty() )
754 pTNd->DelFrames();
755 SwTable& rTable = pTNd->GetTable();
756 for( size_t n = mvDelBoxes.size(); n; )
758 SwTableBox* pBox = rTable.GetTableBox( mvDelBoxes[ --n ] );
759 if( pBox )
760 ::DeleteBox_( rTable, pBox, nullptr, false, false );
761 else {
762 OSL_ENSURE( false, "Where is my box?" );
767 rDoc.TableToText( pTNd, 0x0b == m_cSeparator ? 0x09 : m_cSeparator );
769 // join again at start?
770 if( m_nSttContent )
772 SwPaM aPam(rDoc.GetNodes(), nTableNd);
773 if (aPam.Move(fnMoveBackward, GoInContent))
775 SwNode & rIdx = aPam.GetPoint()->GetNode();
777 // than move, relatively, the Cursor/etc. again
778 RemoveIdxRel( rIdx.GetIndex()+1, *aPam.GetPoint() );
780 rIdx.GetContentNode()->JoinNext();
784 // join again at end?
785 if( m_bSplitEnd )
787 SwPosition aEndPos( rDoc.GetNodes(), m_nEndNode );
788 SwTextNode* pTextNd = aEndPos.GetNode().GetTextNode();
789 if( pTextNd && pTextNd->CanJoinNext() )
791 aEndPos.nContent.Assign( nullptr, 0 );
793 // than move, relatively, the Cursor/etc. again
794 aEndPos.SetContent(pTextNd->GetText().getLength());
795 RemoveIdxRel( m_nEndNode + 1, aEndPos );
797 pTextNd->JoinNext();
801 AddUndoRedoPaM(rContext);
804 void SwUndoTextToTable::RedoImpl(::sw::UndoRedoContext & rContext)
806 SwPaM & rPam( AddUndoRedoPaM(rContext) );
807 RemoveIdxFromRange(rPam, false);
808 SetPaM(rPam);
810 SwTable const*const pTable = rContext.GetDoc().TextToTable(
811 m_aInsertTableOpts, rPam, m_cSeparator, m_nAdjust, m_pAutoFormat.get() );
812 static_cast<SwFrameFormat*>(pTable->GetFrameFormat())->SetFormatName( m_sTableName );
815 void SwUndoTextToTable::RepeatImpl(::sw::RepeatContext & rContext)
817 // no Table In Table
818 if (!rContext.GetRepeatPaM().GetPointNode().FindTableNode())
820 rContext.GetDoc().TextToTable( m_aInsertTableOpts, rContext.GetRepeatPaM(),
821 m_cSeparator, m_nAdjust,
822 m_pAutoFormat.get() );
826 void SwUndoTextToTable::AddFillBox( const SwTableBox& rBox )
828 mvDelBoxes.push_back( rBox.GetSttIdx() );
831 SwHistory& SwUndoTextToTable::GetHistory()
833 if( !m_pHistory )
834 m_pHistory = new SwHistory;
835 return *m_pHistory;
838 SwUndoTableHeadline::SwUndoTableHeadline( const SwTable& rTable, sal_uInt16 nOldHdl,
839 sal_uInt16 nNewHdl )
840 : SwUndo( SwUndoId::TABLEHEADLINE, rTable.GetFrameFormat()->GetDoc() ),
841 m_nOldHeadline( nOldHdl ),
842 m_nNewHeadline( nNewHdl )
844 OSL_ENSURE( !rTable.GetTabSortBoxes().empty(), "Table without content" );
845 const SwStartNode *pSttNd = rTable.GetTabSortBoxes()[ 0 ]->GetSttNd();
846 OSL_ENSURE( pSttNd, "Box without content" );
848 m_nTableNode = pSttNd->StartOfSectionIndex();
851 void SwUndoTableHeadline::UndoImpl(::sw::UndoRedoContext & rContext)
853 SwDoc & rDoc = rContext.GetDoc();
854 SwTableNode* pTNd = rDoc.GetNodes()[ m_nTableNode ]->GetTableNode();
855 OSL_ENSURE( pTNd, "could not find any TableNode" );
857 rDoc.SetRowsToRepeat( pTNd->GetTable(), m_nOldHeadline );
860 void SwUndoTableHeadline::RedoImpl(::sw::UndoRedoContext & rContext)
862 SwDoc & rDoc = rContext.GetDoc();
864 SwTableNode* pTNd = rDoc.GetNodes()[ m_nTableNode ]->GetTableNode();
865 OSL_ENSURE( pTNd, "could not find any TableNode" );
867 rDoc.SetRowsToRepeat( pTNd->GetTable(), m_nNewHeadline );
870 void SwUndoTableHeadline::RepeatImpl(::sw::RepeatContext & rContext)
872 SwTableNode *const pTableNd =
873 rContext.GetRepeatPaM().GetPointNode().FindTableNode();
874 if( pTableNd )
876 rContext.GetDoc().SetRowsToRepeat( pTableNd->GetTable(), m_nNewHeadline );
880 SaveTable::SaveTable( const SwTable& rTable, sal_uInt16 nLnCnt, bool bSaveFormula )
881 : m_aTableSet(*rTable.GetFrameFormat()->GetAttrSet().GetPool(), aTableSetRange),
882 m_pSwTable(&rTable), m_nLineCount(nLnCnt), m_bSaveFormula(bSaveFormula)
884 m_bModifyBox = false;
885 m_bNewModel = rTable.IsNewModel();
886 m_aTableSet.Put(rTable.GetFrameFormat()->GetAttrSet());
887 m_pLine.reset( new SaveLine( nullptr, *rTable.GetTabLines()[ 0 ], *this ) );
889 SaveLine* pLn = m_pLine.get();
890 if( USHRT_MAX == nLnCnt )
891 nLnCnt = rTable.GetTabLines().size();
892 for( sal_uInt16 n = 1; n < nLnCnt; ++n )
893 pLn = new SaveLine( pLn, *rTable.GetTabLines()[ n ], *this );
895 m_aFrameFormats.clear();
896 m_pSwTable = nullptr;
899 sal_uInt16 SaveTable::AddFormat( SwFrameFormat* pFormat, bool bIsLine )
901 size_t nRet = m_aFrameFormats.GetPos(pFormat);
902 if( SIZE_MAX == nRet )
904 // Create copy of ItemSet
905 auto pSet = std::make_shared<SfxItemSet>( *pFormat->GetAttrSet().GetPool(),
906 bIsLine ? aTableLineSetRange : aTableBoxSetRange );
907 pSet->Put( pFormat->GetAttrSet() );
908 // When a formula is set, never save the value. It possibly must be
909 // recalculated.
910 // Save formulas always in plain text.
911 if( const SwTableBoxFormula* pItem = pSet->GetItemIfSet( RES_BOXATR_FORMULA ))
913 pSet->ClearItem( RES_BOXATR_VALUE );
914 if (m_pSwTable && m_bSaveFormula)
916 const_cast<SwTable*>(m_pSwTable)->SwitchFormulasToExternalRepresentation();
917 SwTableBoxFormula* pFormulaItem = const_cast<SwTableBoxFormula*>(pItem);
918 pFormulaItem->ChgDefinedIn(pFormat);
919 pFormulaItem->ToRelBoxNm(m_pSwTable);
920 pFormulaItem->ChgDefinedIn(nullptr);
923 nRet = m_aSets.size();
924 m_aSets.push_back(pSet);
925 m_aFrameFormats.insert(m_aFrameFormats.begin() + nRet, pFormat);
927 return o3tl::narrowing<sal_uInt16>(nRet);
930 void SaveTable::RestoreAttr( SwTable& rTable, bool bMdfyBox )
932 m_bModifyBox = bMdfyBox;
934 FndBox_ aTmpBox( nullptr, nullptr );
935 bool bHideChanges = rTable.GetFrameFormat()->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
936 // TODO delete/make frames only at changing line attribute TextChangesOnly (RES_PRINT) to true again
937 if ( bHideChanges )
938 aTmpBox.DelFrames( rTable );
940 // first, get back attributes of TableFrameFormat
941 SwFrameFormat* pFormat = rTable.GetFrameFormat();
942 SfxItemSet& rFormatSet = const_cast<SfxItemSet&>(static_cast<SfxItemSet const &>(pFormat->GetAttrSet()));
943 rFormatSet.ClearItem();
944 rFormatSet.Put(m_aTableSet);
946 pFormat->InvalidateInSwCache(RES_ATTRSET_CHG);
948 // table without table frame
949 bool bHiddenTable = true;
951 // for safety, invalidate all TableFrames
952 SwIterator<SwTabFrame,SwFormat> aIter( *pFormat );
953 for( SwTabFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
955 if( pLast->GetTable() == &rTable )
957 pLast->InvalidateAll();
958 pLast->SetCompletePaint();
959 bHiddenTable = false;
963 // fill FrameFormats with defaults (0)
964 pFormat = nullptr;
965 for (size_t n = m_aSets.size(); n; --n)
966 m_aFrameFormats.push_back(pFormat);
968 const size_t nLnCnt = (USHRT_MAX == m_nLineCount)
969 ? rTable.GetTabLines().size()
970 : m_nLineCount;
972 SaveLine* pLn = m_pLine.get();
973 for (size_t n = 0; n < nLnCnt; ++n, pLn = pLn->m_pNext)
975 if( !pLn )
977 OSL_ENSURE( false, "Number of lines changed" );
978 break;
981 pLn->RestoreAttr( *rTable.GetTabLines()[ n ], *this );
984 m_aFrameFormats.clear();
985 m_bModifyBox = false;
987 if ( bHideChanges )
989 if ( bHiddenTable )
991 SwTableNode* pTableNode = rTable.GetTableNode();
992 pTableNode->DelFrames();
993 pTableNode->MakeOwnFrames();
995 else
997 aTmpBox.MakeFrames( rTable );
1002 void SaveTable::SaveContentAttrs( SwDoc* pDoc )
1004 m_pLine->SaveContentAttrs(pDoc);
1007 void SaveTable::CreateNew( SwTable& rTable, bool bCreateFrames,
1008 bool bRestoreChart )
1010 FndBox_ aTmpBox( nullptr, nullptr );
1011 aTmpBox.DelFrames( rTable );
1013 // first, get back attributes of TableFrameFormat
1014 SwFrameFormat* pFormat = rTable.GetFrameFormat();
1015 SfxItemSet& rFormatSet = const_cast<SfxItemSet&>(static_cast<SfxItemSet const &>(pFormat->GetAttrSet()));
1016 rFormatSet.ClearItem();
1017 rFormatSet.Put(m_aTableSet);
1019 pFormat->InvalidateInSwCache(RES_ATTRSET_CHG);
1021 // SwTableBox must have a format - the SwTableBox takes ownership of it
1022 SwTableBoxFormat *const pNewFormat(pFormat->GetDoc()->MakeTableBoxFormat());
1023 SwTableBox aParent(pNewFormat, rTable.GetTabLines().size(), nullptr);
1025 // fill FrameFormats with defaults (0)
1026 pFormat = nullptr;
1027 for( size_t n = m_aSets.size(); n; --n )
1028 m_aFrameFormats.push_back(pFormat);
1030 m_pLine->CreateNew(rTable, aParent, *this);
1031 m_aFrameFormats.clear();
1033 // add new lines, delete old ones
1034 const size_t nOldLines = (USHRT_MAX == m_nLineCount)
1035 ? rTable.GetTabLines().size()
1036 : m_nLineCount;
1038 SwDoc *pDoc = rTable.GetFrameFormat()->GetDoc();
1039 SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
1040 size_t n = 0;
1041 for( ; n < aParent.GetTabLines().size(); ++n )
1043 SwTableLine* pLn = aParent.GetTabLines()[ n ];
1044 pLn->SetUpper( nullptr );
1045 if( n < nOldLines )
1047 SwTableLine* pOld = rTable.GetTabLines()[ n ];
1049 // TL_CHART2: notify chart about boxes to be removed
1050 const SwTableBoxes &rBoxes = pOld->GetTabBoxes();
1051 const size_t nBoxes = rBoxes.size();
1052 for (size_t k = 0; k < nBoxes; ++k)
1054 SwTableBox *pBox = rBoxes[k];
1055 if (pPCD)
1056 pPCD->DeleteBox( &rTable, *pBox );
1059 rTable.GetTabLines()[n] = pLn;
1060 delete pOld;
1062 else
1063 rTable.GetTabLines().insert( rTable.GetTabLines().begin() + n, pLn );
1066 if( n < nOldLines )
1068 // remove remaining lines...
1069 for (size_t k1 = 0; k1 < nOldLines - n; ++k1)
1071 const SwTableBoxes &rBoxes = rTable.GetTabLines()[n + k1]->GetTabBoxes();
1072 const size_t nBoxes = rBoxes.size();
1073 for (size_t k2 = 0; k2 < nBoxes; ++k2)
1075 SwTableBox *pBox = rBoxes[k2];
1076 // TL_CHART2: notify chart about boxes to be removed
1077 if (pPCD)
1078 pPCD->DeleteBox( &rTable, *pBox );
1082 for( SwTableLines::const_iterator it = rTable.GetTabLines().begin() + n;
1083 it != rTable.GetTabLines().begin() + nOldLines; ++it )
1084 delete *it;
1085 rTable.GetTabLines().erase( rTable.GetTabLines().begin() + n, rTable.GetTabLines().begin() + nOldLines );
1088 aParent.GetTabLines().erase( aParent.GetTabLines().begin(), aParent.GetTabLines().begin() + n );
1089 assert(aParent.GetTabLines().empty());
1091 if( bCreateFrames )
1092 aTmpBox.MakeFrames( rTable );
1093 if( bRestoreChart )
1095 // TL_CHART2: need to inform chart of probably changed cell names
1096 pDoc->UpdateCharts( rTable.GetFrameFormat()->GetName() );
1100 SwFrameFormat& SaveTable::CreateNewFormat(SwFrameFormat& rFormat, sal_uInt16 nFormatPos)
1102 rFormat.SetFormatAttr(*m_aSets[nFormatPos]);
1103 m_aFrameFormats[nFormatPos] = &rFormat;
1104 return rFormat;
1107 void SaveTable::NewFrameFormatForLine(const SwTableLine& rTableLn, sal_uInt16 nFormatPos, SwFrameFormat* pOldFormat)
1109 SwFrameFormat* pFormat = m_aFrameFormats[nFormatPos];
1110 if(!pFormat)
1111 pFormat = &CreateNewFormat(*pOldFormat->GetDoc()->MakeTableLineFormat(), nFormatPos);
1112 pOldFormat->CallSwClientNotify(sw::MoveTableLineHint(*pFormat, rTableLn));
1113 pFormat->Add(const_cast<SwTableLine*>(&rTableLn));
1114 KillEmptyFrameFormat(*pOldFormat);
1117 void SaveTable::NewFrameFormatForBox(const SwTableBox& rTableBx, sal_uInt16 nFormatPos, SwFrameFormat* pOldFormat)
1119 SwFrameFormat* pFormat = m_aFrameFormats[nFormatPos];
1120 if(!pFormat)
1121 pFormat = &CreateNewFormat(*pOldFormat->GetDoc()->MakeTableBoxFormat(), nFormatPos);
1122 pOldFormat->CallSwClientNotify(sw::MoveTableBoxHint(*pFormat, rTableBx));
1123 pFormat->MoveTableBox(*const_cast<SwTableBox*>(&rTableBx), m_bModifyBox ? pOldFormat : nullptr);
1124 KillEmptyFrameFormat(*pOldFormat);
1127 SaveLine::SaveLine(SaveLine* pPrev, const SwTableLine& rLine, SaveTable& rSTable)
1128 : m_pNext(nullptr)
1130 if( pPrev )
1131 pPrev->m_pNext = this;
1133 m_nItemSet = rSTable.AddFormat(rLine.GetFrameFormat(), true);
1135 m_pBox = new SaveBox(nullptr, *rLine.GetTabBoxes()[0], rSTable);
1136 SaveBox* pBx = m_pBox;
1137 for( size_t n = 1; n < rLine.GetTabBoxes().size(); ++n )
1138 pBx = new SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTable );
1141 SaveLine::~SaveLine()
1143 delete m_pBox;
1144 delete m_pNext;
1147 void SaveLine::RestoreAttr( SwTableLine& rLine, SaveTable& rSTable )
1149 rSTable.NewFrameFormatForLine(rLine, m_nItemSet, rLine.GetFrameFormat());
1151 SaveBox* pBx = m_pBox;
1152 for (size_t n = 0; n < rLine.GetTabBoxes().size(); ++n, pBx = pBx->m_pNext)
1154 if( !pBx )
1156 OSL_ENSURE( false, "Number of boxes changed" );
1157 break;
1159 pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTable );
1163 void SaveLine::SaveContentAttrs( SwDoc* pDoc )
1165 m_pBox->SaveContentAttrs(pDoc);
1166 if (m_pNext)
1167 m_pNext->SaveContentAttrs(pDoc);
1170 void SaveLine::CreateNew( SwTable& rTable, SwTableBox& rParent, SaveTable& rSTable )
1172 SwTableLineFormat* pFormat
1173 = static_cast<SwTableLineFormat*>(rSTable.m_aFrameFormats[m_nItemSet]);
1174 if( !pFormat )
1176 SwDoc* pDoc = rTable.GetFrameFormat()->GetDoc();
1177 pFormat = pDoc->MakeTableLineFormat();
1178 pFormat->SetFormatAttr(*rSTable.m_aSets[m_nItemSet]);
1179 rSTable.m_aFrameFormats[m_nItemSet] = pFormat;
1181 SwTableLine* pNew = new SwTableLine( pFormat, 1, &rParent );
1183 rParent.GetTabLines().push_back( pNew );
1185 m_pBox->CreateNew(rTable, *pNew, rSTable);
1187 if (m_pNext)
1188 m_pNext->CreateNew(rTable, rParent, rSTable);
1191 SaveBox::SaveBox(SaveBox* pPrev, const SwTableBox& rBox, SaveTable& rSTable)
1192 : m_pNext(nullptr)
1193 , m_nStartNode(NODE_OFFSET_MAX)
1194 , m_nRowSpan(0)
1196 m_Ptrs.pLine = nullptr;
1198 if( pPrev )
1199 pPrev->m_pNext = this;
1201 m_nItemSet = rSTable.AddFormat(rBox.GetFrameFormat(), false);
1203 if( rBox.GetSttNd() )
1205 m_nStartNode = rBox.GetSttIdx();
1206 m_nRowSpan = rBox.getRowSpan();
1208 else
1210 m_Ptrs.pLine = new SaveLine(nullptr, *rBox.GetTabLines()[0], rSTable);
1212 SaveLine* pLn = m_Ptrs.pLine;
1213 for( size_t n = 1; n < rBox.GetTabLines().size(); ++n )
1214 pLn = new SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTable );
1218 SaveBox::~SaveBox()
1220 if (NODE_OFFSET_MAX == m_nStartNode) // no EndBox
1221 delete m_Ptrs.pLine;
1222 else
1223 delete m_Ptrs.pContentAttrs;
1224 delete m_pNext;
1227 void SaveBox::RestoreAttr( SwTableBox& rBox, SaveTable& rSTable )
1229 rSTable.NewFrameFormatForBox(rBox, m_nItemSet, rBox.GetFrameFormat());
1231 if (NODE_OFFSET_MAX == m_nStartNode) // no EndBox
1233 if( rBox.GetTabLines().empty() )
1235 OSL_ENSURE( false, "Number of lines changed" );
1237 else
1239 SaveLine* pLn = m_Ptrs.pLine;
1240 for (size_t n = 0; n < rBox.GetTabLines().size(); ++n, pLn = pLn->m_pNext)
1242 if( !pLn )
1244 OSL_ENSURE( false, "Number of lines changed" );
1245 break;
1248 pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTable );
1252 else if (rBox.GetSttNd() && rBox.GetSttIdx() == m_nStartNode)
1254 if (m_Ptrs.pContentAttrs)
1256 SwNodes& rNds = rBox.GetFrameFormat()->GetDoc()->GetNodes();
1257 sal_uInt16 nSet = 0;
1258 SwNodeOffset nEnd = rBox.GetSttNd()->EndOfSectionIndex();
1259 for (SwNodeOffset n = m_nStartNode + 1; n < nEnd; ++n)
1261 SwContentNode* pCNd = rNds[ n ]->GetContentNode();
1262 if( pCNd )
1264 std::shared_ptr<SfxItemSet> pSet((*m_Ptrs.pContentAttrs)[nSet++]);
1265 if( pSet )
1267 for( const WhichPair& rPair : aSave_BoxContentSet )
1268 pCNd->ResetAttr( rPair.first, rPair.second );
1269 pCNd->SetAttr( *pSet );
1271 else
1272 pCNd->ResetAllAttr();
1277 else
1279 OSL_ENSURE( false, "Box not anymore at the same node" );
1283 void SaveBox::SaveContentAttrs( SwDoc* pDoc )
1285 if (NODE_OFFSET_MAX == m_nStartNode) // no EndBox
1287 // continue in current line
1288 m_Ptrs.pLine->SaveContentAttrs(pDoc);
1290 else
1292 SwNodeOffset nEnd = pDoc->GetNodes()[m_nStartNode]->EndOfSectionIndex();
1293 m_Ptrs.pContentAttrs = new SfxItemSets;
1294 for (SwNodeOffset n = m_nStartNode + 1; n < nEnd; ++n)
1296 SwContentNode* pCNd = pDoc->GetNodes()[ n ]->GetContentNode();
1297 if( pCNd )
1299 std::shared_ptr<SfxItemSet> pSet;
1300 if( pCNd->HasSwAttrSet() )
1302 pSet = std::make_shared<SfxItemSet>( pDoc->GetAttrPool(),
1303 aSave_BoxContentSet );
1304 pSet->Put( *pCNd->GetpSwAttrSet() );
1307 m_Ptrs.pContentAttrs->push_back(pSet);
1311 if (m_pNext)
1312 m_pNext->SaveContentAttrs(pDoc);
1315 void SaveBox::CreateNew( SwTable& rTable, SwTableLine& rParent, SaveTable& rSTable )
1317 SwTableBoxFormat* pFormat = static_cast<SwTableBoxFormat*>(rSTable.m_aFrameFormats[m_nItemSet]);
1318 if( !pFormat )
1320 SwDoc* pDoc = rTable.GetFrameFormat()->GetDoc();
1321 pFormat = pDoc->MakeTableBoxFormat();
1322 pFormat->SetFormatAttr(*rSTable.m_aSets[m_nItemSet]);
1323 rSTable.m_aFrameFormats[m_nItemSet] = pFormat;
1326 if (NODE_OFFSET_MAX == m_nStartNode) // no EndBox
1328 SwTableBox* pNew = new SwTableBox( pFormat, 1, &rParent );
1329 rParent.GetTabBoxes().push_back( pNew );
1331 m_Ptrs.pLine->CreateNew(rTable, *pNew, rSTable);
1333 else
1335 // search box for StartNode in old table
1336 SwTableBox* pBox = rTable.GetTableBox(m_nStartNode);
1337 if (pBox)
1339 SwFrameFormat* pOld = pBox->GetFrameFormat();
1340 pBox->RegisterToFormat( *pFormat );
1341 if( !pOld->HasWriterListeners() )
1342 delete pOld;
1344 pBox->setRowSpan(m_nRowSpan);
1346 SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
1347 pTBoxes->erase( std::find( pTBoxes->begin(), pTBoxes->end(), pBox ) );
1349 pBox->SetUpper( &rParent );
1350 pTBoxes = &rParent.GetTabBoxes();
1351 pTBoxes->push_back( pBox );
1355 if (m_pNext)
1356 m_pNext->CreateNew(rTable, rParent, rSTable);
1359 // UndoObject for attribute changes on table
1360 SwUndoAttrTable::SwUndoAttrTable( const SwTableNode& rTableNd, bool bClearTabCols )
1361 : SwUndo( SwUndoId::TABLE_ATTR, &rTableNd.GetDoc() ),
1362 m_nStartNode( rTableNd.GetIndex() )
1364 m_bClearTableCol = bClearTabCols;
1365 m_pSaveTable.reset( new SaveTable( rTableNd.GetTable() ) );
1368 SwUndoAttrTable::~SwUndoAttrTable()
1372 void SwUndoAttrTable::UndoImpl(::sw::UndoRedoContext & rContext)
1374 SwDoc & rDoc = rContext.GetDoc();
1375 SwTableNode* pTableNd = rDoc.GetNodes()[ m_nStartNode ]->GetTableNode();
1376 OSL_ENSURE( pTableNd, "no TableNode" );
1378 if (pTableNd)
1380 SaveTable* pOrig = new SaveTable( pTableNd->GetTable() );
1381 m_pSaveTable->RestoreAttr( pTableNd->GetTable() );
1382 m_pSaveTable.reset( pOrig );
1385 if( m_bClearTableCol )
1387 ClearFEShellTabCols(rDoc, nullptr);
1391 void SwUndoAttrTable::RedoImpl(::sw::UndoRedoContext & rContext)
1393 UndoImpl(rContext);
1396 // UndoObject for AutoFormat on Table
1397 SwUndoTableAutoFormat::SwUndoTableAutoFormat( const SwTableNode& rTableNd,
1398 const SwTableAutoFormat& rAFormat )
1399 : SwUndo( SwUndoId::TABLE_AUTOFMT, &rTableNd.GetDoc() )
1400 , m_TableStyleName(rTableNd.GetTable().GetTableStyleName())
1401 , m_nStartNode( rTableNd.GetIndex() )
1402 , m_bSaveContentAttr( false )
1403 , m_nRepeatHeading(rTableNd.GetTable().GetRowsToRepeat())
1405 m_pSaveTable.reset( new SaveTable( rTableNd.GetTable() ) );
1407 if( rAFormat.IsFont() || rAFormat.IsJustify() )
1409 // then also go over the ContentNodes of the EndBoxes and collect
1410 // all paragraph attributes
1411 m_pSaveTable->SaveContentAttrs( &const_cast<SwDoc&>(rTableNd.GetDoc()) );
1412 m_bSaveContentAttr = true;
1416 SwUndoTableAutoFormat::~SwUndoTableAutoFormat()
1420 void SwUndoTableAutoFormat::SaveBoxContent( const SwTableBox& rBox )
1422 m_Undos.push_back(std::make_shared<SwUndoTableNumFormat>(rBox));
1425 void
1426 SwUndoTableAutoFormat::UndoRedo(bool const bUndo, ::sw::UndoRedoContext & rContext)
1428 SwDoc & rDoc = rContext.GetDoc();
1429 SwTableNode* pTableNd = rDoc.GetNodes()[ m_nStartNode ]->GetTableNode();
1430 OSL_ENSURE( pTableNd, "no TableNode" );
1432 SwTable& table = pTableNd->GetTable();
1433 if (table.GetTableStyleName() != m_TableStyleName)
1435 OUString const temp(table.GetTableStyleName());
1436 table.SetTableStyleName(m_TableStyleName);
1437 m_TableStyleName = temp;
1439 SaveTable* pOrig = new SaveTable( table );
1440 // then go also over the ContentNodes of the EndBoxes and collect
1441 // all paragraph attributes
1442 if( m_bSaveContentAttr )
1443 pOrig->SaveContentAttrs( &rDoc );
1445 if (bUndo)
1447 for (size_t n = m_Undos.size(); 0 < n; --n)
1449 m_Undos.at(n-1)->UndoImpl(rContext);
1452 table.SetRowsToRepeat(m_nRepeatHeading);
1455 m_pSaveTable->RestoreAttr( pTableNd->GetTable(), !bUndo );
1456 m_pSaveTable.reset( pOrig );
1459 void SwUndoTableAutoFormat::UndoImpl(::sw::UndoRedoContext & rContext)
1461 UndoRedo(true, rContext);
1464 void SwUndoTableAutoFormat::RedoImpl(::sw::UndoRedoContext & rContext)
1466 UndoRedo(false, rContext);
1469 SwUndoTableNdsChg::SwUndoTableNdsChg( SwUndoId nAction,
1470 const SwSelBoxes& rBoxes,
1471 const SwTableNode& rTableNd,
1472 tools::Long nMn, tools::Long nMx,
1473 sal_uInt16 nCnt, bool bFlg, bool bSmHght )
1474 : SwUndo( nAction, &rTableNd.GetDoc() ),
1475 m_nMin( nMn ), m_nMax( nMx ),
1476 m_nSttNode( rTableNd.GetIndex() ),
1477 m_nCount( nCnt ),
1478 m_bFlag( bFlg ),
1479 m_bSameHeight( bSmHght )
1481 const SwTable& rTable = rTableNd.GetTable();
1482 m_pSaveTable.reset( new SaveTable( rTable ) );
1484 // and remember selection
1485 ReNewBoxes( rBoxes );
1488 void SwUndoTableNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes )
1490 if (rBoxes.size() != m_Boxes.size())
1492 m_Boxes.clear();
1493 for (size_t n = 0; n < rBoxes.size(); ++n)
1495 m_Boxes.insert( rBoxes[n]->GetSttIdx() );
1500 SwUndoTableNdsChg::~SwUndoTableNdsChg()
1504 void SwUndoTableNdsChg::SaveNewBoxes( const SwTableNode& rTableNd,
1505 const SwTableSortBoxes& rOld )
1507 const SwTable& rTable = rTableNd.GetTable();
1508 const SwTableSortBoxes& rTableBoxes = rTable.GetTabSortBoxes();
1510 OSL_ENSURE( ! IsDelBox(), "wrong Action" );
1511 m_xNewSttNds.emplace();
1513 size_t i = 0;
1514 for (size_t n = 0; n < rOld.size(); ++i)
1516 if( rOld[ n ] == rTableBoxes[ i ] )
1517 ++n;
1518 else
1519 // new box: insert sorted
1520 m_xNewSttNds->insert( BoxMove(rTableBoxes[ i ]->GetSttIdx()) );
1523 for( ; i < rTableBoxes.size(); ++i )
1524 // new box: insert sorted
1525 m_xNewSttNds->insert( BoxMove(rTableBoxes[ i ]->GetSttIdx()) );
1528 static SwTableLine* lcl_FindTableLine( const SwTable& rTable,
1529 const SwTableBox& rBox )
1531 SwTableLine* pRet = nullptr;
1532 // i63949: For nested cells we have to take nLineNo - 1, too, not 0!
1533 const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != nullptr ) ?
1534 rBox.GetUpper()->GetUpper()->GetTabLines()
1535 : rTable.GetTabLines();
1536 const SwTableLine* pLine = rBox.GetUpper();
1537 sal_uInt16 nLineNo = rTableLines.GetPos( pLine );
1538 pRet = rTableLines[nLineNo - 1];
1540 return pRet;
1543 static const SwTableLines& lcl_FindParentLines( const SwTable& rTable,
1544 const SwTableBox& rBox )
1546 const SwTableLines& rRet =
1547 ( rBox.GetUpper()->GetUpper() != nullptr ) ?
1548 rBox.GetUpper()->GetUpper()->GetTabLines() :
1549 rTable.GetTabLines();
1551 return rRet;
1554 void SwUndoTableNdsChg::SaveNewBoxes( const SwTableNode& rTableNd,
1555 const SwTableSortBoxes& rOld,
1556 const SwSelBoxes& rBoxes,
1557 const std::vector<SwNodeOffset> &rNodeCnts )
1559 const SwTable& rTable = rTableNd.GetTable();
1560 const SwTableSortBoxes& rTableBoxes = rTable.GetTabSortBoxes();
1562 OSL_ENSURE( ! IsDelBox(), "wrong Action" );
1563 m_xNewSttNds.emplace();
1565 OSL_ENSURE( rTable.IsNewModel() || rOld.size() + m_nCount * rBoxes.size() == rTableBoxes.size(),
1566 "unexpected boxes" );
1567 OSL_ENSURE( rOld.size() <= rTableBoxes.size(), "more unexpected boxes" );
1568 for (size_t n = 0, i = 0; i < rTableBoxes.size(); ++i)
1570 if( ( n < rOld.size() ) &&
1571 ( rOld[ n ] == rTableBoxes[ i ] ) )
1573 // box already known? Then nothing to be done.
1574 ++n;
1576 else
1578 // new box found: insert (obey sort order)
1579 const SwTableBox* pBox = rTableBoxes[ i ];
1581 // find the source box. It must be one in rBoxes.
1582 // We found the right one if it's in the same column as pBox.
1583 // No, if more than one selected cell in the same column has been split,
1584 // we have to look for the nearest one (i65201)!
1585 const SwTableBox* pSourceBox = nullptr;
1586 const SwTableBox* pCheckBox = nullptr;
1587 const SwTableLine* pBoxLine = pBox->GetUpper();
1588 sal_uInt16 nLineDiff = lcl_FindParentLines(rTable,*pBox).GetPos(pBoxLine);
1589 sal_uInt16 nLineNo = 0;
1590 for (size_t j = 0; j < rBoxes.size(); ++j)
1592 pCheckBox = rBoxes[j];
1593 if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() )
1595 const SwTableLine* pCheckLine = pCheckBox->GetUpper();
1596 sal_uInt16 nCheckLine = lcl_FindParentLines( rTable, *pCheckBox ).
1597 GetPos( pCheckLine );
1598 if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff )
1600 nLineNo = nCheckLine;
1601 pSourceBox = pCheckBox;
1606 // find the line number difference
1607 // (to help determine bNodesMoved flag below)
1608 nLineDiff = nLineDiff - nLineNo;
1609 OSL_ENSURE( pSourceBox, "Split source box not found!" );
1610 // find out how many nodes the source box used to have
1611 // (to help determine bNodesMoved flag below)
1612 size_t nNdsPos = 0;
1613 while( rBoxes[ nNdsPos ] != pSourceBox )
1614 ++nNdsPos;
1615 SwNodeOffset nNodes = rNodeCnts[ nNdsPos ];
1617 // When a new table cell is created, it either gets a new
1618 // node, or it gets node(s) from elsewhere. The undo must
1619 // know, of course, and thus we must determine here just
1620 // where pBox's nodes are from:
1621 // If 1) the source box has lost nodes, and
1622 // 2) we're in the node range that got nodes
1623 // then pBox received nodes from elsewhere.
1624 // If bNodesMoved is set for pBox the undo must move the
1625 // boxes back, otherwise it must delete them.
1626 bool bNodesMoved = pSourceBox &&
1627 ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() -
1628 pSourceBox->GetSttIdx() ) )
1629 && ( nNodes - 1 > SwNodeOffset(nLineDiff) );
1630 m_xNewSttNds->insert( BoxMove(pBox->GetSttIdx(), bNodesMoved) );
1635 void SwUndoTableNdsChg::SaveSection( SwStartNode* pSttNd )
1637 OSL_ENSURE( IsDelBox(), "wrong Action" );
1638 if (m_pDelSects == nullptr)
1639 m_pDelSects.reset(new SwUndoSaveSections);
1641 SwTableNode* pTableNd = pSttNd->FindTableNode();
1642 std::unique_ptr<SwUndoSaveSection, o3tl::default_delete<SwUndoSaveSection>> pSave(new SwUndoSaveSection);
1643 pSave->SaveSection( SwNodeIndex( *pSttNd ));
1645 m_pDelSects->push_back(std::move(pSave));
1646 m_nSttNode = pTableNd->GetIndex();
1649 void SwUndoTableNdsChg::UndoImpl(::sw::UndoRedoContext & rContext)
1651 SwDoc & rDoc = rContext.GetDoc();
1652 SwNodeIndex aIdx( rDoc.GetNodes(), m_nSttNode );
1654 SwTableNode *const pTableNd = aIdx.GetNode().GetTableNode();
1655 OSL_ENSURE( pTableNd, "no TableNode" );
1656 pTableNd->GetTable().SwitchFormulasToInternalRepresentation();
1658 CHECK_TABLE( pTableNd->GetTable() )
1660 FndBox_ aTmpBox( nullptr, nullptr );
1661 // ? TL_CHART2: notification or locking of controller required ?
1663 SwChartDataProvider *pPCD = rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider();
1664 SwSelBoxes aDelBoxes;
1665 std::vector< std::pair<SwTableBox *, SwNodeOffset> > aDelNodes;
1666 if( IsDelBox() )
1668 // Trick: add missing boxes in any line, they will be connected
1669 // correctly when calling CreateNew
1670 SwTableBox* pCpyBox = pTableNd->GetTable().GetTabSortBoxes()[0];
1671 SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
1673 // restore sections
1674 for (size_t n = m_pDelSects->size(); n; )
1676 SwUndoSaveSection *const pSave = (*m_pDelSects)[ --n ].get();
1677 pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode );
1678 if( pSave->GetHistory() )
1679 pSave->GetHistory()->Rollback( &rDoc );
1680 SwTableBox* pBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pCpyBox->GetFrameFormat()), aIdx,
1681 pCpyBox->GetUpper() );
1682 rLnBoxes.push_back( pBox );
1684 m_pDelSects->clear();
1686 else if( !m_xNewSttNds->empty() )
1688 // Then the nodes have be moved and not deleted!
1689 // But for that we need a temp array.
1690 std::vector<BoxMove> aTmp( m_xNewSttNds->begin(), m_xNewSttNds->end() );
1692 // backwards
1693 for (size_t n = aTmp.size(); n > 0 ; )
1695 --n;
1696 // delete box from table structure
1697 SwNodeOffset nIdx = aTmp[n].index;
1698 SwTableBox* pBox = pTableNd->GetTable().GetTableBox( nIdx );
1699 OSL_ENSURE( pBox, "Where is my TableBox?" );
1701 // TL_CHART2: notify chart about box to be removed
1702 if (pPCD)
1703 pPCD->DeleteBox( &pTableNd->GetTable(), *pBox );
1705 // insert _before_ deleting the section - otherwise the box
1706 // has no start node so all boxes sort equal in SwSelBoxes
1707 aDelBoxes.insert(pBox);
1709 if( aTmp[n].hasMoved )
1711 SwNodeRange aRg( *pBox->GetSttNd(), SwNodeOffset(1),
1712 *pBox->GetSttNd()->EndOfSectionNode() );
1714 SwTableLine* pLine = lcl_FindTableLine( pTableNd->GetTable(), *pBox );
1715 SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 );
1717 // adjust all StartNode indices
1718 size_t i = n;
1719 SwNodeOffset nSttIdx = aInsPos.GetIndex() - 2,
1720 nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
1721 while( i && aTmp[ --i ].index > nSttIdx )
1722 aTmp[ i ].index += nNdCnt;
1724 // first delete box
1725 delete pBox;
1726 // than move nodes
1727 rDoc.GetNodes().MoveNodes( aRg, rDoc.GetNodes(), aInsPos.GetNode(), false );
1729 else
1731 aDelNodes.emplace_back(pBox, nIdx);
1735 else
1737 // Remove nodes from nodes array (backwards!)
1738 std::set<BoxMove>::reverse_iterator it;
1739 for( it = m_xNewSttNds->rbegin(); it != m_xNewSttNds->rend(); ++it )
1741 SwNodeOffset nIdx = (*it).index;
1742 SwTableBox* pBox = pTableNd->GetTable().GetTableBox( nIdx );
1743 OSL_ENSURE( pBox, "Where's my table box?" );
1744 // TL_CHART2: notify chart about box to be removed
1745 if (pPCD)
1746 pPCD->DeleteBox( &pTableNd->GetTable(), *pBox );
1747 aDelBoxes.insert(pBox);
1748 aDelNodes.emplace_back(pBox, nIdx);
1752 // fdo#57197: before deleting the SwTableBoxes, delete the SwTabFrames
1753 aTmpBox.SetTableLines(aDelBoxes, pTableNd->GetTable());
1754 aTmpBox.DelFrames(pTableNd->GetTable());
1756 // do this _after_ deleting Frames because disposing SwAccessible requires
1757 // connection to the nodes, see SwAccessibleChild::IsAccessible()
1758 for (const std::pair<SwTableBox *, SwNodeOffset> & rDelNode : aDelNodes)
1760 // first disconnect box from node, otherwise ~SwTableBox would
1761 // access pBox->pSttNd, deleted by DeleteSection
1762 rDelNode.first->RemoveFromTable();
1763 rDoc.getIDocumentContentOperations().DeleteSection(rDoc.GetNodes()[ rDelNode.second ]);
1766 // Remove boxes from table structure
1767 for( size_t n = 0; n < aDelBoxes.size(); ++n )
1769 SwTableBox* pCurrBox = aDelBoxes[n];
1770 SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes();
1771 pTBoxes->erase( std::find( pTBoxes->begin(), pTBoxes->end(), pCurrBox ) );
1772 delete pCurrBox;
1775 m_pSaveTable->CreateNew( pTableNd->GetTable(), true, false );
1777 // TL_CHART2: need to inform chart of probably changed cell names
1778 rDoc.UpdateCharts( pTableNd->GetTable().GetFrameFormat()->GetName() );
1779 if (SwFEShell* pFEShell = rDoc.GetDocShell()->GetFEShell())
1780 pFEShell->UpdateTableStyleFormatting(pTableNd);
1781 if( IsDelBox() )
1782 m_nSttNode = pTableNd->GetIndex();
1783 ClearFEShellTabCols(rDoc, nullptr);
1784 CHECK_TABLE( pTableNd->GetTable() )
1787 void SwUndoTableNdsChg::RedoImpl(::sw::UndoRedoContext & rContext)
1789 SwDoc & rDoc = rContext.GetDoc();
1791 SwTableNode* pTableNd = rDoc.GetNodes()[ m_nSttNode ]->GetTableNode();
1792 OSL_ENSURE( pTableNd, "no TableNode" );
1793 CHECK_TABLE( pTableNd->GetTable() )
1795 SwSelBoxes aSelBoxes;
1796 for (const auto& rBox : m_Boxes)
1798 SwTableBox* pBox = pTableNd->GetTable().GetTableBox( rBox );
1799 aSelBoxes.insert( pBox );
1802 // create SelBoxes and call InsertCell/-Row/SplitTable
1803 switch( GetId() )
1805 case SwUndoId::TABLE_INSCOL:
1806 rDoc.InsertCol( aSelBoxes, m_nCount, m_bFlag );
1807 break;
1809 case SwUndoId::TABLE_INSROW:
1810 rDoc.InsertRow( aSelBoxes, m_nCount, m_bFlag );
1811 break;
1813 case SwUndoId::TABLE_SPLIT:
1814 rDoc.SplitTable( aSelBoxes, m_bFlag, m_nCount, m_bSameHeight );
1815 break;
1816 case SwUndoId::TABLE_DELBOX:
1817 case SwUndoId::ROW_DELETE:
1818 case SwUndoId::COL_DELETE:
1820 SwTable &rTable = pTableNd->GetTable();
1821 rTable.SwitchFormulasToInternalRepresentation();
1822 if( m_nMax > m_nMin && rTable.IsNewModel() )
1823 rTable.PrepareDeleteCol( m_nMin, m_nMax );
1824 rTable.DeleteSel( &rDoc, aSelBoxes, nullptr, this, true, true );
1825 m_nSttNode = pTableNd->GetIndex();
1827 break;
1828 default:
1831 ClearFEShellTabCols(rDoc, nullptr);
1832 CHECK_TABLE( pTableNd->GetTable() )
1835 SwUndoTableMerge::SwUndoTableMerge( const SwPaM& rTableSel )
1836 : SwUndo( SwUndoId::TABLE_MERGE, &rTableSel.GetDoc() ), SwUndRng( rTableSel )
1838 const SwTableNode* pTableNd = rTableSel.GetPointNode().FindTableNode();
1839 OSL_ENSURE( pTableNd, "Where is the TableNode?" );
1840 m_pSaveTable.reset( new SaveTable( pTableNd->GetTable() ) );
1841 m_nTableNode = pTableNd->GetIndex();
1844 SwUndoTableMerge::~SwUndoTableMerge()
1846 m_pSaveTable.reset();
1847 m_vMoves.clear();
1848 m_pHistory.reset();
1851 void SwUndoTableMerge::UndoImpl(::sw::UndoRedoContext & rContext)
1853 SwDoc & rDoc = rContext.GetDoc();
1854 SwNodeIndex aIdx( rDoc.GetNodes(), m_nTableNode );
1856 SwTableNode *const pTableNd = aIdx.GetNode().GetTableNode();
1857 OSL_ENSURE( pTableNd, "no TableNode" );
1859 pTableNd->GetTable().SwitchFormulasToInternalRepresentation();
1861 // ? TL_CHART2: notification or locking of controller required ?
1863 // 1. restore deleted boxes:
1864 // Trick: add missing boxes in any line, they will be connected
1865 // correctly when calling CreateNew
1866 SwTableBox *pBox, *pCpyBox = pTableNd->GetTable().GetTabSortBoxes()[0];
1867 SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
1869 CHECKTABLE(pTableNd->GetTable())
1871 SwSelBoxes aSelBoxes;
1872 SwTextFormatColl* pColl = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD );
1874 for (const auto& rBox : m_Boxes)
1876 aIdx = rBox;
1877 SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx.GetNode(),
1878 SwTableBoxStartNode, pColl );
1879 pBox = new SwTableBox( static_cast<SwTableBoxFormat*>(pCpyBox->GetFrameFormat()), *pSttNd,
1880 pCpyBox->GetUpper() );
1881 rLnBoxes.push_back( pBox );
1883 aSelBoxes.insert( pBox );
1886 CHECKTABLE(pTableNd->GetTable())
1888 SwChartDataProvider *pPCD = rDoc.getIDocumentChartDataProviderAccess().GetChartDataProvider();
1889 // 2. deleted the inserted boxes
1890 // delete nodes (from last to first)
1891 for( size_t n = m_aNewStartNodes.size(); n; )
1893 // remove box from table structure
1894 SwNodeOffset nIdx = m_aNewStartNodes[ --n ];
1896 if( !nIdx && n )
1898 nIdx = m_aNewStartNodes[ --n ];
1899 pBox = pTableNd->GetTable().GetTableBox( nIdx );
1900 OSL_ENSURE( pBox, "Where is my TableBox?" );
1902 if( !m_pSaveTable->IsNewModel() )
1903 rDoc.GetNodes().MakeTextNode(
1904 const_cast<SwEndNode&>(*pBox->GetSttNd()->EndOfSectionNode()), pColl );
1906 // this was the separator -> restore moved ones
1907 for (size_t i = m_vMoves.size(); i; )
1909 SwTextNode* pTextNd = nullptr;
1910 sal_Int32 nDelPos = 0;
1911 SwUndoMove *const pUndo = m_vMoves[ --i ].get();
1912 if( !pUndo->IsMoveRange() )
1914 pTextNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTextNode();
1915 nDelPos = pUndo->GetDestSttContent() - 1;
1917 pUndo->UndoImpl(rContext);
1918 if( pUndo->IsMoveRange() )
1920 // delete the unnecessary node
1921 aIdx = pUndo->GetEndNode();
1922 SwContentNode *pCNd = aIdx.GetNode().GetContentNode();
1923 if( pCNd )
1925 SwNodeIndex aTmp( aIdx, -1 );
1926 SwContentNode *pMove = aTmp.GetNode().GetContentNode();
1927 if( pMove )
1928 pCNd->MoveTo( *pMove );
1930 rDoc.GetNodes().Delete( aIdx );
1932 else if( pTextNd )
1934 // also delete not needed attributes
1935 SwContentIndex aTmpIdx( pTextNd, nDelPos );
1936 if( pTextNd->GetpSwpHints() && pTextNd->GetpSwpHints()->Count() )
1937 pTextNd->RstTextAttr( nDelPos, pTextNd->GetText().getLength() - nDelPos + 1 );
1938 // delete separator
1939 pTextNd->EraseText( aTmpIdx, 1 );
1942 nIdx = pBox->GetSttIdx();
1944 else
1945 pBox = pTableNd->GetTable().GetTableBox( nIdx );
1947 if( !m_pSaveTable->IsNewModel() )
1949 // TL_CHART2: notify chart about box to be removed
1950 if (pPCD)
1951 pPCD->DeleteBox( &pTableNd->GetTable(), *pBox );
1953 SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
1954 pTBoxes->erase( std::find(pTBoxes->begin(), pTBoxes->end(), pBox ) );
1956 // delete indices from section
1958 SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
1959 SwDoc::CorrAbs( SwNodeIndex( aTmpIdx, 1 ),
1960 SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ),
1961 SwPosition( aTmpIdx, nullptr, 0 ), true );
1964 delete pBox;
1965 rDoc.getIDocumentContentOperations().DeleteSection( rDoc.GetNodes()[ nIdx ] );
1968 CHECKTABLE(pTableNd->GetTable())
1970 m_pSaveTable->CreateNew( pTableNd->GetTable(), true, false );
1972 // TL_CHART2: need to inform chart of probably changed cell names
1973 rDoc.UpdateCharts( pTableNd->GetTable().GetFrameFormat()->GetName() );
1975 if( m_pHistory )
1977 m_pHistory->TmpRollback( &rDoc, 0 );
1978 m_pHistory->SetTmpEnd( m_pHistory->Count() );
1980 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
1981 pPam->DeleteMark();
1982 pPam->GetPoint()->Assign(m_nSttNode, m_nSttContent );
1983 pPam->SetMark();
1984 pPam->DeleteMark();
1986 CHECKTABLE(pTableNd->GetTable())
1987 ClearFEShellTabCols(rDoc, nullptr);
1990 void SwUndoTableMerge::RedoImpl(::sw::UndoRedoContext & rContext)
1992 SwDoc & rDoc = rContext.GetDoc();
1993 SwPaM & rPam( AddUndoRedoPaM(rContext) );
1994 rDoc.MergeTable(rPam);
1997 void SwUndoTableMerge::MoveBoxContent( SwDoc& rDoc, SwNodeRange& rRg, SwNode& rPos )
1999 SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 );
2000 std::unique_ptr<SwUndoMove> pUndo(new SwUndoMove( rDoc, rRg, rPos ));
2001 ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
2002 rDoc.getIDocumentContentOperations().MoveNodeRange( rRg, rPos, m_pSaveTable->IsNewModel() ?
2003 SwMoveFlags::NO_DELFRMS :
2004 SwMoveFlags::DEFAULT );
2005 ++aTmp;
2006 ++aTmp2;
2007 pUndo->SetDestRange( aTmp2.GetNode(), rPos, aTmp );
2009 m_vMoves.push_back(std::move(pUndo));
2012 void SwUndoTableMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
2014 // memorize selection
2015 for (size_t n = 0; n < rBoxes.size(); ++n)
2017 m_Boxes.insert(rBoxes[n]->GetSttIdx());
2020 // as separator for inserts of new boxes after shifting
2021 m_aNewStartNodes.push_back( SwNodeOffset(0) );
2023 // The new table model does not delete overlapped cells (by row span),
2024 // so the rBoxes array might be empty even some cells have been merged.
2025 if( !rBoxes.empty() )
2026 m_nTableNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex();
2029 void SwUndoTableMerge::SaveCollection( const SwTableBox& rBox )
2031 if( !m_pHistory )
2032 m_pHistory.reset(new SwHistory);
2034 SwNodeIndex aIdx( *rBox.GetSttNd(), 1 );
2035 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
2036 if( !pCNd )
2037 pCNd = aIdx.GetNodes().GoNext( &aIdx );
2039 m_pHistory->Add( pCNd->GetFormatColl(), aIdx.GetIndex(), pCNd->GetNodeType());
2040 if( pCNd->HasSwAttrSet() )
2041 m_pHistory->CopyFormatAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() );
2044 SwUndoTableNumFormat::SwUndoTableNumFormat( const SwTableBox& rBox,
2045 const SfxItemSet* pNewSet )
2046 : SwUndo(SwUndoId::TBLNUMFMT, rBox.GetFrameFormat()->GetDoc())
2047 , m_nFormatIdx(getSwDefaultTextFormat())
2048 , m_nNewFormatIdx(0)
2049 , m_fNum(0.0)
2050 , m_fNewNum(0.0)
2051 , m_bNewFormat(false)
2052 , m_bNewFormula(false)
2053 , m_bNewValue(false)
2055 m_nNode = rBox.GetSttIdx();
2057 m_nNodePos = rBox.IsValidNumTextNd( nullptr == pNewSet );
2058 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2060 if( NODE_OFFSET_MAX != m_nNodePos )
2062 SwTextNode* pTNd = pDoc->GetNodes()[ m_nNodePos ]->GetTextNode();
2064 m_pHistory.reset(new SwHistory);
2065 SwRegHistory aRHst( *rBox.GetSttNd(), m_pHistory.get() );
2066 // always save all text attributes because of possibly overlapping
2067 // areas of on/off
2068 m_pHistory->CopyAttr( pTNd->GetpSwpHints(), m_nNodePos, 0,
2069 pTNd->GetText().getLength(), true );
2071 if( pTNd->HasSwAttrSet() )
2072 m_pHistory->CopyFormatAttr( *pTNd->GetpSwAttrSet(), m_nNodePos );
2074 m_aStr = pTNd->GetText();
2075 if( pTNd->GetpSwpHints() )
2076 pTNd->GetpSwpHints()->DeRegister();
2079 m_pBoxSet.reset( new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange ) );
2080 m_pBoxSet->Put( rBox.GetFrameFormat()->GetAttrSet() );
2082 if( pNewSet )
2084 if( const SwTableBoxNumFormat* pItem = pNewSet->GetItemIfSet( RES_BOXATR_FORMAT,
2085 false ))
2087 m_bNewFormat = true;
2088 m_nNewFormatIdx = pItem->GetValue();
2090 if( const SwTableBoxFormula* pItem = pNewSet->GetItemIfSet( RES_BOXATR_FORMULA,
2091 false ))
2093 m_bNewFormula = true;
2094 m_aNewFormula = pItem->GetFormula();
2096 if( const SwTableBoxValue* pItem = pNewSet->GetItemIfSet( RES_BOXATR_VALUE,
2097 false ))
2099 m_bNewValue = true;
2100 m_fNewNum = pItem->GetValue();
2104 // is a history needed at all?
2105 if (m_pHistory && !m_pHistory->Count())
2107 m_pHistory.reset();
2111 SwUndoTableNumFormat::~SwUndoTableNumFormat()
2113 m_pHistory.reset();
2114 m_pBoxSet.reset();
2117 void SwUndoTableNumFormat::UndoImpl(::sw::UndoRedoContext & rContext)
2119 OSL_ENSURE( m_pBoxSet, "Where's the stored item set?" );
2121 SwDoc & rDoc = rContext.GetDoc();
2122 SwStartNode* pSttNd = rDoc.GetNodes()[ m_nNode ]->
2123 FindSttNodeByType( SwTableBoxStartNode );
2124 OSL_ENSURE( pSttNd, "without StartNode no TableBox" );
2125 SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTableBox(
2126 pSttNd->GetIndex() );
2127 OSL_ENSURE( pBox, "found no TableBox" );
2129 SwTableBoxFormat* pFormat = rDoc.MakeTableBoxFormat();
2130 pFormat->SetFormatAttr( *m_pBoxSet );
2131 pBox->ChgFrameFormat( pFormat );
2133 if( NODE_OFFSET_MAX == m_nNodePos )
2134 return;
2136 SwTextNode* pTextNd = rDoc.GetNodes()[ m_nNodePos ]->GetTextNode();
2137 // If more than one node was deleted then all "node" attributes were also
2138 // saved
2139 if( pTextNd->HasSwAttrSet() )
2140 pTextNd->ResetAllAttr();
2142 if( pTextNd->GetpSwpHints() && !m_aStr.isEmpty() )
2143 pTextNd->ClearSwpHintsArr( true );
2145 // ChgTextToNum(..) only acts when the strings are different. We need to do
2146 // the same here.
2147 if( pTextNd->GetText() != m_aStr )
2149 rDoc.getIDocumentRedlineAccess().DeleteRedline( *( pBox->GetSttNd() ), false, RedlineType::Any );
2151 SwContentIndex aIdx( pTextNd, 0 );
2152 if( !m_aStr.isEmpty() )
2154 pTextNd->EraseText( aIdx );
2155 pTextNd->InsertText( m_aStr, aIdx,
2156 SwInsertFlags::NOHINTEXPAND );
2160 if( m_pHistory )
2162 sal_uInt16 nTmpEnd = m_pHistory->GetTmpEnd();
2163 m_pHistory->TmpRollback( &rDoc, 0 );
2164 m_pHistory->SetTmpEnd( nTmpEnd );
2167 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2168 pPam->DeleteMark();
2169 pPam->GetPoint()->Assign( m_nNode + 1 );
2172 namespace {
2174 /** switch the RedlineFlags on the given document, using
2175 * SetRedlineFlags_intern. This class set the mode in the constructor,
2176 * and changes it back in the destructor, i.e. it uses the
2177 * initialization-is-resource-acquisition idiom.
2179 class RedlineFlagsInternGuard
2181 SwDoc& mrDoc;
2182 RedlineFlags meOldRedlineFlags;
2184 public:
2185 RedlineFlagsInternGuard(
2186 SwDoc& rDoc, // change mode of this document
2187 RedlineFlags eNewRedlineFlags, // new redline mode
2188 RedlineFlags eRedlineFlagsMask /*change only bits set in this mask*/);
2190 ~RedlineFlagsInternGuard();
2195 RedlineFlagsInternGuard::RedlineFlagsInternGuard(
2196 SwDoc& rDoc,
2197 RedlineFlags eNewRedlineFlags,
2198 RedlineFlags eRedlineFlagsMask )
2199 : mrDoc( rDoc ),
2200 meOldRedlineFlags( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() )
2202 mrDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ( meOldRedlineFlags & ~eRedlineFlagsMask ) |
2203 ( eNewRedlineFlags & eRedlineFlagsMask ) );
2206 RedlineFlagsInternGuard::~RedlineFlagsInternGuard()
2208 mrDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( meOldRedlineFlags );
2211 void SwUndoTableNumFormat::RedoImpl(::sw::UndoRedoContext & rContext)
2213 // Could the box be changed?
2214 if( !m_pBoxSet )
2215 return ;
2217 SwDoc & rDoc = rContext.GetDoc();
2218 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2220 pPam->DeleteMark();
2221 pPam->GetPoint()->Assign( m_nNode );
2223 SwNode * pNd = & pPam->GetPoint()->GetNode();
2224 SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode );
2225 assert(pSttNd && "without StartNode no TableBox");
2226 SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTableBox(
2227 pSttNd->GetIndex() );
2228 OSL_ENSURE( pBox, "found no TableBox" );
2230 SwFrameFormat* pBoxFormat = pBox->ClaimFrameFormat();
2231 if( m_bNewFormat || m_bNewFormula || m_bNewValue )
2233 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aBoxSet( rDoc.GetAttrPool() );
2235 // Resetting attributes is not enough. In addition, take care that the
2236 // text will be also formatted correctly.
2237 pBoxFormat->LockModify();
2239 if( m_bNewFormula )
2240 aBoxSet.Put( SwTableBoxFormula( m_aNewFormula ));
2241 else
2242 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
2243 if( m_bNewFormat )
2244 aBoxSet.Put( SwTableBoxNumFormat( m_nNewFormatIdx ));
2245 else
2246 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT );
2247 if( m_bNewValue )
2248 aBoxSet.Put( SwTableBoxValue( m_fNewNum ));
2249 else
2250 pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
2251 pBoxFormat->UnlockModify();
2253 // dvo: When redlining is (was) enabled, setting the attribute
2254 // will also change the cell content. To allow this, the
2255 // RedlineFlags::Ignore flag must be removed during Redo. #108450#
2256 RedlineFlagsInternGuard aGuard( rDoc, RedlineFlags::NONE, RedlineFlags::Ignore );
2257 pBoxFormat->SetFormatAttr( aBoxSet );
2259 else if( getSwDefaultTextFormat() != m_nFormatIdx )
2261 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aBoxSet( rDoc.GetAttrPool() );
2263 aBoxSet.Put( SwTableBoxNumFormat( m_nFormatIdx ));
2264 aBoxSet.Put( SwTableBoxValue( m_fNum ));
2266 // Resetting attributes is not enough. In addition, take care that the
2267 // text will be also formatted correctly.
2268 pBoxFormat->LockModify();
2269 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
2270 pBoxFormat->UnlockModify();
2272 // dvo: When redlining is (was) enabled, setting the attribute
2273 // will also change the cell content. To allow this, the
2274 // RedlineFlags::Ignore flag must be removed during Redo. #108450#
2275 RedlineFlagsInternGuard aGuard( rDoc, RedlineFlags::NONE, RedlineFlags::Ignore );
2276 pBoxFormat->SetFormatAttr( aBoxSet );
2278 else
2280 // it's no number
2282 // Resetting attributes is not enough. In addition, take care that the
2283 // text will be also formatted correctly.
2284 pBoxFormat->SetFormatAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
2286 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2289 if( m_bNewFormula )
2291 // No matter what was set, an update of the table is always a good idea
2292 rDoc.getIDocumentFieldsAccess().UpdateTableFields(&pSttNd->FindTableNode()->GetTable());
2295 if( !pNd->IsContentNode() )
2296 pNd = rDoc.GetNodes().GoNext( pPam->GetPoint() );
2299 void SwUndoTableNumFormat::SetBox( const SwTableBox& rBox )
2301 m_nNode = rBox.GetSttIdx();
2304 UndoTableCpyTable_Entry::UndoTableCpyTable_Entry( const SwTableBox& rBox )
2305 : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ),
2306 bJoin( false )
2310 void UndoTableCpyTable_Entry::dumpAsXml(xmlTextWriterPtr pWriter) const
2312 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("UndoTableCpyTable_Entry"));
2314 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("nBoxIdx"));
2315 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
2316 BAD_CAST(OString::number(sal_Int32(nBoxIdx)).getStr()));
2317 (void)xmlTextWriterEndElement(pWriter);
2319 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("nOffset"));
2320 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
2321 BAD_CAST(OString::number(sal_Int32(nOffset)).getStr()));
2322 (void)xmlTextWriterEndElement(pWriter);
2324 if (pBoxNumAttr)
2326 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pBoxNumAttr"));
2327 pBoxNumAttr->dumpAsXml(pWriter);
2328 (void)xmlTextWriterEndElement(pWriter);
2331 if (pUndo)
2333 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pUndo"));
2334 pUndo->dumpAsXml(pWriter);
2335 (void)xmlTextWriterEndElement(pWriter);
2338 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("bJoin"));
2339 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
2340 BAD_CAST(OString::boolean(bJoin).getStr()));
2341 (void)xmlTextWriterEndElement(pWriter);
2343 (void)xmlTextWriterEndElement(pWriter);
2346 SwUndoTableCpyTable::SwUndoTableCpyTable(const SwDoc& rDoc)
2347 : SwUndo( SwUndoId::TBLCPYTBL, &rDoc )
2351 SwUndoTableCpyTable::~SwUndoTableCpyTable()
2353 m_vArr.clear();
2354 m_pInsRowUndo.reset();
2357 void SwUndoTableCpyTable::UndoImpl(::sw::UndoRedoContext & rContext)
2359 SwDoc & rDoc = rContext.GetDoc();
2360 DEBUG_REDLINE( &rDoc )
2362 SwTableNode* pTableNd = nullptr;
2363 for (size_t n = m_vArr.size(); n; )
2365 UndoTableCpyTable_Entry *const pEntry = m_vArr[ --n ].get();
2366 SwNodeOffset nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2367 SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2368 if( !pTableNd )
2369 pTableNd = pSNd->FindTableNode();
2371 SwTableBox* pBox = pTableNd->GetTable().GetTableBox( nSttPos );
2372 if (!pBox)
2374 SAL_WARN("sw.core",
2375 "SwUndoTableCpyTable::UndoImpl: invalid start node index for table box");
2376 continue;
2379 SwTableBox& rBox = *pBox;
2381 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2382 rDoc.GetNodes().MakeTextNode( aInsIdx.GetNode(), rDoc.GetDfltTextFormatColl() );
2384 // b62341295: Redline for copying tables
2385 const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode();
2386 SwPaM aPam( aInsIdx.GetNode(), *pEndNode );
2387 std::unique_ptr<SwUndoDelete> pUndo;
2389 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) )
2391 bool bDeleteCompleteParagraph = false;
2392 bool bShiftPam = false;
2393 // There are a couple of different situations to consider during redlining
2394 if( pEntry->pUndo )
2396 SwUndoDelete *const pUndoDelete =
2397 dynamic_cast<SwUndoDelete*>(pEntry->pUndo.get());
2398 SwUndoRedlineDelete *const pUndoRedlineDelete =
2399 dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo.get());
2400 assert(pUndoDelete || pUndoRedlineDelete);
2401 if (pUndoRedlineDelete)
2403 // The old content was not empty or he has been merged with the new content
2404 bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged
2405 // Set aTmpIdx to the beginning of the old content
2406 SwNodeIndex aTmpIdx( *pEndNode,
2407 pUndoRedlineDelete->NodeDiff()-1 );
2408 SwTextNode *pText = aTmpIdx.GetNode().GetTextNode();
2409 if( pText )
2411 aPam.GetPoint()->Assign(*pText,
2412 pUndoRedlineDelete->ContentStart() );
2414 else
2415 aPam.GetPoint()->Assign( aTmpIdx );
2417 else if (pUndoDelete && pUndoDelete->IsDelFullPara())
2419 // When the old content was an empty paragraph, but could not be joined
2420 // with the new content (e.g. because of a section or table)
2421 // We "save" the aPam.Point, we go one step backwards (because later on the
2422 // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag
2423 // for step forward later on.
2424 bDeleteCompleteParagraph = true;
2425 bShiftPam = true;
2426 aPam.GetPoint()->Assign(*pEndNode, SwNodeOffset(-1));
2429 rDoc.getIDocumentRedlineAccess().DeleteRedline( aPam, true, RedlineType::Any );
2431 if( pEntry->pUndo )
2433 pEntry->pUndo->UndoImpl(rContext);
2434 pEntry->pUndo.reset();
2436 if( bShiftPam )
2438 // The aPam.Point is at the moment at the last position of the new content and has to be
2439 // moved to the first position of the old content for the SwUndoDelete operation
2440 aPam.GetPoint()->Assign(aPam.GetPoint()->GetNode(), SwNodeOffset(1));
2442 pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, bDeleteCompleteParagraph, true);
2444 else
2446 pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true);
2447 if( pEntry->pUndo )
2449 pEntry->pUndo->UndoImpl(rContext);
2450 pEntry->pUndo.reset();
2453 pEntry->pUndo = std::move(pUndo);
2455 aInsIdx = rBox.GetSttIdx() + 1;
2456 rDoc.GetNodes().Delete( aInsIdx );
2458 SfxItemSetFixed<
2459 RES_VERT_ORIENT, RES_VERT_ORIENT,
2460 RES_BOXATR_FORMAT, RES_BOXATR_VALUE>
2461 aTmpSet(rDoc.GetAttrPool());
2462 aTmpSet.Put( rBox.GetFrameFormat()->GetAttrSet() );
2463 if( aTmpSet.Count() )
2465 SwFrameFormat* pBoxFormat = rBox.ClaimFrameFormat();
2466 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2467 pBoxFormat->ResetFormatAttr( RES_VERT_ORIENT );
2470 if( pEntry->pBoxNumAttr )
2472 rBox.ClaimFrameFormat()->SetFormatAttr( *pEntry->pBoxNumAttr );
2473 pEntry->pBoxNumAttr.reset();
2476 if( aTmpSet.Count() )
2478 pEntry->pBoxNumAttr = std::make_unique<SfxItemSetFixed<
2479 RES_VERT_ORIENT, RES_VERT_ORIENT,
2480 RES_BOXATR_FORMAT, RES_BOXATR_VALUE>>(rDoc.GetAttrPool());
2481 pEntry->pBoxNumAttr->Put( aTmpSet );
2484 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2487 if( m_pInsRowUndo )
2489 m_pInsRowUndo->UndoImpl(rContext);
2491 DEBUG_REDLINE( &rDoc )
2494 void SwUndoTableCpyTable::RedoImpl(::sw::UndoRedoContext & rContext)
2496 SwDoc & rDoc = rContext.GetDoc();
2497 DEBUG_REDLINE( &rDoc )
2499 if( m_pInsRowUndo )
2501 m_pInsRowUndo->RedoImpl(rContext);
2504 SwTableNode* pTableNd = nullptr;
2505 for (size_t n = 0; n < m_vArr.size(); ++n)
2507 UndoTableCpyTable_Entry *const pEntry = m_vArr[ n ].get();
2508 SwNodeOffset nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2509 SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2510 if( !pTableNd )
2511 pTableNd = pSNd->FindTableNode();
2513 SwTableBox& rBox = *pTableNd->GetTable().GetTableBox( nSttPos );
2515 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2517 // b62341295: Redline for copying tables - Start.
2518 rDoc.GetNodes().MakeTextNode( aInsIdx.GetNode(), rDoc.GetDfltTextFormatColl() );
2519 SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
2520 std::unique_ptr<SwUndo> pUndo(IDocumentRedlineAccess::IsRedlineOn(GetRedlineFlags())
2521 ? nullptr
2522 : std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true));
2523 if( pEntry->pUndo )
2525 pEntry->pUndo->UndoImpl(rContext);
2526 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) )
2528 // PrepareRedline has to be called with the beginning of the old content
2529 // When new and old content has been joined, the rIter.pAktPam has been set
2530 // by the Undo operation to this point.
2531 // Otherwise aInsIdx has been moved during the Undo operation
2532 if( pEntry->bJoin )
2534 SwPaM& rLastPam =
2535 rContext.GetCursorSupplier().GetCurrentShellCursor();
2536 pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(),
2537 pEntry->bJoin, true );
2539 else
2541 SwPosition aTmpPos( aInsIdx );
2542 pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true );
2545 pEntry->pUndo.reset();
2547 pEntry->pUndo = std::move(pUndo);
2548 // b62341295: Redline for copying tables - End.
2550 aInsIdx = rBox.GetSttIdx() + 1;
2551 rDoc.GetNodes().Delete( aInsIdx );
2553 SfxItemSetFixed<
2554 RES_VERT_ORIENT, RES_VERT_ORIENT,
2555 RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aTmpSet(rDoc.GetAttrPool());
2556 aTmpSet.Put( rBox.GetFrameFormat()->GetAttrSet() );
2557 if( aTmpSet.Count() )
2559 SwFrameFormat* pBoxFormat = rBox.ClaimFrameFormat();
2560 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2561 pBoxFormat->ResetFormatAttr( RES_VERT_ORIENT );
2563 if( pEntry->pBoxNumAttr )
2565 rBox.ClaimFrameFormat()->SetFormatAttr( *pEntry->pBoxNumAttr );
2566 pEntry->pBoxNumAttr.reset();
2569 if( aTmpSet.Count() )
2571 pEntry->pBoxNumAttr = std::make_unique<SfxItemSetFixed<
2572 RES_VERT_ORIENT, RES_VERT_ORIENT,
2573 RES_BOXATR_FORMAT, RES_BOXATR_VALUE>>(rDoc.GetAttrPool());
2574 pEntry->pBoxNumAttr->Put( aTmpSet );
2577 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2579 DEBUG_REDLINE( &rDoc )
2582 void SwUndoTableCpyTable::AddBoxBefore( const SwTableBox& rBox, bool bDelContent )
2584 if (!m_vArr.empty() && !bDelContent)
2585 return;
2587 UndoTableCpyTable_Entry* pEntry = new UndoTableCpyTable_Entry( rBox );
2588 m_vArr.push_back(std::unique_ptr<UndoTableCpyTable_Entry>(pEntry));
2590 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2591 DEBUG_REDLINE( pDoc )
2592 if( bDelContent )
2594 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2595 pDoc->GetNodes().MakeTextNode( aInsIdx.GetNode(), pDoc->GetDfltTextFormatColl() );
2596 SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
2598 if( !pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
2599 pEntry->pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true);
2602 pEntry->pBoxNumAttr = std::make_unique<SfxItemSetFixed<
2603 RES_VERT_ORIENT, RES_VERT_ORIENT,
2604 RES_BOXATR_FORMAT, RES_BOXATR_VALUE>>(pDoc->GetAttrPool());
2605 pEntry->pBoxNumAttr->Put( rBox.GetFrameFormat()->GetAttrSet() );
2606 if( !pEntry->pBoxNumAttr->Count() )
2608 pEntry->pBoxNumAttr.reset();
2610 DEBUG_REDLINE( pDoc )
2613 void SwUndoTableCpyTable::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, bool bDelContent )
2615 UndoTableCpyTable_Entry *const pEntry = m_vArr.back().get();
2617 // If the content was deleted then remove also the temporarily created node
2618 if( bDelContent )
2620 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2621 DEBUG_REDLINE( pDoc )
2623 if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
2625 SwPosition aTmpPos( rIdx );
2626 pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false );
2628 SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 );
2629 rBox.GetFrameFormat()->GetDoc()->GetNodes().Delete( aDelIdx );
2630 DEBUG_REDLINE( pDoc )
2633 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2636 // PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations.
2637 // bRedo is set by calling from Redo()
2638 // rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has
2639 // been merged.
2640 // rJoin is true if Redo() is calling and the content has already been merged
2642 std::unique_ptr<SwUndo> SwUndoTableCpyTable::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox,
2643 SwPosition& rPos, bool& rJoin, bool bRedo )
2645 std::unique_ptr<SwUndo> pUndo;
2646 // b62341295: Redline for copying tables
2647 // What's to do?
2648 // Mark the cell content before rIdx as insertion,
2649 // mark the cell content behind rIdx as deletion
2650 // merge text nodes at rIdx if possible
2651 RedlineFlags eOld = pDoc->getIDocumentRedlineAccess().GetRedlineFlags();
2652 pDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern( ( eOld | RedlineFlags::DontCombineRedlines ) & ~RedlineFlags::Ignore );
2653 SwPosition aInsertEnd( rPos );
2654 SwTextNode* pText;
2655 if( !rJoin )
2657 // If the content is not merged, the end of the insertion is at the end of the node
2658 // _before_ the given position rPos
2659 aInsertEnd.Adjust(SwNodeOffset(-1));
2660 pText = aInsertEnd.GetNode().GetTextNode();
2661 if( pText )
2663 aInsertEnd.SetContent(pText->GetText().getLength());
2664 if( !bRedo && rPos.GetNode().GetTextNode() )
2665 { // Try to merge, if not called by Redo()
2666 rJoin = true;
2668 // Park this somewhere else so nothing points to the to-be-deleted node.
2669 rPos.nContent.Assign(pText, 0);
2671 pText->JoinNext();
2674 else
2675 aInsertEnd.nContent.Assign(nullptr, 0);
2677 // For joined (merged) contents the start of deletion and end of insertion are identical
2678 // otherwise adjacent nodes.
2679 SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos );
2680 if( !rJoin )
2682 pText = aDeleteStart.GetNode().GetTextNode();
2683 if( pText )
2684 aDeleteStart.SetContent( 0 );
2686 SwPosition aCellEnd( *rBox.GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
2687 pText = aCellEnd.GetNode().GetTextNode();
2688 if( pText )
2689 aCellEnd.SetContent(pText->GetText().getLength());
2690 if( aDeleteStart != aCellEnd )
2691 { // If the old (deleted) part is not empty, here we are...
2692 SwPaM aDeletePam( aDeleteStart, aCellEnd );
2693 pUndo = std::make_unique<SwUndoRedlineDelete>( aDeletePam, SwUndoId::DELETE );
2694 pDoc->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Delete, aDeletePam ), true );
2696 else if( !rJoin ) // If the old part is empty and joined, we are finished
2697 { // if it is not joined, we have to delete this empty paragraph
2698 aCellEnd.Assign(*rBox.GetSttNd()->EndOfSectionNode());
2699 SwPaM aTmpPam( aDeleteStart, aCellEnd );
2700 pUndo = std::make_unique<SwUndoDelete>(aTmpPam, SwDeleteFlags::Default, true);
2702 SwPosition aCellStart( *rBox.GetSttNd(), SwNodeOffset(2) );
2703 pText = aCellStart.GetNode().GetTextNode();
2704 if( pText )
2705 aCellStart.SetContent( 0 );
2706 if( aCellStart != aInsertEnd ) // An empty insertion will not been marked
2708 SwPaM aTmpPam( aCellStart, aInsertEnd );
2709 pDoc->getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, aTmpPam ), true );
2712 pDoc->getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
2713 return pUndo;
2716 bool SwUndoTableCpyTable::InsertRow( SwTable& rTable, const SwSelBoxes& rBoxes,
2717 sal_uInt16 nCnt )
2719 SwTableNode* pTableNd = const_cast<SwTableNode*>(rTable.GetTabSortBoxes()[0]->
2720 GetSttNd()->FindTableNode());
2722 m_pInsRowUndo.reset( new SwUndoTableNdsChg( SwUndoId::TABLE_INSROW, rBoxes, *pTableNd,
2723 0, 0, nCnt, true, false ) );
2724 SwTableSortBoxes aTmpLst( rTable.GetTabSortBoxes() );
2726 bool bRet = rTable.InsertRow( rTable.GetFrameFormat()->GetDoc(), rBoxes, nCnt, /*bBehind*/true );
2727 if( bRet )
2728 m_pInsRowUndo->SaveNewBoxes( *pTableNd, aTmpLst );
2729 else
2731 m_pInsRowUndo.reset();
2733 return bRet;
2736 void SwUndoTableCpyTable::dumpAsXml(xmlTextWriterPtr pWriter) const
2738 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoTableCpyTable"));
2740 for (const auto& pEntry : m_vArr)
2742 pEntry->dumpAsXml(pWriter);
2745 if (m_pInsRowUndo)
2747 m_pInsRowUndo->dumpAsXml(pWriter);
2750 (void)xmlTextWriterEndElement(pWriter);
2753 bool SwUndoTableCpyTable::IsEmpty() const
2755 return !m_pInsRowUndo && m_vArr.empty();
2758 SwUndoCpyTable::SwUndoCpyTable(const SwDoc& rDoc)
2759 : SwUndo( SwUndoId::CPYTBL, &rDoc ), m_nTableNode( 0 )
2763 SwUndoCpyTable::~SwUndoCpyTable()
2767 void SwUndoCpyTable::UndoImpl(::sw::UndoRedoContext & rContext)
2769 SwDoc & rDoc = rContext.GetDoc();
2770 SwTableNode* pTNd = rDoc.GetNodes()[ m_nTableNode ]->GetTableNode();
2772 // move hard page breaks into next node
2773 SwContentNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetContentNode();
2774 if( pNextNd )
2776 SwFrameFormat* pTableFormat = pTNd->GetTable().GetFrameFormat();
2778 if( const SwFormatPageDesc* pItem = pTableFormat->GetItemIfSet( RES_PAGEDESC,
2779 false ) )
2780 pNextNd->SetAttr( *pItem );
2782 if( const SvxFormatBreakItem* pItem = pTableFormat->GetItemIfSet( RES_BREAK,
2783 false ) )
2784 pNextNd->SetAttr( *pItem );
2787 SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), SwNodeOffset(0) , SwNodeOffset(1) );
2788 m_pDelete.reset(new SwUndoDelete(aPam, SwDeleteFlags::Default, true));
2791 void SwUndoCpyTable::RedoImpl(::sw::UndoRedoContext & rContext)
2793 m_pDelete->UndoImpl(rContext);
2794 m_pDelete.reset();
2797 SwUndoSplitTable::SwUndoSplitTable( const SwTableNode& rTableNd,
2798 std::unique_ptr<SwSaveRowSpan> pRowSp, SplitTable_HeadlineOption eMode, bool bNewSize )
2799 : SwUndo( SwUndoId::SPLIT_TABLE, &rTableNd.GetDoc() ),
2800 m_nTableNode( rTableNd.GetIndex() ), m_nOffset( 0 ), mpSaveRowSpan( std::move(pRowSp) ),
2801 m_nMode( eMode ), m_nFormulaEnd( 0 ), m_bCalcNewSize( bNewSize )
2803 switch( m_nMode )
2805 case SplitTable_HeadlineOption::BoxAttrAllCopy:
2806 m_pHistory.reset(new SwHistory);
2807 [[fallthrough]];
2808 case SplitTable_HeadlineOption::BorderCopy:
2809 case SplitTable_HeadlineOption::BoxAttrCopy:
2810 m_pSavedTable.reset(new SaveTable( rTableNd.GetTable(), 1, false ));
2811 break;
2812 default: break;
2816 SwUndoSplitTable::~SwUndoSplitTable()
2818 m_pSavedTable.reset();
2819 m_pHistory.reset();
2820 mpSaveRowSpan.reset();
2823 void SwUndoSplitTable::UndoImpl(::sw::UndoRedoContext & rContext)
2825 SwDoc *const pDoc = & rContext.GetDoc();
2826 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2828 SwPosition& rPtPos = *pPam->GetPoint();
2829 rPtPos.Assign( m_nTableNode + m_nOffset );
2830 assert(rPtPos.GetNode().GetContentNode()->Len() == 0); // empty para inserted
2833 // avoid asserts from ~SwContentIndexReg
2834 SwNodeIndex const idx(pDoc->GetNodes(), m_nTableNode + m_nOffset);
2836 SwPaM pam(idx);
2837 pam.Move(fnMoveBackward, GoInContent);
2838 ::PaMCorrAbs(*pPam, *pam.GetPoint());
2841 // remove implicitly created paragraph again
2842 pDoc->GetNodes().Delete( idx );
2845 rPtPos.Assign( m_nTableNode + m_nOffset );
2846 SwTableNode* pTableNd = rPtPos.GetNode().GetTableNode();
2847 SwTable& rTable = pTableNd->GetTable();
2848 rTable.SwitchFormulasToInternalRepresentation();
2850 switch( m_nMode )
2852 case SplitTable_HeadlineOption::BoxAttrAllCopy:
2853 if( m_pHistory )
2854 m_pHistory->TmpRollback( pDoc, m_nFormulaEnd );
2855 [[fallthrough]];
2856 case SplitTable_HeadlineOption::BoxAttrCopy:
2857 case SplitTable_HeadlineOption::BorderCopy:
2859 m_pSavedTable->CreateNew( rTable, false );
2860 m_pSavedTable->RestoreAttr( rTable );
2862 break;
2864 case SplitTable_HeadlineOption::ContentCopy:
2865 // the created first line has to be removed again
2867 SwSelBoxes aSelBoxes;
2868 SwTableBox* pBox = rTable.GetTableBox( m_nTableNode + m_nOffset + 1 );
2869 SwTable::SelLineFromBox( pBox, aSelBoxes );
2870 FndBox_ aTmpBox( nullptr, nullptr );
2871 aTmpBox.SetTableLines( aSelBoxes, rTable );
2872 aTmpBox.DelFrames( rTable );
2873 rTable.DeleteSel( pDoc, aSelBoxes, nullptr, nullptr, false, false );
2875 break;
2876 default: break;
2879 pDoc->GetNodes().MergeTable( rPtPos.GetNode() );
2881 if( m_pHistory )
2883 m_pHistory->TmpRollback( pDoc, 0 );
2884 m_pHistory->SetTmpEnd( m_pHistory->Count() );
2886 if( mpSaveRowSpan )
2888 pTableNd = rPtPos.GetNode().FindTableNode();
2889 if( pTableNd )
2890 pTableNd->GetTable().RestoreRowSpan( *mpSaveRowSpan );
2892 ClearFEShellTabCols(*pDoc, nullptr);
2895 void SwUndoSplitTable::RedoImpl(::sw::UndoRedoContext & rContext)
2897 SwDoc *const pDoc = & rContext.GetDoc();
2898 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2900 pPam->DeleteMark();
2901 pPam->GetPoint()->Assign( m_nTableNode );
2902 pDoc->SplitTable( *pPam->GetPoint(), m_nMode, m_bCalcNewSize );
2904 ClearFEShellTabCols(*pDoc, nullptr);
2907 void SwUndoSplitTable::RepeatImpl(::sw::RepeatContext & rContext)
2909 SwPaM *const pPam = & rContext.GetRepeatPaM();
2910 SwDoc *const pDoc = & rContext.GetDoc();
2912 pDoc->SplitTable( *pPam->GetPoint(), m_nMode, m_bCalcNewSize );
2913 ClearFEShellTabCols(*pDoc, nullptr);
2916 void SwUndoSplitTable::SaveFormula( SwHistory& rHistory )
2918 if( !m_pHistory )
2919 m_pHistory.reset(new SwHistory);
2921 m_nFormulaEnd = rHistory.Count();
2922 m_pHistory->Move( 0, &rHistory );
2925 SwUndoMergeTable::SwUndoMergeTable( const SwTableNode& rTableNd,
2926 const SwTableNode& rDelTableNd,
2927 bool bWithPrv )
2928 : SwUndo( SwUndoId::MERGE_TABLE, &rTableNd.GetDoc() ),
2929 m_bWithPrev( bWithPrv )
2931 // memorize end node of the last table cell that'll stay in position
2932 if( m_bWithPrev )
2933 m_nTableNode = rDelTableNd.EndOfSectionIndex() - 1;
2934 else
2935 m_nTableNode = rTableNd.EndOfSectionIndex() - 1;
2937 m_aName = rDelTableNd.GetTable().GetFrameFormat()->GetName();
2938 m_pSaveTable.reset(new SaveTable( rDelTableNd.GetTable() ));
2940 if (m_bWithPrev)
2941 m_pSaveHdl.reset( new SaveTable( rTableNd.GetTable(), 1 ) );
2944 SwUndoMergeTable::~SwUndoMergeTable()
2946 m_pSaveTable.reset();
2947 m_pSaveHdl.reset();
2948 m_pHistory.reset();
2951 void SwUndoMergeTable::UndoImpl(::sw::UndoRedoContext & rContext)
2953 SwDoc *const pDoc = & rContext.GetDoc();
2954 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2956 pPam->DeleteMark();
2957 SwPosition& rPtPos = *pPam->GetPoint();
2958 rPtPos.Assign( m_nTableNode);
2960 SwTableNode* pTableNd = rPtPos.GetNode().FindTableNode();
2961 SwTable* pTable = &pTableNd->GetTable();
2962 pTable->SwitchFormulasToInternalRepresentation();
2964 // get lines for layout update
2965 FndBox_ aFndBox( nullptr, nullptr );
2966 aFndBox.SetTableLines( *pTable );
2967 aFndBox.DelFrames( *pTable );
2968 // ? TL_CHART2: notification or locking of controller required ?
2970 SwTableNode* pNew = pDoc->GetNodes().SplitTable( rPtPos.GetNode() );
2972 // update layout
2973 aFndBox.MakeFrames( *pTable );
2974 // ? TL_CHART2: notification or locking of controller required ?
2976 if( m_bWithPrev )
2978 // move name
2979 pNew->GetTable().GetFrameFormat()->SetFormatName( pTable->GetFrameFormat()->GetName() );
2980 m_pSaveHdl->RestoreAttr( pNew->GetTable() );
2982 else
2983 pTable = &pNew->GetTable();
2985 pTable->GetFrameFormat()->SetFormatName( m_aName );
2986 m_pSaveTable->RestoreAttr( *pTable );
2988 if( m_pHistory )
2990 m_pHistory->TmpRollback( pDoc, 0 );
2991 m_pHistory->SetTmpEnd( m_pHistory->Count() );
2994 // create frames for the new table
2995 pNew->MakeOwnFrames();
2997 // position cursor somewhere in content
2998 pDoc->GetNodes().GoNext( &rPtPos );
3000 ClearFEShellTabCols(*pDoc, nullptr);
3002 // TL_CHART2: need to inform chart of probably changed cell names
3003 SwChartDataProvider *pPCD = pDoc->getIDocumentChartDataProviderAccess().GetChartDataProvider();
3004 if (pPCD)
3006 pDoc->UpdateCharts( pTable->GetFrameFormat()->GetName() );
3007 pDoc->UpdateCharts( pNew->GetTable().GetFrameFormat()->GetName() );
3011 void SwUndoMergeTable::RedoImpl(::sw::UndoRedoContext & rContext)
3013 SwDoc *const pDoc = & rContext.GetDoc();
3014 SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3016 pPam->DeleteMark();
3017 if( m_bWithPrev )
3018 pPam->GetPoint()->Assign( m_nTableNode + 3 );
3019 else
3020 pPam->GetPoint()->Assign( m_nTableNode );
3022 pDoc->MergeTable( *pPam->GetPoint(), m_bWithPrev );
3024 ClearFEShellTabCols(*pDoc, nullptr);
3027 void SwUndoMergeTable::RepeatImpl(::sw::RepeatContext & rContext)
3029 SwDoc *const pDoc = & rContext.GetDoc();
3030 SwPaM *const pPam = & rContext.GetRepeatPaM();
3032 pDoc->MergeTable( *pPam->GetPoint(), m_bWithPrev );
3033 ClearFEShellTabCols(*pDoc, nullptr);
3036 void SwUndoMergeTable::SaveFormula( SwHistory& rHistory )
3038 if( !m_pHistory )
3039 m_pHistory.reset( new SwHistory );
3040 m_pHistory->Move( 0, &rHistory );
3043 void InsertSort( std::vector<sal_uInt16>& rArr, sal_uInt16 nIdx )
3045 size_t nO = rArr.size();
3046 size_t nU = 0;
3047 if( nO > 0 )
3049 nO--;
3050 while( nU <= nO )
3052 const size_t nM = nU + ( nO - nU ) / 2;
3053 if ( rArr[nM] == nIdx )
3055 OSL_FAIL( "Index already exists. This should never happen." );
3056 return;
3058 if( rArr[nM] < nIdx )
3059 nU = nM + 1;
3060 else if( nM == 0 )
3061 break;
3062 else
3063 nO = nM - 1;
3066 rArr.insert( rArr.begin() + nU, nIdx );
3069 #if OSL_DEBUG_LEVEL > 0
3070 void CheckTable( const SwTable& rTable )
3072 const SwNodes& rNds = rTable.GetFrameFormat()->GetDoc()->GetNodes();
3073 const SwTableSortBoxes& rSrtArr = rTable.GetTabSortBoxes();
3074 for (size_t n = 0; n < rSrtArr.size(); ++n)
3076 const SwTableBox* pBox = rSrtArr[ n ];
3077 const SwNode* pNd = pBox->GetSttNd();
3078 OSL_ENSURE( rNds[ pBox->GetSttIdx() ] == pNd, "Box with wrong StartNode" );
3081 #endif
3083 SwUndoTableStyleMake::SwUndoTableStyleMake(OUString aName, const SwDoc& rDoc)
3084 : SwUndo(SwUndoId::TBLSTYLE_CREATE, &rDoc),
3085 m_sName(std::move(aName))
3088 SwUndoTableStyleMake::~SwUndoTableStyleMake()
3091 void SwUndoTableStyleMake::UndoImpl(::sw::UndoRedoContext & rContext)
3093 m_pAutoFormat = rContext.GetDoc().DelTableStyle(m_sName, true);
3096 void SwUndoTableStyleMake::RedoImpl(::sw::UndoRedoContext & rContext)
3098 if (m_pAutoFormat)
3100 SwTableAutoFormat* pFormat = rContext.GetDoc().MakeTableStyle(m_sName, true);
3101 if (pFormat)
3103 *pFormat = *m_pAutoFormat;
3104 m_pAutoFormat.reset();
3109 SwRewriter SwUndoTableStyleMake::GetRewriter() const
3111 SwRewriter aResult;
3112 aResult.AddRule(UndoArg1, m_sName);
3113 return aResult;
3116 SwUndoTableStyleDelete::SwUndoTableStyleDelete(std::unique_ptr<SwTableAutoFormat> pAutoFormat, std::vector<SwTable*>&& rAffectedTables, const SwDoc& rDoc)
3117 : SwUndo(SwUndoId::TBLSTYLE_DELETE, &rDoc),
3118 m_pAutoFormat(std::move(pAutoFormat)),
3119 m_rAffectedTables(std::move(rAffectedTables))
3122 SwUndoTableStyleDelete::~SwUndoTableStyleDelete()
3125 void SwUndoTableStyleDelete::UndoImpl(::sw::UndoRedoContext & rContext)
3127 SwTableAutoFormat* pNewFormat = rContext.GetDoc().MakeTableStyle(m_pAutoFormat->GetName(), true);
3128 *pNewFormat = *m_pAutoFormat;
3129 for (size_t i=0; i < m_rAffectedTables.size(); i++)
3130 m_rAffectedTables[i]->SetTableStyleName(m_pAutoFormat->GetName());
3133 void SwUndoTableStyleDelete::RedoImpl(::sw::UndoRedoContext & rContext)
3135 // Don't need to remember deleted table style nor affected tables, because they must be the same as these already known.
3136 rContext.GetDoc().DelTableStyle(m_pAutoFormat->GetName());
3139 SwRewriter SwUndoTableStyleDelete::GetRewriter() const
3141 SwRewriter aResult;
3142 aResult.AddRule(UndoArg1, m_pAutoFormat->GetName());
3143 return aResult;
3146 SwUndoTableStyleUpdate::SwUndoTableStyleUpdate(const SwTableAutoFormat& rNewFormat, const SwTableAutoFormat& rOldFormat, const SwDoc& rDoc)
3147 : SwUndo(SwUndoId::TBLSTYLE_UPDATE, &rDoc)
3148 , m_pOldFormat(new SwTableAutoFormat(rOldFormat))
3149 , m_pNewFormat(new SwTableAutoFormat(rNewFormat))
3152 SwUndoTableStyleUpdate::~SwUndoTableStyleUpdate()
3155 void SwUndoTableStyleUpdate::UndoImpl(::sw::UndoRedoContext & rContext)
3157 rContext.GetDoc().ChgTableStyle(m_pNewFormat->GetName(), *m_pOldFormat);
3160 void SwUndoTableStyleUpdate::RedoImpl(::sw::UndoRedoContext & rContext)
3162 rContext.GetDoc().ChgTableStyle(m_pNewFormat->GetName(), *m_pNewFormat);
3165 SwRewriter SwUndoTableStyleUpdate::GetRewriter() const
3167 SwRewriter aResult;
3168 aResult.AddRule(UndoArg1, m_pNewFormat->GetName());
3169 return aResult;
3172 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */