update dev300-m58
[ooovba.git] / sw / source / core / undo / untbl.cxx
blobf08e8b3cc5bc6533cfdcc42861a7550d2b37d749
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: untbl.cxx,v $
10 * $Revision: 1.41 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <svx/brkitem.hxx>
37 #include <fmtornt.hxx>
38 #include <fmtpdsc.hxx>
39 #include <doc.hxx>
40 #include <editsh.hxx>
41 #include <docary.hxx>
42 #include <ndtxt.hxx>
43 #include <swtable.hxx>
44 #include <pam.hxx>
45 #include <cntfrm.hxx>
46 #include <tblsel.hxx>
47 #include <swundo.hxx> // fuer die UndoIds
48 #include <undobj.hxx>
49 #include <rolbck.hxx>
50 #include <ddefld.hxx>
51 #include <tabcol.hxx>
52 #include <tabfrm.hxx>
53 #include <rowfrm.hxx>
54 #include <cellfrm.hxx>
55 #include <swcache.hxx>
56 #include <tblafmt.hxx>
57 #include <poolfmt.hxx>
58 #include <mvsave.hxx>
59 #include <cellatr.hxx>
60 #include <swtblfmt.hxx>
61 #include <swddetbl.hxx>
62 #include <redline.hxx>
63 #include <node2lay.hxx>
64 #include <tblrwcl.hxx>
65 #include <fmtanchr.hxx>
66 #include <comcore.hrc>
67 #include <unochart.hxx>
70 #ifdef PRODUCT
71 #define CHECK_TABLE(t)
72 #else
73 #ifdef DEBUG
74 #define CHECK_TABLE(t) (t).CheckConsistency();
75 #else
76 #define CHECK_TABLE(t)
77 #endif
78 #endif
80 #ifdef PRODUCT
81 #define _DEBUG_REDLINE( pDoc )
82 #else
83 void lcl_DebugRedline( const SwDoc* pDoc );
84 #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc );
85 #endif
87 inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); }
88 extern void ClearFEShellTabCols();
90 typedef SfxItemSet* SfxItemSetPtr;
91 SV_DECL_PTRARR_DEL( SfxItemSets, SfxItemSetPtr, 10, 5 )
93 typedef SwUndoSaveSection* SwUndoSaveSectionPtr;
94 SV_DECL_PTRARR_DEL( SwUndoSaveSections, SwUndoSaveSectionPtr, 0, 10 )
96 typedef SwUndoMove* SwUndoMovePtr;
97 SV_DECL_PTRARR_DEL( SwUndoMoves, SwUndoMovePtr, 0, 10 )
99 struct SwTblToTxtSave;
100 typedef SwTblToTxtSave* SwTblToTxtSavePtr;
101 SV_DECL_PTRARR_DEL( SwTblToTxtSaves, SwTblToTxtSavePtr, 0, 10 )
103 struct _UndoTblCpyTbl_Entry
105 ULONG nBoxIdx, nOffset;
106 SfxItemSet* pBoxNumAttr;
107 SwUndo* pUndo;
109 // Was the last paragraph of the new and the first paragraph of the old content joined?
110 bool bJoin; // For redlining only
112 _UndoTblCpyTbl_Entry( const SwTableBox& rBox );
113 ~_UndoTblCpyTbl_Entry();
115 typedef _UndoTblCpyTbl_Entry* _UndoTblCpyTbl_EntryPtr;
116 SV_DECL_PTRARR_DEL( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr, 0, 10 )
118 class _SaveBox;
119 class _SaveLine;
121 class _SaveTable
123 friend class _SaveBox;
124 friend class _SaveLine;
125 SfxItemSet aTblSet;
126 _SaveLine* pLine;
127 const SwTable* pSwTable;
128 SfxItemSets aSets;
129 SwFrmFmts aFrmFmts;
130 USHORT nLineCount;
131 BOOL bModifyBox : 1;
132 BOOL bSaveFormula : 1;
133 BOOL bNewModel : 1;
135 public:
136 _SaveTable( const SwTable& rTbl, USHORT nLnCnt = USHRT_MAX,
137 BOOL bSaveFml = TRUE );
138 ~_SaveTable();
140 USHORT AddFmt( SwFrmFmt* pFmt, bool bIsLine );
141 void NewFrmFmt( const SwClient* pLnBx, BOOL bIsLine, USHORT nFmtPos,
142 SwFrmFmt* pOldFmt );
144 void RestoreAttr( SwTable& rTbl, BOOL bModifyBox = FALSE );
145 void SaveCntntAttrs( SwDoc* pDoc );
146 void CreateNew( SwTable& rTbl, BOOL bCreateFrms = TRUE,
147 BOOL bRestoreChart = TRUE );
148 BOOL IsNewModel() const { return bNewModel; }
151 class _SaveLine
153 friend class _SaveTable;
154 friend class _SaveBox;
156 _SaveLine* pNext;
157 _SaveBox* pBox;
158 USHORT nItemSet;
160 public:
162 _SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl );
163 ~_SaveLine();
165 void RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl );
166 void SaveCntntAttrs( SwDoc* pDoc );
168 void CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl );
171 class _SaveBox
173 friend class _SaveLine;
175 _SaveBox* pNext;
176 ULONG nSttNode;
177 long nRowSpan;
178 USHORT nItemSet;
179 union
181 SfxItemSets* pCntntAttrs;
182 _SaveLine* pLine;
183 } Ptrs;
185 public:
186 _SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl );
187 ~_SaveBox();
189 void RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl );
190 void SaveCntntAttrs( SwDoc* pDoc );
192 void CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl );
195 void InsertSort( SvUShorts& rArr, USHORT nIdx, USHORT* pInsPos = 0 );
196 void InsertSort( SvULongs& rArr, ULONG nIdx, USHORT* pInsPos = 0 );
198 #if defined( JP_DEBUG ) && !defined( PRODUCT )
199 #include "shellio.hxx"
200 void DumpDoc( SwDoc* pDoc, const String& rFileNm );
201 void CheckTable( const SwTable& );
202 #define DUMPDOC(p,s) DumpDoc( p, s);
203 #define CHECKTABLE(t) CheckTable( t );
204 #else
205 #define DUMPDOC(p,s)
206 #define CHECKTABLE(t)
207 #endif
209 /* #130880: Crash in undo of table to text when the table has (freshly) merged cells
210 The order of cell content nodes in the nodes array is not given by the recursive table structure.
211 The algorithmn must not rely on this even it holds for a fresh loaded table in odt file format.
212 So we need to remember not only the start node position but the end node position as well.
215 struct SwTblToTxtSave
217 ULONG m_nSttNd;
218 ULONG m_nEndNd;
219 xub_StrLen m_nCntnt;
220 SwHistory* m_pHstry;
221 // metadata references for first and last paragraph in cell
222 ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart;
223 ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd;
225 SwTblToTxtSave( SwDoc& rDoc, ULONG nNd, ULONG nEndIdx, xub_StrLen nCntnt );
226 ~SwTblToTxtSave() { delete m_pHstry; }
229 SV_IMPL_PTRARR( SfxItemSets, SfxItemSetPtr )
230 SV_IMPL_PTRARR( SwUndoSaveSections, SwUndoSaveSectionPtr )
231 SV_IMPL_PTRARR( SwUndoMoves, SwUndoMovePtr )
232 SV_IMPL_PTRARR( SwTblToTxtSaves, SwTblToTxtSavePtr )
233 SV_IMPL_PTRARR( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr )
235 USHORT __FAR_DATA aSave_BoxCntntSet[] = {
236 RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT,
237 RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
238 RES_CHRATR_POSTURE, RES_CHRATR_POSTURE,
239 RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT,
240 RES_PARATR_ADJUST, RES_PARATR_ADJUST,
241 0 };
245 SwUndoInsTbl::SwUndoInsTbl( const SwPosition& rPos, USHORT nCl, USHORT nRw,
246 USHORT nAdj, const SwInsertTableOptions& rInsTblOpts,
247 const SwTableAutoFmt* pTAFmt,
248 const SvUShorts* pColArr,
249 const String & rName)
250 : SwUndo( UNDO_INSTABLE ),
251 aInsTblOpts( rInsTblOpts ), pDDEFldType( 0 ), pColWidth( 0 ), pRedlData( 0 ), pAutoFmt( 0 ),
252 nSttNode( rPos.nNode.GetIndex() ), nRows( nRw ), nCols( nCl ), nAdjust( nAdj )
254 if( pColArr )
256 pColWidth = new SvUShorts( 0, 1 );
257 pColWidth->Insert( pColArr, 0 );
259 if( pTAFmt )
260 pAutoFmt = new SwTableAutoFmt( *pTAFmt );
262 // Redline beachten
263 SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc();
264 if( rDoc.IsRedlineOn() )
266 pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() );
267 SetRedlineMode( rDoc.GetRedlineMode() );
270 sTblNm = rName;
274 SwUndoInsTbl::~SwUndoInsTbl()
276 delete pDDEFldType;
277 delete pColWidth;
278 delete pRedlData;
279 delete pAutoFmt;
282 void SwUndoInsTbl::Undo( SwUndoIter& rUndoIter )
284 SwDoc& rDoc = rUndoIter.GetDoc();
285 SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
287 SwTableNode* pTblNd = aIdx.GetNode().GetTableNode();
288 ASSERT( pTblNd, "kein TabellenNode" );
289 pTblNd->DelFrms();
291 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
292 rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX );
293 RemoveIdxFromSection( rDoc, nSttNode );
295 // harte SeitenUmbrueche am nachfolgenden Node verschieben
296 SwCntntNode* pNextNd = rDoc.GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
297 if( pNextNd )
299 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
300 const SfxPoolItem *pItem;
302 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
303 FALSE, &pItem ) )
304 pNextNd->SetAttr( *pItem );
306 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
307 FALSE, &pItem ) )
308 pNextNd->SetAttr( *pItem );
312 sTblNm = pTblNd->GetTable().GetFrmFmt()->GetName();
313 if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
314 pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
315 GetDDEFldType()->Copy();
317 rDoc.GetNodes().Delete( aIdx, pTblNd->EndOfSectionIndex() -
318 aIdx.GetIndex() + 1 );
320 rUndoIter.pAktPam->DeleteMark();
321 rUndoIter.pAktPam->GetPoint()->nNode = aIdx;
322 rUndoIter.pAktPam->GetPoint()->nContent.Assign(
323 rUndoIter.pAktPam->GetCntntNode(), 0 );
327 void SwUndoInsTbl::Redo( SwUndoIter& rUndoIter )
329 SwDoc& rDoc = rUndoIter.GetDoc();
331 SwPosition aPos( *rUndoIter.pAktPam->GetPoint() );
332 aPos.nNode = nSttNode;
333 const SwTable* pTbl = rDoc.InsertTable( aInsTblOpts, aPos, nRows, nCols,
334 nAdjust,
335 pAutoFmt, pColWidth );
336 ((SwFrmFmt*)pTbl->GetFrmFmt())->SetName( sTblNm );
337 SwTableNode* pTblNode = (SwTableNode*)rDoc.GetNodes()[nSttNode]->GetTableNode();
339 if( pDDEFldType )
341 SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
342 *pDDEFldType);
343 SwDDETable* pDDETbl = new SwDDETable( pTblNode->GetTable(), pNewType );
344 pTblNode->SetNewTable( pDDETbl ); // setze die DDE-Tabelle
345 delete pDDEFldType, pDDEFldType = 0;
348 if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) ||
349 ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
350 rDoc.GetRedlineTbl().Count() ))
352 SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 );
353 SwCntntNode* pCNd = aPam.GetCntntNode( FALSE );
354 if( pCNd )
355 aPam.GetMark()->nContent.Assign( pCNd, 0 );
357 if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
359 RedlineMode_t eOld = rDoc.GetRedlineMode();
360 rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE));
362 rDoc.AppendRedline( new SwRedline( *pRedlData, aPam ), true);
363 rDoc.SetRedlineMode_intern( eOld );
365 else
366 rDoc.SplitRedline( aPam );
371 void SwUndoInsTbl::Repeat( SwUndoIter& rUndoIter )
373 rUndoIter.GetDoc().InsertTable( aInsTblOpts, *rUndoIter.pAktPam->GetPoint(),
374 nRows, nCols, nAdjust,
375 pAutoFmt, pColWidth );
378 SwRewriter SwUndoInsTbl::GetRewriter() const
380 SwRewriter aRewriter;
382 aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE));
383 aRewriter.AddRule(UNDO_ARG2, sTblNm);
384 aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE));
386 return aRewriter;
389 // -----------------------------------------------------
391 SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, ULONG nNd, ULONG nEndIdx, xub_StrLen nCnt )
392 : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 )
394 // Attributierung des gejointen Node merken.
395 SwTxtNode* pNd = rDoc.GetNodes()[ nNd ]->GetTxtNode();
396 if( pNd )
398 m_pHstry = new SwHistory;
400 m_pHstry->Add( pNd->GetTxtColl(), nNd, ND_TEXTNODE );
401 if ( pNd->GetpSwpHints() )
403 m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0,
404 pNd->GetTxt().Len(), false );
406 if( pNd->HasSwAttrSet() )
407 m_pHstry->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNd );
409 if( !m_pHstry->Count() )
410 delete m_pHstry, m_pHstry = 0;
412 // METADATA: store
413 m_pMetadataUndoStart = pNd->CreateUndo();
416 // we also need to store the metadata reference of the _last_ paragraph
417 // we subtract 1 to account for the removed cell start/end node pair
418 // (after SectionUp, the end of the range points to the node after the cell)
419 if ( nEndIdx - 1 > nNd )
421 SwTxtNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTxtNode() );
422 if( pLastNode )
424 // METADATA: store
425 m_pMetadataUndoEnd = pLastNode->CreateUndo();
430 SwUndoTblToTxt::SwUndoTblToTxt( const SwTable& rTbl, sal_Unicode cCh )
431 : SwUndo( UNDO_TABLETOTEXT ),
432 sTblNm( rTbl.GetFrmFmt()->GetName() ), pDDEFldType( 0 ), pHistory( 0 ),
433 nSttNd( 0 ), nEndNd( 0 ),
434 nAdjust( static_cast<USHORT>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ),
435 cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() )
437 pTblSave = new _SaveTable( rTbl );
438 pBoxSaves = new SwTblToTxtSaves( (BYTE)rTbl.GetTabSortBoxes().Count() );
440 if( rTbl.IsA( TYPE( SwDDETable ) ) )
441 pDDEFldType = (SwDDEFieldType*)((SwDDETable&)rTbl).GetDDEFldType()->Copy();
443 bCheckNumFmt = rTbl.GetFrmFmt()->GetDoc()->IsInsTblFormatNum();
445 pHistory = new SwHistory;
446 const SwTableNode* pTblNd = rTbl.GetTableNode();
447 ULONG nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex();
449 const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts();
450 for( USHORT n = 0; n < rFrmFmtTbl.Count(); ++n )
452 const SwPosition* pAPos;
453 SwFrmFmt* pFmt = rFrmFmtTbl[ n ];
454 const SwFmtAnchor* pAnchor = &pFmt->GetAnchor();
455 if( 0 != ( pAPos = pAnchor->GetCntntAnchor()) &&
456 ( FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ||
457 FLY_AT_CNTNT == pAnchor->GetAnchorId() ) &&
458 nTblStt <= pAPos->nNode.GetIndex() &&
459 pAPos->nNode.GetIndex() < nTblEnd )
461 pHistory->Add( *pFmt );
465 if( !pHistory->Count() )
466 delete pHistory, pHistory = 0;
470 SwUndoTblToTxt::~SwUndoTblToTxt()
472 delete pDDEFldType;
473 delete pTblSave;
474 delete pBoxSaves;
475 delete pHistory;
480 void SwUndoTblToTxt::Undo( SwUndoIter& rUndoIter )
482 SwDoc& rDoc = rUndoIter.GetDoc();
483 SwPaM* pPam = rUndoIter.pAktPam;
485 SwNodeIndex aFrmIdx( rDoc.GetNodes(), nSttNd );
486 SwNodeIndex aEndIdx( rDoc.GetNodes(), nEndNd );
488 pPam->GetPoint()->nNode = aFrmIdx;
489 pPam->SetMark();
490 pPam->GetPoint()->nNode = aEndIdx;
491 rDoc.DelNumRules( *pPam );
492 pPam->DeleteMark();
494 // dann sammel mal alle Uppers ein
495 SwNode2Layout aNode2Layout( aFrmIdx.GetNode() );
497 // erzeuge die TabelleNode Structur
498 SwTableNode* pTblNd = rDoc.GetNodes().UndoTableToText( nSttNd, nEndNd, *pBoxSaves );
499 pTblNd->GetTable().SetTableModel( pTblSave->IsNewModel() );
500 SwTableFmt* pTableFmt = rDoc.MakeTblFrmFmt( sTblNm, rDoc.GetDfltFrmFmt() );
501 pTableFmt->Add( &pTblNd->GetTable() ); // das Frame-Format setzen
502 pTblNd->GetTable().SetRowsToRepeat( nHdlnRpt );
504 // erzeuge die alte Tabellen Struktur
505 pTblSave->CreateNew( pTblNd->GetTable() );
507 if( pDDEFldType )
509 SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
510 *pDDEFldType);
511 SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType );
512 pTblNd->SetNewTable( pDDETbl, FALSE ); // setze die DDE-Tabelle
513 delete pDDEFldType, pDDEFldType = 0;
516 if( bCheckNumFmt )
518 SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes();
519 for( USHORT nBoxes = rBxs.Count(); nBoxes; )
520 rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], FALSE );
523 if( pHistory )
525 USHORT nTmpEnd = pHistory->GetTmpEnd();
526 pHistory->TmpRollback( &rDoc, 0 );
527 pHistory->SetTmpEnd( nTmpEnd );
530 aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(),
531 pTblNd->GetIndex(), pTblNd->GetIndex()+1 );
533 // will man eine TabellenSelektion ??
534 pPam->DeleteMark();
535 pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
536 pPam->SetMark();
537 pPam->GetPoint()->nNode = *pPam->GetNode()->StartOfSectionNode();
538 pPam->Move( fnMoveForward, fnGoCntnt );
539 pPam->Exchange();
540 pPam->Move( fnMoveBackward, fnGoCntnt );
542 ClearFEShellTabCols();
545 // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
546 SwTableNode* SwNodes::UndoTableToText( ULONG nSttNd, ULONG nEndNd,
547 const SwTblToTxtSaves& rSavedData )
549 SwNodeIndex aSttIdx( *this, nSttNd );
550 SwNodeIndex aEndIdx( *this, nEndNd+1 );
552 SwTableNode * pTblNd = new SwTableNode( aSttIdx );
553 SwEndNode* pEndNd = new SwEndNode( aEndIdx, *pTblNd );
555 aEndIdx = *pEndNd;
557 /* Set pTblNd as start of section for all nodes in [nSttNd, nEndNd].
558 Delete all Frames attached to the nodes in that range. */
559 SwNode* pNd;
561 ULONG n, nTmpEnd = aEndIdx.GetIndex();
562 for( n = pTblNd->GetIndex() + 1; n < nTmpEnd; ++n )
564 if( ( pNd = (*this)[ n ] )->IsCntntNode() )
565 ((SwCntntNode*)pNd)->DelFrms();
566 pNd->pStartOfSection = pTblNd;
570 // dann die Tabellen Struktur teilweise aufbauen. Erstmal eine Line
571 // in der alle Boxen stehen! Die korrekte Struktur kommt dann aus der
572 // SaveStruct
573 SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt();
574 SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt();
575 SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.Count(), 0 );
576 pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pLine, 0 );
578 SvULongs aBkmkArr( 0, 4 );
579 for( USHORT n = rSavedData.Count(); n; )
581 SwTblToTxtSave* pSave = rSavedData[ --n ];
582 // if the start node was merged with last from prev. cell,
583 // subtract 1 from index to get the merged paragraph, and split that
584 aSttIdx = pSave->m_nSttNd - ( ( USHRT_MAX != pSave->m_nCntnt ) ? 1 : 0);
585 SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
587 if( USHRT_MAX != pSave->m_nCntnt )
589 // an der ContentPosition splitten, das vorherige Zeichen
590 // loeschen (ist der Trenner!)
591 ASSERT( pTxtNd, "Wo ist der TextNode geblieben?" );
592 SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 );
594 pTxtNd->Erase( aCntPos, 1 );
595 SwCntntNode* pNewNd = pTxtNd->SplitCntntNode(
596 SwPosition( aSttIdx, aCntPos ));
597 if( aBkmkArr.Count() )
598 _RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt,
599 pSave->m_nCntnt + 1 );
601 else
603 if( aBkmkArr.Count() )
604 aBkmkArr.Remove( 0, aBkmkArr.Count() );
605 if( pTxtNd )
606 _SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(),
607 pTxtNd->GetTxt().Len(), aBkmkArr );
610 if( pTxtNd )
612 // METADATA: restore
613 pTxtNd->GetTxtNode()->RestoreMetadata(pSave->m_pMetadataUndoStart);
614 if( pTxtNd->HasSwAttrSet() )
615 pTxtNd->ResetAllAttr();
617 if( pTxtNd->GetpSwpHints() )
618 pTxtNd->ClearSwpHintsArr( false );
621 if( pSave->m_pHstry )
623 USHORT nTmpEnd = pSave->m_pHstry->GetTmpEnd();
624 pSave->m_pHstry->TmpRollback( GetDoc(), 0 );
625 pSave->m_pHstry->SetTmpEnd( nTmpEnd );
628 // METADATA: restore
629 // end points to node after cell
630 if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd )
632 SwTxtNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTxtNode();
633 if (pLastNode)
635 pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd);
639 aEndIdx = pSave->m_nEndNd;
640 SwStartNode* pSttNd = new SwStartNode( aSttIdx, ND_STARTNODE,
641 SwTableBoxStartNode );
642 pSttNd->pStartOfSection = pTblNd;
643 new SwEndNode( aEndIdx, *pSttNd );
645 for( ULONG i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i )
647 pNd = (*this)[ i ];
648 pNd->pStartOfSection = pSttNd;
649 if( pNd->IsStartNode() )
650 i = pNd->EndOfSectionIndex();
653 SwTableBox* pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
654 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, 0 );
656 return pTblNd;
660 void SwUndoTblToTxt::Redo( SwUndoIter& rUndoIter )
662 SwDoc& rDoc = rUndoIter.GetDoc();
663 SwPaM* pPam = rUndoIter.pAktPam;
666 pPam->GetPoint()->nNode = nSttNd;
667 pPam->GetPoint()->nContent.Assign( 0, 0 );
668 SwNodeIndex aSaveIdx( pPam->GetPoint()->nNode, -1 );
670 pPam->SetMark(); // alle Indizies abmelden
671 pPam->DeleteMark();
673 SwTableNode* pTblNd = pPam->GetNode()->GetTableNode();
674 ASSERT( pTblNd, "keinen TableNode gefunden" );
676 if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
677 pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
678 GetDDEFldType()->Copy();
680 rDoc.TableToText( pTblNd, cTrenner );
682 aSaveIdx++;
683 SwCntntNode* pCNd = aSaveIdx.GetNode().GetCntntNode();
684 if( !pCNd && 0 == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) &&
685 0 == ( pCNd = rDoc.GetNodes().GoPrevious( &aSaveIdx )) )
687 ASSERT( FALSE, "wo steht denn nun der TextNode" );
690 pPam->GetPoint()->nNode = aSaveIdx;
691 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
693 pPam->SetMark(); // alle Indizies abmelden
694 pPam->DeleteMark();
698 void SwUndoTblToTxt::Repeat( SwUndoIter& rUndoIter )
700 SwTableNode* pTblNd = rUndoIter.pAktPam->GetNode()->FindTableNode();
701 if( pTblNd )
703 // bewege den Cursor aus der Tabelle
704 SwPaM* pPam = rUndoIter.pAktPam;
705 pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
706 pPam->Move( fnMoveForward, fnGoCntnt );
707 pPam->SetMark();
708 pPam->DeleteMark();
710 rUndoIter.GetDoc().TableToText( pTblNd, cTrenner );
714 void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg )
716 nSttNd = rRg.aStart.GetIndex();
717 nEndNd = rRg.aEnd.GetIndex();
720 void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, ULONG nNdIdx, ULONG nEndIdx, xub_StrLen nCntntIdx )
722 SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx );
723 pBoxSaves->Insert( pNew, pBoxSaves->Count() );
726 // -----------------------------------------------------
728 SwUndoTxtToTbl::SwUndoTxtToTbl( const SwPaM& rRg,
729 const SwInsertTableOptions& rInsTblOpts,
730 sal_Unicode cCh, USHORT nAdj,
731 const SwTableAutoFmt* pAFmt )
732 : SwUndo( UNDO_TEXTTOTABLE ), SwUndRng( rRg ), aInsTblOpts( rInsTblOpts ),
733 pDelBoxes( 0 ), pAutoFmt( 0 ),
734 pHistory( 0 ), cTrenner( cCh ), nAdjust( nAdj )
736 if( pAFmt )
737 pAutoFmt = new SwTableAutoFmt( *pAFmt );
739 const SwPosition* pEnd = rRg.End();
740 SwNodes& rNds = rRg.GetDoc()->GetNodes();
741 bSplitEnd = pEnd->nContent.GetIndex() && ( pEnd->nContent.GetIndex()
742 != pEnd->nNode.GetNode().GetCntntNode()->Len() ||
743 pEnd->nNode.GetIndex() >= rNds.GetEndOfContent().GetIndex()-1 );
746 SwUndoTxtToTbl::~SwUndoTxtToTbl()
748 delete pDelBoxes;
749 delete pAutoFmt;
752 void SwUndoTxtToTbl::Undo( SwUndoIter& rUndoIter )
754 SwDoc& rDoc = rUndoIter.GetDoc();
756 ULONG nTblNd = nSttNode;
757 if( nSttCntnt )
758 ++nTblNd; // Node wurde vorher gesplittet
759 SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd );
760 SwTableNode* pTNd = rDoc.GetNodes()[ aIdx ]->GetTableNode();
761 ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
763 RemoveIdxFromSection( rDoc, nTblNd );
765 sTblNm = pTNd->GetTable().GetFrmFmt()->GetName();
767 if( pHistory )
769 pHistory->TmpRollback( &rDoc, 0 );
770 pHistory->SetTmpEnd( pHistory->Count() );
773 if( pDelBoxes )
775 SwTable& rTbl = pTNd->GetTable();
776 for( USHORT n = pDelBoxes->Count(); n; )
778 SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] );
779 if( pBox )
780 ::_DeleteBox( rTbl, pBox, 0, FALSE, FALSE );
781 else {
782 ASSERT( !this, "Wo ist die Box geblieben?" );
787 SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() );
788 rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner );
790 // am Start wieder zusammenfuegen ?
791 SwPosition* pPos = rUndoIter.pAktPam->GetPoint();
792 if( nSttCntnt )
794 pPos->nNode = nTblNd;
795 pPos->nContent.Assign( rDoc.GetNodes()[ pPos->nNode ]->GetCntntNode(), 0 );
796 if( rUndoIter.pAktPam->Move( fnMoveBackward, fnGoCntnt))
798 SwNodeIndex& rIdx = rUndoIter.pAktPam->GetPoint()->nNode;
800 // dann die Crsr/etc. nochmal relativ verschieben
801 RemoveIdxRel( rIdx.GetIndex()+1, *pPos );
803 rIdx.GetNode().GetCntntNode()->JoinNext();
807 // am Ende wieder zusammenfuegen ?
808 if( bSplitEnd )
810 SwNodeIndex& rIdx = pPos->nNode;
811 rIdx = nEndNode;
812 SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode();
813 if( pTxtNd && pTxtNd->CanJoinNext() )
815 rUndoIter.pAktPam->GetMark()->nContent.Assign( 0, 0 );
816 rUndoIter.pAktPam->GetPoint()->nContent.Assign( 0, 0 );
818 // dann die Crsr/etc. nochmal relativ verschieben
819 pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
820 RemoveIdxRel( nEndNode + 1, *pPos );
822 pTxtNd->JoinNext();
826 SetPaM( rUndoIter ); // manipulierten Bereich selectieren
830 void SwUndoTxtToTbl::Redo( SwUndoIter& rUndoIter )
832 SetPaM( rUndoIter );
833 RemoveIdxFromRange( *rUndoIter.pAktPam, FALSE );
834 SetPaM( rUndoIter );
836 const SwTable* pTable = rUndoIter.GetDoc().TextToTable(
837 aInsTblOpts, *rUndoIter.pAktPam, cTrenner,
838 nAdjust, pAutoFmt );
839 ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm );
843 void SwUndoTxtToTbl::Repeat( SwUndoIter& rUndoIter )
845 // keine TABLE IN TABLE
846 if( !rUndoIter.pAktPam->GetNode()->FindTableNode() )
847 rUndoIter.GetDoc().TextToTable( aInsTblOpts, *rUndoIter.pAktPam,
848 cTrenner, nAdjust,
849 pAutoFmt );
852 void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox )
854 if( !pDelBoxes )
855 pDelBoxes = new SvULongs;
856 pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() );
859 SwHistory& SwUndoTxtToTbl::GetHistory()
861 if( !pHistory )
862 pHistory = new SwHistory;
863 return *pHistory;
866 // -----------------------------------------------------
868 SwUndoTblHeadline::SwUndoTblHeadline( const SwTable& rTbl, USHORT nOldHdl,
869 USHORT nNewHdl )
870 : SwUndo( UNDO_TABLEHEADLINE ),
871 nOldHeadline( nOldHdl ),
872 nNewHeadline( nNewHdl )
874 ASSERT( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" );
875 const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd();
876 ASSERT( pSttNd, "Box ohne Inhalt" );
878 nTblNd = pSttNd->StartOfSectionIndex();
882 void SwUndoTblHeadline::Undo( SwUndoIter& rUndoIter )
884 SwDoc& rDoc = rUndoIter.GetDoc();
885 SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
886 ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
888 rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline );
892 void SwUndoTblHeadline::Redo( SwUndoIter& rUndoIter )
894 SwDoc& rDoc = rUndoIter.GetDoc();
896 SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
897 ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
899 rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline );
903 void SwUndoTblHeadline::Repeat( SwUndoIter& rUndoIter )
905 SwTableNode* pTblNd = rUndoIter.pAktPam->GetNode()->FindTableNode();
906 if( pTblNd )
907 rUndoIter.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline );
911 /* \f */
915 _SaveTable::_SaveTable( const SwTable& rTbl, USHORT nLnCnt, BOOL bSaveFml )
916 : aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ),
917 pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml )
919 bModifyBox = FALSE;
920 bNewModel = rTbl.IsNewModel();
921 aTblSet.Put( rTbl.GetFrmFmt()->GetAttrSet() );
922 pLine = new _SaveLine( 0, *rTbl.GetTabLines()[ 0 ], *this );
924 _SaveLine* pLn = pLine;
925 if( USHRT_MAX == nLnCnt )
926 nLnCnt = rTbl.GetTabLines().Count();
927 for( USHORT n = 1; n < nLnCnt; ++n )
928 pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this );
930 aFrmFmts.Remove( 0, aFrmFmts.Count() );
931 pSwTable = 0;
935 _SaveTable::~_SaveTable()
937 delete pLine;
941 USHORT _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine )
943 USHORT nRet = aFrmFmts.GetPos( pFmt );
944 if( USHRT_MAX == nRet )
946 // Kopie vom ItemSet anlegen
947 SfxItemSet* pSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
948 bIsLine ? aTableLineSetRange : aTableBoxSetRange );
949 pSet->Put( pFmt->GetAttrSet() );
950 //JP 20.04.98: Bug 49502 - wenn eine Formel gesetzt ist, nie den
951 // Value mit sichern. Der muss gegebenfalls neu
952 // errechnet werden!
953 //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern
954 const SfxPoolItem* pItem;
955 if( SFX_ITEM_SET == pSet->GetItemState( RES_BOXATR_FORMULA, TRUE, &pItem ))
957 pSet->ClearItem( RES_BOXATR_VALUE );
958 if( pSwTable && bSaveFormula )
960 SwTableFmlUpdate aMsgHnt( pSwTable );
961 aMsgHnt.eFlags = TBL_BOXNAME;
962 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( pFmt );
963 ((SwTblBoxFormula*)pItem)->ChangeState( &aMsgHnt );
964 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( 0 );
967 aSets.Insert( pSet, (nRet = aSets.Count() ) );
968 aFrmFmts.Insert( pFmt, nRet );
970 return nRet;
974 void _SaveTable::RestoreAttr( SwTable& rTbl, BOOL bMdfyBox )
976 USHORT n;
978 bModifyBox = bMdfyBox;
980 // zuerst die Attribute des TabellenFrmFormates zurueck holen
981 SwFrmFmt* pFmt = rTbl.GetFrmFmt();
982 SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet();
983 rFmtSet.ClearItem();
984 rFmtSet.Put( aTblSet );
986 if( pFmt->IsInCache() )
988 SwFrm::GetCache().Delete( pFmt );
989 pFmt->SetInCache( FALSE );
992 // zur Sicherheit alle Tableframes invalidieren
993 SwClientIter aIter( *pFmt );
994 for( SwClient* pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
995 if( ((SwTabFrm*)pLast)->GetTable() == &rTbl )
997 ((SwTabFrm*)pLast)->InvalidateAll();
998 ((SwTabFrm*)pLast)->SetCompletePaint();
1001 // FrmFmts mit Defaults (0) fuellen
1002 pFmt = 0;
1003 for( n = aSets.Count(); n; --n )
1004 aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1006 USHORT nLnCnt = nLineCount;
1007 if( USHRT_MAX == nLnCnt )
1008 nLnCnt = rTbl.GetTabLines().Count();
1010 _SaveLine* pLn = pLine;
1011 for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext )
1013 if( !pLn )
1015 ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1016 break;
1019 pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this );
1022 aFrmFmts.Remove( 0, aFrmFmts.Count() );
1023 bModifyBox = FALSE;
1027 void _SaveTable::SaveCntntAttrs( SwDoc* pDoc )
1029 pLine->SaveCntntAttrs( pDoc );
1033 void _SaveTable::CreateNew( SwTable& rTbl, BOOL bCreateFrms,
1034 BOOL bRestoreChart )
1036 USHORT n;
1038 _FndBox aTmpBox( 0, 0 );
1039 //if( bRestoreChart )
1040 // // ? TL_CHART2: notification or locking of controller required ?
1041 aTmpBox.DelFrms( rTbl );
1043 // zuerst die Attribute des TabellenFrmFormates zurueck holen
1044 SwFrmFmt* pFmt = rTbl.GetFrmFmt();
1045 SfxItemSet& rFmtSet = (SfxItemSet&)pFmt->GetAttrSet();
1046 rFmtSet.ClearItem();
1047 rFmtSet.Put( aTblSet );
1049 if( pFmt->IsInCache() )
1051 SwFrm::GetCache().Delete( pFmt );
1052 pFmt->SetInCache( FALSE );
1055 // SwTableBox muss ein Format haben!!
1056 SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().Count(), 0 );
1058 // FrmFmts mit Defaults (0) fuellen
1059 pFmt = 0;
1060 for( n = aSets.Count(); n; --n )
1061 aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1063 pLine->CreateNew( rTbl, aParent, *this );
1064 aFrmFmts.Remove( 0, aFrmFmts.Count() );
1066 // die neuen Lines eintragen, die alten loeschen
1067 USHORT nOldLines = nLineCount;
1068 if( USHRT_MAX == nLineCount )
1069 nOldLines = rTbl.GetTabLines().Count();
1071 SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc();
1072 SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
1073 for( n = 0; n < aParent.GetTabLines().Count(); ++n )
1075 SwTableLine* pLn = aParent.GetTabLines()[ n ];
1076 pLn->SetUpper( 0 );
1077 if( n < nOldLines )
1079 SwTableLine* pOld = rTbl.GetTabLines()[ n ];
1081 // TL_CHART2: notify chart about boxes to be removed
1082 const SwTableBoxes &rBoxes = pOld->GetTabBoxes();
1083 USHORT nBoxes = rBoxes.Count();
1084 for (USHORT k = 0; k < nBoxes; ++k)
1086 SwTableBox *pBox = rBoxes[k];
1087 if (pPCD)
1088 pPCD->DeleteBox( &rTbl, *pBox );
1091 rTbl.GetTabLines().C40_REPLACE( SwTableLine, pLn, n );
1092 delete pOld;
1094 else
1095 rTbl.GetTabLines().C40_INSERT( SwTableLine, pLn, n );
1098 if( n < nOldLines )
1100 // remove remaining lines...
1102 for (USHORT k1 = 0; k1 < nOldLines - n; ++k1)
1104 const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes();
1105 USHORT nBoxes = rBoxes.Count();
1106 for (USHORT k2 = 0; k2 < nBoxes; ++k2)
1108 SwTableBox *pBox = rBoxes[k2];
1109 // TL_CHART2: notify chart about boxes to be removed
1110 if (pPCD)
1111 pPCD->DeleteBox( &rTbl, *pBox );
1115 rTbl.GetTabLines().DeleteAndDestroy( n, nOldLines - n );
1118 aParent.GetTabLines().Remove( 0, n );
1120 if( bCreateFrms )
1121 aTmpBox.MakeFrms( rTbl );
1122 if( bRestoreChart )
1124 // TL_CHART2: need to inform chart of probably changed cell names
1125 pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
1130 void _SaveTable::NewFrmFmt( const SwClient* pLnBx, BOOL bIsLine,
1131 USHORT nFmtPos, SwFrmFmt* pOldFmt )
1133 SwDoc* pDoc = pOldFmt->GetDoc();
1135 SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ];
1136 if( !pFmt )
1138 if( bIsLine )
1139 pFmt = pDoc->MakeTableLineFmt();
1140 else
1141 pFmt = pDoc->MakeTableBoxFmt();
1142 pFmt->SetFmtAttr( *aSets[ nFmtPos ] );
1143 aFrmFmts.Replace( pFmt, nFmtPos );
1146 //Erstmal die Frms ummelden.
1147 SwClientIter aIter( *pOldFmt );
1148 for( SwClient* pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
1150 if( bIsLine ? pLnBx == ((SwRowFrm*)pLast)->GetTabLine()
1151 : pLnBx == ((SwCellFrm*)pLast)->GetTabBox() )
1153 pFmt->Add( pLast );
1154 ((SwFrm*)pLast)->InvalidateAll();
1155 ((SwFrm*)pLast)->ReinitializeFrmSizeAttrFlags();
1156 if ( !bIsLine )
1158 ((SwCellFrm*)pLast)->SetDerivedVert( FALSE );
1159 ((SwCellFrm*)pLast)->CheckDirChange();
1164 //Jetzt noch mich selbst ummelden.
1165 pFmt->Add( (SwClient*)pLnBx );
1167 if( bModifyBox && !bIsLine )
1169 const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ),
1170 & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT );
1171 if( rOld != rNew )
1172 pFmt->Modify( (SfxPoolItem*)&rOld, (SfxPoolItem*)&rNew );
1175 if( !pOldFmt->GetDepends() )
1176 delete pOldFmt;
1181 _SaveLine::_SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl )
1182 : pNext( 0 )
1184 if( pPrev )
1185 pPrev->pNext = this;
1187 nItemSet = rSTbl.AddFmt( rLine.GetFrmFmt(), true );
1189 pBox = new _SaveBox( 0, *rLine.GetTabBoxes()[ 0 ], rSTbl );
1190 _SaveBox* pBx = pBox;
1191 for( USHORT n = 1; n < rLine.GetTabBoxes().Count(); ++n )
1192 pBx = new _SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTbl );
1196 _SaveLine::~_SaveLine()
1198 delete pBox;
1199 delete pNext;
1203 void _SaveLine::RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl )
1205 rSTbl.NewFrmFmt( &rLine, TRUE, nItemSet, rLine.GetFrmFmt() );
1207 _SaveBox* pBx = pBox;
1208 for( USHORT n = 0; n < rLine.GetTabBoxes().Count(); ++n, pBx = pBx->pNext )
1210 if( !pBx )
1212 ASSERT( !this, "Anzahl der Boxen hat sich veraendert" );
1213 break;
1215 pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl );
1220 void _SaveLine::SaveCntntAttrs( SwDoc* pDoc )
1222 pBox->SaveCntntAttrs( pDoc );
1223 if( pNext )
1224 pNext->SaveCntntAttrs( pDoc );
1228 void _SaveLine::CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl )
1230 SwTableLineFmt* pFmt = (SwTableLineFmt*)rSTbl.aFrmFmts[ nItemSet ];
1231 if( !pFmt )
1233 SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1234 pFmt = pDoc->MakeTableLineFmt();
1235 pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1236 rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1238 SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent );
1240 rParent.GetTabLines().C40_INSERT( SwTableLine, pNew, rParent.GetTabLines().Count() );
1242 // HB, #127868# robustness: in some cases - which I
1243 // cannot reproduce nor see from the code - pNew seems
1244 // to be set to NULL in C40_INSERT.
1245 ASSERT(pNew, "Table line just created set to NULL in C40_INSERT");
1247 if (pNew)
1249 pBox->CreateNew( rTbl, *pNew, rSTbl );
1252 if( pNext )
1253 pNext->CreateNew( rTbl, rParent, rSTbl );
1257 _SaveBox::_SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl )
1258 : pNext( 0 ), nSttNode( ULONG_MAX ), nRowSpan(0)
1260 Ptrs.pLine = 0;
1262 if( pPrev )
1263 pPrev->pNext = this;
1265 nItemSet = rSTbl.AddFmt( rBox.GetFrmFmt(), false );
1267 if( rBox.GetSttNd() )
1269 nSttNode = rBox.GetSttIdx();
1270 nRowSpan = rBox.getRowSpan();
1272 else
1274 Ptrs.pLine = new _SaveLine( 0, *rBox.GetTabLines()[ 0 ], rSTbl );
1276 _SaveLine* pLn = Ptrs.pLine;
1277 for( USHORT n = 1; n < rBox.GetTabLines().Count(); ++n )
1278 pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl );
1283 _SaveBox::~_SaveBox()
1285 if( ULONG_MAX == nSttNode ) // keine EndBox
1286 delete Ptrs.pLine;
1287 else
1288 delete Ptrs.pCntntAttrs;
1289 delete pNext;
1293 void _SaveBox::RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl )
1295 rSTbl.NewFrmFmt( &rBox, FALSE, nItemSet, rBox.GetFrmFmt() );
1297 if( ULONG_MAX == nSttNode ) // keine EndBox
1299 if( !rBox.GetTabLines().Count() )
1301 ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1303 else
1305 _SaveLine* pLn = Ptrs.pLine;
1306 for( USHORT n = 0; n < rBox.GetTabLines().Count(); ++n, pLn = pLn->pNext )
1308 if( !pLn )
1310 ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1311 break;
1314 pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTbl );
1318 else if( rBox.GetSttNd() && rBox.GetSttIdx() == nSttNode )
1320 if( Ptrs.pCntntAttrs )
1322 SwNodes& rNds = rBox.GetFrmFmt()->GetDoc()->GetNodes();
1323 USHORT nSet = 0;
1324 ULONG nEnd = rBox.GetSttNd()->EndOfSectionIndex();
1325 for( ULONG n = nSttNode + 1; n < nEnd; ++n )
1327 SwCntntNode* pCNd = rNds[ n ]->GetCntntNode();
1328 if( pCNd )
1330 SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ];
1331 if( pSet )
1333 USHORT *pRstAttr = aSave_BoxCntntSet;
1334 while( *pRstAttr )
1336 pCNd->ResetAttr( *pRstAttr, *(pRstAttr+1) );
1337 pRstAttr += 2;
1339 pCNd->SetAttr( *pSet );
1341 else
1342 pCNd->ResetAllAttr();
1347 else
1349 ASSERT( !this, "Box nicht mehr am gleichen Node" );
1354 void _SaveBox::SaveCntntAttrs( SwDoc* pDoc )
1356 if( ULONG_MAX == nSttNode ) // keine EndBox
1358 // weiter in der Line
1359 Ptrs.pLine->SaveCntntAttrs( pDoc );
1361 else
1363 ULONG nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex();
1364 Ptrs.pCntntAttrs = new SfxItemSets( (BYTE)(nEnd - nSttNode - 1 ), 5 );
1365 for( ULONG n = nSttNode + 1; n < nEnd; ++n )
1367 SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode();
1368 if( pCNd )
1370 SfxItemSet* pSet = 0;
1371 if( pCNd->HasSwAttrSet() )
1373 pSet = new SfxItemSet( pDoc->GetAttrPool(),
1374 aSave_BoxCntntSet );
1375 pSet->Put( *pCNd->GetpSwAttrSet() );
1378 Ptrs.pCntntAttrs->Insert( pSet, Ptrs.pCntntAttrs->Count() );
1382 if( pNext )
1383 pNext->SaveCntntAttrs( pDoc );
1387 void _SaveBox::CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl )
1389 SwTableBoxFmt* pFmt = (SwTableBoxFmt*)rSTbl.aFrmFmts[ nItemSet ];
1390 if( !pFmt )
1392 SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1393 pFmt = pDoc->MakeTableBoxFmt();
1394 pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1395 rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1398 if( ULONG_MAX == nSttNode ) // keine EndBox
1400 SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent );
1401 rParent.GetTabBoxes().C40_INSERT( SwTableBox, pNew, rParent.GetTabBoxes().Count() );
1403 Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl );
1405 else
1407 // Box zum StartNode in der alten Tabelle suchen
1408 SwTableBox* pBox = rTbl.GetTblBox( nSttNode );
1409 ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1411 SwFrmFmt* pOld = pBox->GetFrmFmt();
1412 pFmt->Add( pBox );
1413 if( !pOld->GetDepends() )
1414 delete pOld;
1416 pBox->setRowSpan( nRowSpan );
1418 SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
1419 pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
1421 pBox->SetUpper( &rParent );
1422 pTBoxes = &rParent.GetTabBoxes();
1423 pTBoxes->C40_INSERT( SwTableBox, pBox, pTBoxes->Count() );
1426 if( pNext )
1427 pNext->CreateNew( rTbl, rParent, rSTbl );
1431 /* \f */
1433 // UndoObject fuer Attribut Aenderung an der Tabelle
1436 SwUndoAttrTbl::SwUndoAttrTbl( const SwTableNode& rTblNd, BOOL bClearTabCols )
1437 : SwUndo( UNDO_TABLE_ATTR ),
1438 nSttNode( rTblNd.GetIndex() )
1440 bClearTabCol = bClearTabCols;
1441 pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1445 SwUndoAttrTbl::~SwUndoAttrTbl()
1447 delete pSaveTbl;
1452 void SwUndoAttrTbl::Undo( SwUndoIter& rUndoIter )
1454 SwDoc& rDoc = rUndoIter.GetDoc();
1455 SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1456 ASSERT( pTblNd, "kein TabellenNode" );
1458 if (pTblNd)
1460 _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1461 pSaveTbl->RestoreAttr( pTblNd->GetTable() );
1462 delete pSaveTbl;
1463 pSaveTbl = pOrig;
1466 if( bClearTabCol )
1467 ClearFEShellTabCols();
1471 void SwUndoAttrTbl::Redo( SwUndoIter& rUndoIter )
1473 Undo( rUndoIter );
1477 /* \f */
1479 // UndoObject fuer AutoFormat an der Tabelle
1482 SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd,
1483 const SwTableAutoFmt& rAFmt )
1484 : SwUndo( UNDO_TABLE_AUTOFMT ),
1485 nSttNode( rTblNd.GetIndex() ), pUndos( 0 ),
1486 bSaveCntntAttr( FALSE )
1488 pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1490 if( rAFmt.IsFont() || rAFmt.IsJustify() )
1492 // dann auch noch ueber die ContentNodes der EndBoxen und
1493 // und alle Absatz-Attribute zusammen sammeln
1494 pSaveTbl->SaveCntntAttrs( (SwDoc*)rTblNd.GetDoc() );
1495 bSaveCntntAttr = TRUE;
1500 SwUndoTblAutoFmt::~SwUndoTblAutoFmt()
1502 delete pUndos;
1503 delete pSaveTbl;
1506 void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox )
1508 SwUndoTblNumFmt* p = new SwUndoTblNumFmt( rBox );
1509 if( !pUndos )
1510 pUndos = new SwUndos( 8, 8 );
1511 pUndos->Insert( p, pUndos->Count() );
1515 void SwUndoTblAutoFmt::UndoRedo( BOOL bUndo, SwUndoIter& rUndoIter )
1517 SwDoc& rDoc = rUndoIter.GetDoc();
1518 SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1519 ASSERT( pTblNd, "kein TabellenNode" );
1521 _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1522 // dann auch noch ueber die ContentNodes der EndBoxen und
1523 // und alle Absatz-Attribute zusammen sammeln
1524 if( bSaveCntntAttr )
1525 pOrig->SaveCntntAttrs( &rDoc );
1527 if( pUndos && bUndo )
1528 for( USHORT n = pUndos->Count(); n; )
1529 pUndos->GetObject( --n )->Undo( rUndoIter );
1531 pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo );
1532 delete pSaveTbl;
1533 pSaveTbl = pOrig;
1536 void SwUndoTblAutoFmt::Undo( SwUndoIter& rUndoIter )
1538 UndoRedo( TRUE, rUndoIter );
1542 void SwUndoTblAutoFmt::Redo( SwUndoIter& rUndoIter )
1544 UndoRedo( FALSE, rUndoIter );
1548 /* \f */
1551 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1552 const SwSelBoxes& rBoxes,
1553 const SwTableNode& rTblNd,
1554 long nMn, long nMx,
1555 USHORT nCnt, BOOL bFlg, BOOL bSmHght )
1556 : SwUndo( nAction ),
1557 aBoxes( rBoxes.Count() < 255 ? (BYTE)rBoxes.Count() : 255, 10 ),
1558 nMin( nMn ), nMax( nMx ),
1559 nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1560 nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ),
1561 nSetColType( USHRT_MAX ),
1562 bFlag( bFlg ),
1563 bSameHeight( bSmHght )
1565 Ptrs.pNewSttNds = 0;
1567 const SwTable& rTbl = rTblNd.GetTable();
1568 pSaveTbl = new _SaveTable( rTbl );
1570 // und die Selektion merken
1571 for( USHORT n = 0; n < rBoxes.Count(); ++n )
1572 aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1576 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1577 const SwSelBoxes& rBoxes,
1578 const SwTableNode& rTblNd )
1579 : SwUndo( nAction ),
1580 aBoxes( rBoxes.Count() < 255 ? (BYTE)rBoxes.Count() : 255, 10 ),
1581 nMin( 0 ), nMax( 0 ),
1582 nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1583 nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ),
1584 nSetColType( USHRT_MAX ),
1585 bFlag( FALSE ),
1586 bSameHeight( FALSE )
1588 Ptrs.pNewSttNds = 0;
1590 const SwTable& rTbl = rTblNd.GetTable();
1591 pSaveTbl = new _SaveTable( rTbl );
1593 // und die Selektion merken
1594 for( USHORT n = 0; n < rBoxes.Count(); ++n )
1595 aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1598 void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes )
1600 if( rBoxes.Count() != aBoxes.Count() )
1602 aBoxes.Remove( 0, aBoxes.Count() );
1603 for( USHORT n = 0; n < rBoxes.Count(); ++n )
1604 aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1608 SwUndoTblNdsChg::~SwUndoTblNdsChg()
1610 delete pSaveTbl;
1612 if( IsDelBox() )
1613 delete Ptrs.pDelSects;
1614 else
1615 delete Ptrs.pNewSttNds;
1618 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1619 const SwTableSortBoxes& rOld )
1621 const SwTable& rTbl = rTblNd.GetTable();
1622 const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1623 USHORT n;
1624 USHORT i;
1626 ASSERT( ! IsDelBox(), "falsche Action" );
1627 Ptrs.pNewSttNds = new SvULongs( (BYTE)(rTblBoxes.Count() - rOld.Count()), 5 );
1629 for( n = 0, i = 0; n < rOld.Count(); ++i )
1631 if( rOld[ n ] == rTblBoxes[ i ] )
1632 ++n;
1633 else
1634 // neue Box: sortiert einfuegen!!
1635 InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1638 for( ; i < rTblBoxes.Count(); ++i )
1639 // neue Box: sortiert einfuegen!!
1640 InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1644 SwTableLine* lcl_FindTableLine( const SwTable& rTable,
1645 const SwTableBox& rBox )
1647 SwTableLine* pRet = NULL;
1648 // i63949: For nested cells we have to take nLineNo - 1, too, not 0!
1649 const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != NULL ) ?
1650 rBox.GetUpper()->GetUpper()->GetTabLines()
1651 : rTable.GetTabLines();
1652 const SwTableLine* pLine = rBox.GetUpper();
1653 USHORT nLineNo = rTableLines.C40_GETPOS( SwTableLine, pLine );
1654 pRet = rTableLines[nLineNo - 1];
1656 return pRet;
1659 const SwTableLines& lcl_FindParentLines( const SwTable& rTable,
1660 const SwTableBox& rBox )
1662 const SwTableLines& rRet =
1663 ( rBox.GetUpper()->GetUpper() != NULL ) ?
1664 rBox.GetUpper()->GetUpper()->GetTabLines() :
1665 rTable.GetTabLines();
1667 return rRet;
1671 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1672 const SwTableSortBoxes& rOld,
1673 const SwSelBoxes& rBoxes,
1674 const SvULongs& rNodeCnts )
1676 const SwTable& rTbl = rTblNd.GetTable();
1677 const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1679 ASSERT( ! IsDelBox(), "falsche Action" );
1680 Ptrs.pNewSttNds = new SvULongs( (BYTE)(rTblBoxes.Count() - rOld.Count()), 5 );
1682 ASSERT( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(),
1683 "unexpected boxes" );
1684 ASSERT( rOld.Count() <= rTblBoxes.Count(), "more unexpected boxes" );
1685 for( USHORT n = 0, i = 0; i < rTblBoxes.Count(); ++i )
1687 if( ( n < rOld.Count() ) &&
1688 ( rOld[ n ] == rTblBoxes[ i ] ) )
1690 // box already known? Then nothing to be done.
1691 ++n;
1693 else
1695 // new box found: insert (obey sort order)
1696 USHORT nInsPos;
1697 const SwTableBox* pBox = rTblBoxes[ i ];
1698 InsertSort( *Ptrs.pNewSttNds, pBox->GetSttIdx(), &nInsPos );
1700 // find the source box. It must be one in rBoxes.
1701 // We found the right one if it's in the same column as pBox.
1702 // No, if more than one selected cell in the same column has been splitted,
1703 // we have to look for the nearest one (i65201)!
1704 const SwTableBox* pSourceBox = NULL;
1705 const SwTableBox* pCheckBox = NULL;
1706 const SwTableLine* pBoxLine = pBox->GetUpper();
1707 USHORT nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine);
1708 USHORT nLineNo = 0;
1709 for( USHORT j = 0; j < rBoxes.Count(); ++j )
1711 pCheckBox = rBoxes[j];
1712 if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() )
1714 const SwTableLine* pCheckLine = pCheckBox->GetUpper();
1715 USHORT nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ).
1716 C40_GETPOS( SwTableLine, pCheckLine );
1717 if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff )
1719 nLineNo = nCheckLine;
1720 pSourceBox = pCheckBox;
1725 // find the line number difference
1726 // (to help determine bNodesMoved flag below)
1727 nLineDiff = nLineDiff - nLineNo;
1728 ASSERT( pSourceBox, "Splitted source box not found!" );
1729 // find out how many nodes the source box used to have
1730 // (to help determine bNodesMoved flag below)
1731 USHORT nNdsPos = 0;
1732 while( rBoxes[ nNdsPos ] != pSourceBox )
1733 ++nNdsPos;
1734 ULONG nNodes = rNodeCnts[ nNdsPos ];
1736 // When a new table cell is created, it either gets a new
1737 // node, or it gets node(s) from elsewhere. The undo must
1738 // know, of course, and thus we must determine here just
1739 // where pBox's nodes are from:
1740 // If 1) the source box has lost nodes, and
1741 // 2) we're in the node range that got nodes
1742 // then pBox received nodes from elsewhere.
1743 // If bNodesMoved is set for pBox the undo must move the
1744 // boxes back, otherwise it must delete them.
1745 // The bNodesMoved flag is stored in a seperate array
1746 // which mirrors Ptrs.pNewSttNds, i.e. Ptrs.pNewSttNds[i]
1747 // and aMvBoxes[i] belong together.
1748 BOOL bNodesMoved =
1749 ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() -
1750 pSourceBox->GetSttIdx() ) )
1751 && ( nNodes - 1 > nLineDiff );
1752 aMvBoxes.Insert( bNodesMoved, nInsPos );
1758 void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd )
1760 ASSERT( IsDelBox(), "falsche Action" );
1761 if( !Ptrs.pDelSects )
1762 Ptrs.pDelSects = new SwUndoSaveSections( 10, 5 );
1764 SwTableNode* pTblNd = pSttNd->FindTableNode();
1765 SwUndoSaveSection* pSave = new SwUndoSaveSection;
1766 pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd ));
1768 Ptrs.pDelSects->Insert( pSave, Ptrs.pDelSects->Count() );
1769 nSttNode = pTblNd->GetIndex();
1773 void SwUndoTblNdsChg::Undo( SwUndoIter& rUndoIter )
1775 SwDoc& rDoc = rUndoIter.GetDoc();
1776 SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
1778 SwTableNode* pTblNd = rDoc.GetNodes()[ aIdx ]->GetTableNode();
1779 ASSERT( pTblNd, "kein TabellenNode" );
1781 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1782 aMsgHnt.eFlags = TBL_BOXPTR;
1783 rDoc.UpdateTblFlds( &aMsgHnt );
1785 CHECK_TABLE( pTblNd->GetTable() )
1787 _FndBox aTmpBox( 0, 0 );
1788 // ? TL_CHART2: notification or locking of controller required ?
1790 SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
1791 std::vector< SwTableBox* > aDelBoxes;
1792 if( IsDelBox() )
1794 // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
1795 // CreateNew werden sie korrekt verbunden.
1796 SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
1797 SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
1799 // die Sections wieder herstellen
1800 for( USHORT n = Ptrs.pDelSects->Count(); n; )
1802 SwUndoSaveSection* pSave = (*Ptrs.pDelSects)[ --n ];
1803 pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode );
1804 if( pSave->GetHistory() )
1805 pSave->GetHistory()->Rollback( &rDoc );
1806 SwTableBox* pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), aIdx,
1807 pCpyBox->GetUpper() );
1808 rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
1810 Ptrs.pDelSects->DeleteAndDestroy( 0, Ptrs.pDelSects->Count() );
1812 else if( aMvBoxes.Count() )
1814 // dann muessen Nodes verschoben und nicht geloescht werden!
1815 // Dafuer brauchen wir aber ein temp Array
1816 SvULongs aTmp( 0, 5);
1817 aTmp.Insert( Ptrs.pNewSttNds, 0 );
1819 // von hinten anfangen
1820 for( USHORT n = aTmp.Count(); n; )
1822 // Box aus der Tabellen-Struktur entfernen
1823 ULONG nIdx = aTmp[ --n ];
1824 SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1825 ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1827 // TL_CHART2: notify chart about box to be removed
1828 if (pPCD)
1829 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1831 if( aMvBoxes[ n ] )
1833 SwNodeRange aRg( *pBox->GetSttNd(), 1,
1834 *pBox->GetSttNd()->EndOfSectionNode() );
1836 SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox );
1837 SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 );
1839 // alle StartNode Indizies anpassen
1840 USHORT i = n;
1841 ULONG nSttIdx = aInsPos.GetIndex() - 2,
1842 nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
1843 while( i && aTmp[ --i ] > nSttIdx )
1844 aTmp[ i ] += nNdCnt;
1846 // erst die Box loeschen
1847 delete pBox;
1848 // dann die Nodes verschieben,
1849 rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, FALSE );
1851 else
1852 rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1853 aDelBoxes.insert( aDelBoxes.end(), pBox );
1856 else
1858 // Remove nodes from nodes array (backwards!)
1859 for( USHORT n = Ptrs.pNewSttNds->Count(); n; )
1861 ULONG nIdx = (*Ptrs.pNewSttNds)[ --n ];
1862 SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1863 ASSERT( pBox, "Where's my table box?" );
1864 // TL_CHART2: notify chart about box to be removed
1865 if (pPCD)
1866 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1867 aDelBoxes.insert( aDelBoxes.end(), pBox );
1868 rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1871 // Remove boxes from table structure
1872 for( USHORT n = 0; n < aDelBoxes.size(); ++n )
1874 SwTableBox* pCurrBox = aDelBoxes[n];
1875 SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes();
1876 pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pCurrBox ) );
1877 delete pCurrBox;
1880 pSaveTbl->CreateNew( pTblNd->GetTable(), TRUE, FALSE );
1882 // TL_CHART2: need to inform chart of probably changed cell names
1883 rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
1885 if( IsDelBox() )
1886 nSttNode = pTblNd->GetIndex();
1887 ClearFEShellTabCols();
1888 CHECK_TABLE( pTblNd->GetTable() )
1892 void SwUndoTblNdsChg::Redo( SwUndoIter& rUndoIter )
1894 SwDoc& rDoc = rUndoIter.GetDoc();
1896 SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1897 ASSERT( pTblNd, "kein TabellenNode" );
1898 CHECK_TABLE( pTblNd->GetTable() )
1900 SwSelBoxes aSelBoxes;
1901 for( USHORT n = 0; n < aBoxes.Count(); ++n )
1903 SwTableBox* pBox = pTblNd->GetTable().GetTblBox( aBoxes[ n ] );
1904 aSelBoxes.Insert( pBox );
1907 // SelBoxes erzeugen und InsertCell/-Row/SplitTbl aufrufen
1908 switch( GetId() )
1910 case UNDO_TABLE_INSCOL:
1911 if( USHRT_MAX == nSetColType )
1912 rDoc.InsertCol( aSelBoxes, nCount, bFlag );
1913 else
1915 SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nCurrBox );
1916 rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff,
1917 nRelDiff );
1919 break;
1921 case UNDO_TABLE_INSROW:
1922 if( USHRT_MAX == nSetColType )
1923 rDoc.InsertRow( aSelBoxes, nCount, bFlag );
1924 else
1926 SwTable& rTbl = pTblNd->GetTable();
1927 SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1928 TblChgMode eOldMode = rTbl.GetTblChgMode();
1929 rTbl.SetTblChgMode( (TblChgMode)nCount );
1930 rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, nRelDiff );
1931 rTbl.SetTblChgMode( eOldMode );
1933 break;
1935 case UNDO_TABLE_SPLIT:
1936 rDoc.SplitTbl( aSelBoxes, bFlag, nCount, bSameHeight );
1937 break;
1938 case UNDO_TABLE_DELBOX:
1939 case UNDO_ROW_DELETE:
1940 case UNDO_COL_DELETE:
1941 if( USHRT_MAX == nSetColType )
1943 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1944 aMsgHnt.eFlags = TBL_BOXPTR;
1945 rDoc.UpdateTblFlds( &aMsgHnt );
1946 SwTable &rTable = pTblNd->GetTable();
1947 if( nMax > nMin && rTable.IsNewModel() )
1948 rTable.PrepareDeleteCol( nMin, nMax );
1949 rTable.DeleteSel( &rDoc, aSelBoxes, 0, this, TRUE, TRUE );
1951 else
1953 SwTable& rTbl = pTblNd->GetTable();
1955 SwTableFmlUpdate aMsgHnt( &rTbl );
1956 aMsgHnt.eFlags = TBL_BOXPTR;
1957 rDoc.UpdateTblFlds( &aMsgHnt );
1959 SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1960 TblChgMode eOldMode = rTbl.GetTblChgMode();
1961 rTbl.SetTblChgMode( (TblChgMode)nCount );
1963 rDoc.DoUndo( TRUE ); // wir brauchen die SaveSections!
1964 SwUndoTblNdsChg* pUndo = 0;
1966 switch( nSetColType & 0xff )
1968 case nsTblChgWidthHeightType::WH_COL_LEFT:
1969 case nsTblChgWidthHeightType::WH_COL_RIGHT:
1970 case nsTblChgWidthHeightType::WH_CELL_LEFT:
1971 case nsTblChgWidthHeightType::WH_CELL_RIGHT:
1972 rTbl.SetColWidth( *pBox, nSetColType, nAbsDiff,
1973 nRelDiff, (SwUndo**)&pUndo );
1974 break;
1975 case nsTblChgWidthHeightType::WH_ROW_TOP:
1976 case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
1977 case nsTblChgWidthHeightType::WH_CELL_TOP:
1978 case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
1979 rTbl.SetRowHeight( *pBox, nSetColType, nAbsDiff,
1980 nRelDiff, (SwUndo**)&pUndo );
1981 break;
1984 if( pUndo )
1986 Ptrs.pDelSects->Insert( pUndo->Ptrs.pDelSects, 0 );
1987 pUndo->Ptrs.pDelSects->Remove( 0, pUndo->Ptrs.pDelSects->Count() );
1989 delete pUndo;
1991 rDoc.DoUndo( FALSE );
1993 rTbl.SetTblChgMode( eOldMode );
1995 nSttNode = pTblNd->GetIndex();
1996 break;
1997 default:
2000 ClearFEShellTabCols();
2001 CHECK_TABLE( pTblNd->GetTable() )
2005 /* \f */
2008 SwUndoTblMerge::SwUndoTblMerge( const SwPaM& rTblSel )
2009 : SwUndo( UNDO_TABLE_MERGE ), SwUndRng( rTblSel ), pHistory( 0 )
2011 const SwTableNode* pTblNd = rTblSel.GetNode()->FindTableNode();
2012 ASSERT( pTblNd, "Wo ist TabllenNode" )
2013 pSaveTbl = new _SaveTable( pTblNd->GetTable() );
2014 pMoves = new SwUndoMoves;
2015 nTblNode = pTblNd->GetIndex();
2019 SwUndoTblMerge::~SwUndoTblMerge()
2021 delete pSaveTbl;
2022 delete pMoves;
2023 delete pHistory;
2027 void SwUndoTblMerge::Undo( SwUndoIter& rUndoIter )
2029 SwDoc& rDoc = rUndoIter.GetDoc();
2030 SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode );
2032 SwTableNode* pTblNd = rDoc.GetNodes()[ aIdx ]->GetTableNode();
2033 ASSERT( pTblNd, "kein TabellenNode" );
2035 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2036 aMsgHnt.eFlags = TBL_BOXPTR;
2037 rDoc.UpdateTblFlds( &aMsgHnt );
2039 _FndBox aTmpBox( 0, 0 );
2040 // ? TL_CHART2: notification or locking of controller required ?
2043 // 1. die geloeschten Boxen wiederherstellen:
2045 // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
2046 // CreateNew werden sie korrekt verbunden.
2047 SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
2048 SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
2050 DUMPDOC( &rDoc, "d:\\tmp\\tab_a.db" )
2051 CHECKTABLE(pTblNd->GetTable())
2053 SwSelBoxes aSelBoxes;
2054 SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD );
2055 USHORT n;
2057 for( n = 0; n < aBoxes.Count(); ++n )
2059 aIdx = aBoxes[ n ];
2060 SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx,
2061 SwTableBoxStartNode, pColl );
2062 pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd,
2063 pCpyBox->GetUpper() );
2064 rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
2066 aSelBoxes.Insert( pBox );
2069 DUMPDOC( &rDoc, "d:\\tmp\\tab_b.db" )
2070 CHECKTABLE(pTblNd->GetTable())
2072 SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
2073 // 2. die eingefuegten Boxen loeschen
2074 // die Nodes loeschen (von Hinten!!)
2075 for( n = aNewSttNds.Count(); n; )
2077 // Box aus der Tabellen-Struktur entfernen
2078 ULONG nIdx = aNewSttNds[ --n ];
2080 if( !nIdx && n )
2082 nIdx = aNewSttNds[ --n ];
2083 pBox = pTblNd->GetTable().GetTblBox( nIdx );
2084 ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
2086 if( !pSaveTbl->IsNewModel() )
2087 rDoc.GetNodes().MakeTxtNode( SwNodeIndex(
2088 *pBox->GetSttNd()->EndOfSectionNode() ), pColl );
2090 // das war der Trenner, -> die verschobenen herstellen
2091 for( USHORT i = pMoves->Count(); i; )
2093 SwTxtNode* pTxtNd = 0;
2094 USHORT nDelPos = 0;
2095 SwUndoMove* pUndo = (*pMoves)[ --i ];
2096 if( !pUndo->IsMoveRange() )
2098 pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode();
2099 nDelPos = pUndo->GetDestSttCntnt() - 1;
2101 pUndo->Undo( rUndoIter );
2102 if( pUndo->IsMoveRange() )
2104 // den ueberfluessigen Node loeschen
2105 aIdx = pUndo->GetEndNode();
2106 SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode();
2107 if( pCNd )
2109 SwNodeIndex aTmp( aIdx, -1 );
2110 SwCntntNode *pMove = aTmp.GetNode().GetCntntNode();
2111 if( pMove )
2112 pCNd->MoveTo( *pMove );
2114 rDoc.GetNodes().Delete( aIdx, 1 );
2116 else if( pTxtNd )
2118 // evt. noch ueberflussige Attribute loeschen
2119 SwIndex aTmpIdx( pTxtNd, nDelPos );
2120 if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
2121 pTxtNd->RstAttr( aTmpIdx, pTxtNd->GetTxt().Len() -
2122 nDelPos + 1 );
2123 // das Trennzeichen loeschen
2124 pTxtNd->Erase( aTmpIdx, 1 );
2126 // delete pUndo;
2127 DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) +
2128 String(".db") )
2130 // pMoves->Remove( 0, pMoves->Count() );
2131 nIdx = pBox->GetSttIdx();
2133 else
2134 pBox = pTblNd->GetTable().GetTblBox( nIdx );
2136 if( !pSaveTbl->IsNewModel() )
2138 // TL_CHART2: notify chart about box to be removed
2139 if (pPCD)
2140 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
2142 SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
2143 pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
2146 // Indizies aus dem Bereich loeschen
2148 SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
2149 rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ),
2150 SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ),
2151 SwPosition( aTmpIdx, SwIndex( 0, 0 )), TRUE );
2154 delete pBox;
2155 rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
2158 DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" )
2159 CHECKTABLE(pTblNd->GetTable())
2162 pSaveTbl->CreateNew( pTblNd->GetTable(), TRUE, FALSE );
2164 // TL_CHART2: need to inform chart of probably changed cell names
2165 rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
2167 if( pHistory )
2169 pHistory->TmpRollback( &rDoc, 0 );
2170 pHistory->SetTmpEnd( pHistory->Count() );
2172 // nTblNode = pTblNd->GetIndex();
2174 SwPaM* pPam = rUndoIter.pAktPam;
2175 pPam->DeleteMark();
2176 pPam->GetPoint()->nNode = nSttNode;
2177 pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt );
2178 pPam->SetMark();
2179 pPam->DeleteMark();
2181 CHECKTABLE(pTblNd->GetTable())
2182 ClearFEShellTabCols();
2186 void SwUndoTblMerge::Redo( SwUndoIter& rUndoIter )
2188 SwPaM* pPam = rUndoIter.pAktPam;
2189 SwDoc& rDoc = *pPam->GetDoc();
2191 SetPaM( *pPam );
2192 rDoc.MergeTbl( *pPam );
2195 void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos )
2197 SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 );
2198 SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos );
2199 sal_Bool bDoesUndo = pDoc->DoesUndo();
2200 pDoc->DoUndo( sal_False );
2201 pDoc->Move( rRg, rPos, pSaveTbl->IsNewModel() ?
2202 IDocumentContentOperations::DOC_NO_DELFRMS :
2203 IDocumentContentOperations::DOC_MOVEDEFAULT );
2204 if( bDoesUndo )
2205 pDoc->DoUndo( sal_True );
2206 aTmp++;
2207 aTmp2++;
2208 pUndo->SetDestRange( aTmp2, rPos, aTmp );
2210 pMoves->Insert( pUndo, pMoves->Count() );
2214 void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
2216 // die Selektion merken
2217 for( USHORT n = 0; n < rBoxes.Count(); ++n )
2218 InsertSort( aBoxes, rBoxes[n]->GetSttIdx() );
2220 // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben!
2221 aNewSttNds.Insert( (ULONG)0, aNewSttNds.Count() );
2223 // The new table model does not delete overlapped cells (by row span),
2224 // so the rBoxes array might be empty even some cells have been merged.
2225 if( rBoxes.Count() )
2226 nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex();
2229 void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox )
2231 if( !pHistory )
2232 pHistory = new SwHistory;
2234 SwNodeIndex aIdx( *rBox.GetSttNd(), 1 );
2235 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
2236 if( !pCNd )
2237 pCNd = aIdx.GetNodes().GoNext( &aIdx );
2239 pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType());
2240 if( pCNd->HasSwAttrSet() )
2241 pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() );
2244 /* \f */
2247 SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox,
2248 const SfxItemSet* pNewSet )
2249 : SwUndo( UNDO_TBLNUMFMT ),
2250 pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT )
2252 bNewFmt = bNewFml = bNewValue = FALSE;
2253 nNode = rBox.GetSttIdx();
2255 nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet );
2256 SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2258 if( ULONG_MAX != nNdPos )
2260 SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2262 pHistory = new SwHistory;
2263 SwRegHistory aRHst( *rBox.GetSttNd(), pHistory );
2264 // always save all text atttibutes because of possibly overlapping
2265 // areas of on/off
2266 pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0,
2267 pTNd->GetTxt().Len(), true );
2269 if( pTNd->HasSwAttrSet() )
2270 pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos );
2272 aStr = pTNd->GetTxt();
2273 if( pTNd->GetpSwpHints() )
2274 pTNd->GetpSwpHints()->DeRegister();
2277 pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange );
2278 pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() );
2280 if( pNewSet )
2282 const SfxPoolItem* pItem;
2283 if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT,
2284 FALSE, &pItem ))
2286 bNewFmt = TRUE;
2287 nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2289 if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA,
2290 FALSE, &pItem ))
2292 bNewFml = TRUE;
2293 aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula();
2295 if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE,
2296 FALSE, &pItem ))
2298 bNewValue = TRUE;
2299 fNewNum = ((SwTblBoxValue*)pItem)->GetValue();
2303 // wird die History ueberhaupt benoetigt ??
2304 if( pHistory && !pHistory->Count() )
2305 DELETEZ( pHistory );
2309 SwUndoTblNumFmt::~SwUndoTblNumFmt()
2311 delete pHistory;
2312 delete pBoxSet;
2315 void SwUndoTblNumFmt::Undo( SwUndoIter& rIter )
2317 ASSERT( pBoxSet, "Where's the stored item set?" )
2319 SwDoc& rDoc = rIter.GetDoc();
2320 SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]->
2321 FindSttNodeByType( SwTableBoxStartNode );
2322 ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2323 SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2324 pSttNd->GetIndex() );
2325 ASSERT( pBox, "keine TabellenBox gefunden" );
2327 SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt();
2328 pFmt->SetFmtAttr( *pBoxSet );
2329 pBox->ChgFrmFmt( pFmt );
2331 if( ULONG_MAX == nNdPos )
2332 return;
2334 SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode();
2335 // wenn mehr als ein Node geloescht wurde, dann wurden auch
2336 // alle "Node"-Attribute gespeichert
2337 if( pTxtNd->HasSwAttrSet() )
2338 pTxtNd->ResetAllAttr();
2340 if( pTxtNd->GetpSwpHints() && aStr.Len() )
2341 pTxtNd->ClearSwpHintsArr( true );
2343 // ChgTextToNum(..) only acts when the strings are different. We
2344 // need to do the same here.
2345 if( pTxtNd->GetTxt() != aStr )
2347 rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX );
2349 SwIndex aIdx( pTxtNd, 0 );
2350 if( aStr.Len() )
2352 pTxtNd->Erase( aIdx );
2353 pTxtNd->Insert( aStr, aIdx, INS_NOHINTEXPAND );
2357 if( pHistory )
2359 USHORT nTmpEnd = pHistory->GetTmpEnd();
2360 pHistory->TmpRollback( &rDoc, 0 );
2361 pHistory->SetTmpEnd( nTmpEnd );
2364 SwPaM* pPam = rIter.pAktPam;
2365 pPam->DeleteMark();
2366 pPam->GetPoint()->nNode = nNode + 1;
2367 pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2370 /** switch the RedlineMode on the given document, using
2371 * SetRedlineMode_intern. This class set the mode in the constructor,
2372 * and changes it back in the destructor, i.e. it uses the
2373 * initialization-is-resource-acquisition idiom.
2375 class RedlineModeInternGuard
2377 SwDoc& mrDoc;
2378 RedlineMode_t meOldRedlineMode;
2380 public:
2381 RedlineModeInternGuard(
2382 SwDoc& rDoc, /// change mode of this document
2383 RedlineMode_t eNewRedlineMode, /// new redline mode
2384 RedlineMode_t eRedlineModeMask = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/));
2386 ~RedlineModeInternGuard();
2389 RedlineModeInternGuard::RedlineModeInternGuard(
2390 SwDoc& rDoc,
2391 RedlineMode_t eNewRedlineMode,
2392 RedlineMode_t eRedlineModeMask )
2393 : mrDoc( rDoc ),
2394 meOldRedlineMode( rDoc.GetRedlineMode() )
2396 mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) |
2397 ( eNewRedlineMode & eRedlineModeMask ) ));
2400 RedlineModeInternGuard::~RedlineModeInternGuard()
2402 mrDoc.SetRedlineMode_intern( meOldRedlineMode );
2407 void SwUndoTblNumFmt::Redo( SwUndoIter& rIter )
2409 // konnte die Box veraendert werden ?
2410 if( !pBoxSet )
2411 return ;
2413 SwDoc& rDoc = rIter.GetDoc();
2415 SwPaM* pPam = rIter.pAktPam;
2416 pPam->DeleteMark();
2417 pPam->GetPoint()->nNode = nNode;
2419 SwNode* pNd = rDoc.GetNodes()[ pPam->GetPoint()->nNode ];
2420 SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode );
2421 ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2422 SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2423 pSttNd->GetIndex() );
2424 ASSERT( pBox, "keine TabellenBox gefunden" );
2426 SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
2427 if( bNewFmt || bNewFml || bNewValue )
2429 SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2430 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2432 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2433 // Sorge dafuer, das der Text auch entsprechend
2434 // formatiert wird!
2435 pBoxFmt->LockModify();
2437 if( bNewFml )
2438 aBoxSet.Put( SwTblBoxFormula( aNewFml ));
2439 else
2440 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2441 if( bNewFmt )
2442 aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx ));
2443 else
2444 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2445 if( bNewValue )
2446 aBoxSet.Put( SwTblBoxValue( fNewNum ));
2447 else
2448 pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
2449 pBoxFmt->UnlockModify();
2451 // dvo: When redlining is (was) enabled, setting the attribute
2452 // will also change the cell content. To allow this, the
2453 // REDLINE_IGNORE flag must be removed during Redo. #108450#
2454 RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2455 pBoxFmt->SetFmtAttr( aBoxSet );
2457 else if( NUMBERFORMAT_TEXT != nFmtIdx )
2459 SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2460 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2462 aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
2463 aBoxSet.Put( SwTblBoxValue( fNum ));
2465 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2466 // Sorge dafuer, das der Text auch entsprechend
2467 // formatiert wird!
2468 pBoxFmt->LockModify();
2469 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2470 pBoxFmt->UnlockModify();
2472 // dvo: When redlining is (was) enabled, setting the attribute
2473 // will also change the cell content. To allow this, the
2474 // REDLINE_IGNORE flag must be removed during Redo. #108450#
2475 RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2476 pBoxFmt->SetFmtAttr( aBoxSet );
2478 else
2480 // es ist keine Zahl
2482 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2483 // Sorge dafuer, das der Text auch entsprechend
2484 // formatiert wird!
2485 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
2487 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2490 if( bNewFml )
2492 // egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut
2493 SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() );
2494 rDoc.UpdateTblFlds( &aTblUpdate );
2497 if( !pNd->IsCntntNode() )
2498 pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode );
2499 pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2502 void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox )
2504 nNode = rBox.GetSttIdx();
2507 /* \f */
2509 _UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox )
2510 : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ),
2511 pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false )
2515 _UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry()
2517 delete pUndo;
2518 delete pBoxNumAttr;
2522 SwUndoTblCpyTbl::SwUndoTblCpyTbl()
2523 : SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 )
2525 pArr = new _UndoTblCpyTbl_Entries;
2528 SwUndoTblCpyTbl::~SwUndoTblCpyTbl()
2530 delete pArr;
2531 delete pInsRowUndo;
2534 void SwUndoTblCpyTbl::Undo( SwUndoIter& rIter )
2536 SwDoc& rDoc = rIter.GetDoc();
2537 _DEBUG_REDLINE( &rDoc )
2539 SwTableNode* pTblNd = 0;
2540 for( USHORT n = pArr->Count(); n; )
2542 _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ];
2543 ULONG nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2544 SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2545 if( !pTblNd )
2546 pTblNd = pSNd->FindTableNode();
2548 SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2550 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2551 rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2553 // b62341295: Redline for copying tables
2554 const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode();
2555 SwPaM aPam( aInsIdx.GetNode(), *pEndNode );
2556 SwUndoDelete* pUndo = 0;
2558 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2560 bool bDeleteCompleteParagraph = false;
2561 bool bShiftPam = false;
2562 // There are a couple of different situations to consider during redlining
2563 if( pEntry->pUndo )
2565 SwUndoDelete *pUnDel = (SwUndoDelete*)pEntry->pUndo;
2566 if( UNDO_REDLINE == pUnDel->GetId() )
2568 // The old content was not empty or he has been merged with the new content
2569 bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged
2570 // Set aTmpIdx to the beginning fo the old content
2571 SwNodeIndex aTmpIdx( *pEndNode, pUnDel->NodeDiff()-1 );
2572 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2573 if( pTxt )
2575 aPam.GetPoint()->nNode = *pTxt;
2576 aPam.GetPoint()->nContent.Assign( pTxt, pUnDel->ContentStart() );
2578 else
2579 *aPam.GetPoint() = SwPosition( aTmpIdx );
2581 else if( pUnDel->IsDelFullPara() )
2583 // When the old content was an empty paragraph, but could not be joined
2584 // with the new content (e.g. because of a section or table)
2585 // We "save" the aPam.Point, we go one step backwards (because later on the
2586 // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag
2587 // for step forward later on.
2588 bDeleteCompleteParagraph = true;
2589 bShiftPam = true;
2590 SwNodeIndex aTmpIdx( *pEndNode, -1 );
2591 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2592 if( pTxt )
2594 aPam.GetPoint()->nNode = *pTxt;
2595 aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2597 else
2598 *aPam.GetPoint() = SwPosition( aTmpIdx );
2601 rDoc.DeleteRedline( aPam, true, USHRT_MAX );
2603 if( pEntry->pUndo )
2605 pEntry->pUndo->Undo( rIter );
2606 delete pEntry->pUndo;
2608 if( bShiftPam )
2610 // The aPam.Point is at the moment at the last position of the new content and has to be
2611 // moved to the first postion of the old content for the SwUndoDelete operation
2612 SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 );
2613 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2614 if( pTxt )
2616 aPam.GetPoint()->nNode = *pTxt;
2617 aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2619 else
2620 *aPam.GetPoint() = SwPosition( aTmpIdx );
2622 pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, TRUE );
2624 else
2626 pUndo = new SwUndoDelete( aPam, true );
2627 if( pEntry->pUndo )
2629 pEntry->pUndo->Undo( rIter );
2630 delete pEntry->pUndo;
2633 pEntry->pUndo = pUndo;
2635 aInsIdx = rBox.GetSttIdx() + 1;
2636 rDoc.GetNodes().Delete( aInsIdx, 1 );
2638 SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2639 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2640 aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2641 if( aTmpSet.Count() )
2643 SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2644 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2645 pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2648 if( pEntry->pBoxNumAttr )
2650 rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2651 delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2654 if( aTmpSet.Count() )
2656 pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2657 RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2658 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2659 pEntry->pBoxNumAttr->Put( aTmpSet );
2662 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2665 if( pInsRowUndo )
2666 pInsRowUndo->Undo( rIter );
2667 _DEBUG_REDLINE( &rDoc )
2670 void SwUndoTblCpyTbl::Redo( SwUndoIter& rIter )
2672 SwDoc& rDoc = rIter.GetDoc();
2673 _DEBUG_REDLINE( &rDoc )
2675 if( pInsRowUndo )
2676 pInsRowUndo->Redo( rIter );
2678 SwTableNode* pTblNd = 0;
2679 for( USHORT n = 0; n < pArr->Count(); ++n )
2681 _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ];
2682 ULONG nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2683 SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2684 if( !pTblNd )
2685 pTblNd = pSNd->FindTableNode();
2687 SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2689 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2691 // b62341295: Redline for copying tables - Start.
2692 rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2693 SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
2694 SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, TRUE );
2695 if( pEntry->pUndo )
2697 pEntry->pUndo->Undo( rIter );
2698 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2700 // PrepareRedline has to be called with the beginning of the old content
2701 // When new and old content has been joined, the rIter.pAktPam has been set
2702 // by the Undo operation to this point.
2703 // Otherwise aInsIdx has been moved during the Undo operation
2704 if( pEntry->bJoin )
2705 pUndo = PrepareRedline( &rDoc, rBox, *rIter.pAktPam->GetPoint(),
2706 pEntry->bJoin, true );
2707 else
2709 SwPosition aTmpPos( aInsIdx );
2710 pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true );
2713 delete pEntry->pUndo;
2715 pEntry->pUndo = pUndo;
2716 // b62341295: Redline for copying tables - End.
2718 aInsIdx = rBox.GetSttIdx() + 1;
2719 rDoc.GetNodes().Delete( aInsIdx, 1 );
2721 SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2722 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2723 aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2724 if( aTmpSet.Count() )
2726 SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2727 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2728 pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2730 if( pEntry->pBoxNumAttr )
2732 rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2733 delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2736 if( aTmpSet.Count() )
2738 pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2739 RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2740 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2741 pEntry->pBoxNumAttr->Put( aTmpSet );
2744 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2746 _DEBUG_REDLINE( &rDoc )
2749 void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, BOOL bDelCntnt )
2751 if( pArr->Count() && !bDelCntnt )
2752 return;
2754 _UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox );
2755 pArr->Insert( pEntry, pArr->Count() );
2757 SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2758 _DEBUG_REDLINE( pDoc )
2759 if( bDelCntnt )
2761 SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2762 pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
2763 SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
2765 if( !pDoc->IsRedlineOn() )
2766 pEntry->pUndo = new SwUndoDelete( aPam, TRUE );
2769 pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(),
2770 RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2771 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2772 pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() );
2773 if( !pEntry->pBoxNumAttr->Count() )
2774 delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2775 _DEBUG_REDLINE( pDoc )
2778 void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, BOOL bDelCntnt )
2780 _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ];
2782 // wurde der Inhalt geloescht, so loesche jetzt auch noch den temp.
2783 // erzeugten Node
2784 if( bDelCntnt )
2786 SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2787 _DEBUG_REDLINE( pDoc )
2789 if( pDoc->IsRedlineOn() )
2791 SwPosition aTmpPos( rIdx );
2792 pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false );
2794 SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 );
2795 rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 );
2796 _DEBUG_REDLINE( pDoc )
2799 pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2802 // PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations.
2803 // bRedo is set by calling from Redo()
2804 // rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has
2805 // been merged.
2806 // rJoin is true if Redo() is calling and the content has already been merged
2808 SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox,
2809 const SwPosition& rPos, bool& rJoin, bool bRedo )
2811 SwUndo *pUndo = 0;
2812 // b62341295: Redline for copying tables
2813 // What's to do?
2814 // Mark the cell content before rIdx as insertion,
2815 // mark the cell content behind rIdx as deletion
2816 // merge text nodes at rIdx if possible
2817 RedlineMode_t eOld = pDoc->GetRedlineMode();
2818 pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &
2819 ~nsRedlineMode_t::REDLINE_IGNORE ));
2820 SwPosition aInsertEnd( rPos );
2821 SwTxtNode* pTxt;
2822 if( !rJoin )
2824 // If the content is not merged, the end of the insertion is at the end of the node
2825 // _before_ the given position rPos
2826 --aInsertEnd.nNode;
2827 pTxt = aInsertEnd.nNode.GetNode().GetTxtNode();
2828 if( pTxt )
2830 aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2831 if( !bRedo && rPos.nNode.GetNode().GetTxtNode() )
2832 { // Try to merge, if not called by Redo()
2833 rJoin = true;
2834 pTxt->JoinNext();
2837 else
2838 aInsertEnd.nContent = SwIndex( 0 );
2840 // For joined (merged) contents the start of deletionm and end of insertion are identical
2841 // otherwise adjacent nodes.
2842 SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos );
2843 if( !rJoin )
2845 pTxt = aDeleteStart.nNode.GetNode().GetTxtNode();
2846 if( pTxt )
2847 aDeleteStart.nContent.Assign( pTxt, 0 );
2849 SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) );
2850 pTxt = aCellEnd.nNode.GetNode().GetTxtNode();
2851 if( pTxt )
2852 aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2853 if( aDeleteStart != aCellEnd )
2854 { // If the old (deleted) part is not empty, here we are...
2855 SwPaM aDeletePam( aDeleteStart, aCellEnd );
2856 pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE );
2857 pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true );
2859 else if( !rJoin ) // If the old part is empty and joined, we are finished
2860 { // if it is not joined, we have to delete this empty paragraph
2861 aCellEnd = SwPosition(
2862 SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() ));
2863 SwPaM aTmpPam( aDeleteStart, aCellEnd );
2864 pUndo = new SwUndoDelete( aTmpPam, TRUE );
2866 SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) );
2867 pTxt = aCellStart.nNode.GetNode().GetTxtNode();
2868 if( pTxt )
2869 aCellStart.nContent.Assign( pTxt, 0 );
2870 if( aCellStart != aInsertEnd ) // An empty insertion will not been marked
2872 SwPaM aTmpPam( aCellStart, aInsertEnd );
2873 pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true );
2876 pDoc->SetRedlineMode_intern( eOld );
2877 return pUndo;
2881 BOOL SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes,
2882 USHORT nCnt )
2884 SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]->
2885 GetSttNd()->FindTableNode();
2887 SwTableSortBoxes aTmpLst( 0, 5 );
2888 pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd,
2889 0, 0, nCnt, TRUE, FALSE );
2890 aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2892 BOOL bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, TRUE );
2893 if( bRet )
2894 pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2895 else
2896 delete pInsRowUndo, pInsRowUndo = 0;
2897 return bRet;
2900 BOOL SwUndoTblCpyTbl::IsEmpty() const
2902 return !pInsRowUndo && !pArr->Count();
2905 /* \f */
2907 SwUndoCpyTbl::SwUndoCpyTbl()
2908 : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 )
2912 SwUndoCpyTbl::~SwUndoCpyTbl()
2914 delete pDel;
2917 void SwUndoCpyTbl::Undo( SwUndoIter& rIter )
2919 SwDoc& rDoc = rIter.GetDoc();
2920 SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode();
2922 // harte SeitenUmbrueche am nachfolgenden Node verschieben
2923 SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2924 if( pNextNd )
2926 SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt();
2927 const SfxPoolItem *pItem;
2929 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2930 FALSE, &pItem ) )
2931 pNextNd->SetAttr( *pItem );
2933 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2934 FALSE, &pItem ) )
2935 pNextNd->SetAttr( *pItem );
2938 SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 );
2939 pDel = new SwUndoDelete( aPam, TRUE );
2942 void SwUndoCpyTbl::Redo( SwUndoIter& rIter )
2944 pDel->Undo( rIter );
2945 delete pDel, pDel = 0;
2949 /* \f */
2951 SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd,
2952 SwSaveRowSpan* pRowSp, USHORT eMode, BOOL bNewSize )
2953 : SwUndo( UNDO_SPLIT_TABLE ),
2954 nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ),
2955 pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize )
2957 switch( nMode )
2959 case HEADLINE_BOXATRCOLLCOPY:
2960 pHistory = new SwHistory;
2961 // kein break;
2962 case HEADLINE_BORDERCOPY:
2963 case HEADLINE_BOXATTRCOPY:
2964 pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, FALSE );
2965 break;
2969 SwUndoSplitTbl::~SwUndoSplitTbl()
2971 delete pSavTbl;
2972 delete pHistory;
2973 delete mpSaveRowSpan;
2976 void SwUndoSplitTbl::Undo( SwUndoIter& rIter )
2978 SwPaM* pPam = rIter.pAktPam;
2979 SwDoc* pDoc = pPam->GetDoc();
2981 pPam->DeleteMark();
2982 SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2983 rIdx = nTblNode + nOffset;
2985 //Den implizit erzeugten Absatz wieder entfernen.
2986 pDoc->GetNodes().Delete( rIdx, 1 );
2988 rIdx = nTblNode + nOffset;
2989 SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
2990 SwTable& rTbl = pTblNd->GetTable();
2992 SwTableFmlUpdate aMsgHnt( &rTbl );
2993 aMsgHnt.eFlags = TBL_BOXPTR;
2994 pDoc->UpdateTblFlds( &aMsgHnt );
2996 switch( nMode )
2998 case HEADLINE_BOXATRCOLLCOPY:
2999 if( pHistory )
3000 pHistory->TmpRollback( pDoc, nFmlEnd );
3002 // kein break
3003 case HEADLINE_BOXATTRCOPY:
3004 case HEADLINE_BORDERCOPY:
3006 pSavTbl->CreateNew( rTbl, FALSE );
3007 pSavTbl->RestoreAttr( rTbl );
3009 break;
3011 case HEADLINE_CNTNTCOPY:
3012 // die erzeugte 1. Line muss wieder entfernt werden
3014 SwSelBoxes aSelBoxes;
3015 SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 );
3016 rTbl.SelLineFromBox( pBox, aSelBoxes, TRUE );
3017 _FndBox aTmpBox( 0, 0 );
3018 aTmpBox.SetTableLines( aSelBoxes, rTbl );
3019 aTmpBox.DelFrms( rTbl );
3020 rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, FALSE, FALSE );
3022 break;
3025 pDoc->GetNodes().MergeTable( rIdx );
3027 if( pHistory )
3029 pHistory->TmpRollback( pDoc, 0 );
3030 pHistory->SetTmpEnd( pHistory->Count() );
3032 if( mpSaveRowSpan )
3034 pTblNd = rIdx.GetNode().FindTableNode();
3035 if( pTblNd )
3036 pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan );
3038 ClearFEShellTabCols();
3041 void SwUndoSplitTbl::Redo( SwUndoIter& rIter )
3043 SwPaM* pPam = rIter.pAktPam;
3044 SwDoc* pDoc = pPam->GetDoc();
3046 pPam->DeleteMark();
3047 pPam->GetPoint()->nNode = nTblNode;
3048 pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3050 ClearFEShellTabCols();
3053 void SwUndoSplitTbl::Repeat( SwUndoIter& rIter )
3055 SwPaM* pPam = rIter.pAktPam;
3056 SwDoc* pDoc = pPam->GetDoc();
3058 pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3059 ClearFEShellTabCols();
3062 void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory )
3064 if( !pHistory )
3065 pHistory = new SwHistory;
3067 nFmlEnd = rHistory.Count();
3068 pHistory->Move( 0, &rHistory );
3071 /* \f */
3073 SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd,
3074 const SwTableNode& rDelTblNd,
3075 BOOL bWithPrv, USHORT nMd )
3076 : SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ),
3077 pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv )
3079 // Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt
3080 if( bWithPrev )
3081 nTblNode = rDelTblNd.EndOfSectionIndex() - 1;
3082 else
3083 nTblNode = rTblNd.EndOfSectionIndex() - 1;
3085 aName = rDelTblNd.GetTable().GetFrmFmt()->GetName();
3086 pSavTbl = new _SaveTable( rDelTblNd.GetTable() );
3088 pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0;
3091 SwUndoMergeTbl::~SwUndoMergeTbl()
3093 delete pSavTbl;
3094 delete pSavHdl;
3095 delete pHistory;
3098 void SwUndoMergeTbl::Undo( SwUndoIter& rIter )
3100 SwPaM* pPam = rIter.pAktPam;
3101 SwDoc* pDoc = pPam->GetDoc();
3103 pPam->DeleteMark();
3104 SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
3105 rIdx = nTblNode;
3107 SwTableNode* pTblNd = rIdx.GetNode().FindTableNode();
3108 SwTable* pTbl = &pTblNd->GetTable();
3110 SwTableFmlUpdate aMsgHnt( pTbl );
3111 aMsgHnt.eFlags = TBL_BOXPTR;
3112 pDoc->UpdateTblFlds( &aMsgHnt );
3114 //Lines fuer das Layout-Update herausuchen.
3115 _FndBox aFndBox( 0, 0 );
3116 aFndBox.SetTableLines( *pTbl );
3117 aFndBox.DelFrms( *pTbl );
3118 // ? TL_CHART2: notification or locking of controller required ?
3120 SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, TRUE, FALSE );
3122 //Layout updaten
3123 aFndBox.MakeFrms( *pTbl );
3124 // ? TL_CHART2: notification or locking of controller required ?
3126 if( bWithPrev )
3128 // den Namen umsetzen
3129 pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() );
3130 pSavHdl->RestoreAttr( pNew->GetTable() );
3132 else
3133 pTbl = &pNew->GetTable();
3134 pTbl->GetFrmFmt()->SetName( aName );
3136 // pSavTbl->CreateNew( *pTbl, FALSE );
3137 pSavTbl->RestoreAttr( *pTbl );
3140 if( pHistory )
3142 pHistory->TmpRollback( pDoc, 0 );
3143 pHistory->SetTmpEnd( pHistory->Count() );
3146 // fuer die neue Tabelle die Frames anlegen
3147 SwNodeIndex aTmpIdx( *pNew );
3148 pNew->MakeFrms( &aTmpIdx );
3150 // Cursor irgendwo in den Content stellen
3151 SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx );
3152 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3154 ClearFEShellTabCols();
3156 // TL_CHART2: need to inform chart of probably changed cell names
3157 SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
3158 if (pPCD)
3160 pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() );
3161 pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() );
3165 void SwUndoMergeTbl::Redo( SwUndoIter& rIter )
3167 SwPaM* pPam = rIter.pAktPam;
3168 SwDoc* pDoc = pPam->GetDoc();
3170 pPam->DeleteMark();
3171 pPam->GetPoint()->nNode = nTblNode;
3172 if( bWithPrev )
3173 pPam->GetPoint()->nNode = nTblNode + 3;
3174 else
3175 pPam->GetPoint()->nNode = nTblNode;
3177 pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3179 ClearFEShellTabCols();
3182 void SwUndoMergeTbl::Repeat( SwUndoIter& rIter )
3184 SwPaM* pPam = rIter.pAktPam;
3185 SwDoc* pDoc = pPam->GetDoc();
3187 pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3188 ClearFEShellTabCols();
3191 void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory )
3193 if( !pHistory )
3194 pHistory = new SwHistory;
3195 pHistory->Move( 0, &rHistory );
3198 /* \f */
3201 void InsertSort( SvUShorts& rArr, USHORT nIdx, USHORT* pInsPos )
3203 USHORT nO = rArr.Count(), nM, nU = 0;
3204 if( nO > 0 )
3206 nO--;
3207 while( nU <= nO )
3209 nM = nU + ( nO - nU ) / 2;
3210 if( *(rArr.GetData() + nM) == nIdx )
3212 ASSERT( FALSE, "Index ist schon vorhanden, darf nie sein!" );
3213 return;
3215 if( *(rArr.GetData() + nM) < nIdx )
3216 nU = nM + 1;
3217 else if( nM == 0 )
3218 break;
3219 else
3220 nO = nM - 1;
3223 rArr.Insert( nIdx, nU );
3224 if( pInsPos )
3225 *pInsPos = nU;
3228 void InsertSort( SvULongs& rArr, ULONG nIdx, USHORT* pInsPos )
3230 USHORT nO = rArr.Count(), nM, nU = 0;
3231 if( nO > 0 )
3233 nO--;
3234 while( nU <= nO )
3236 nM = nU + ( nO - nU ) / 2;
3237 if( *(rArr.GetData() + nM) == nIdx )
3239 ASSERT( FALSE, "Index ist schon vorhanden, darf nie sein!" );
3240 return;
3242 if( *(rArr.GetData() + nM) < nIdx )
3243 nU = nM + 1;
3244 else if( nM == 0 )
3245 break;
3246 else
3247 nO = nM - 1;
3250 rArr.Insert( nIdx, nU );
3251 if( pInsPos )
3252 *pInsPos = nU;
3255 #if defined( JP_DEBUG ) && !defined( PRODUCT )
3258 void DumpDoc( SwDoc* pDoc, const String& rFileNm )
3260 Writer* pWrt = SwIoSystem::GetWriter( "DEBUG" );
3261 if( pWrt )
3263 SvFileStream aStream( rFileNm, STREAM_STD_WRITE );
3264 SwPaM* pPam = new SwPaM( pDoc, SwPosition( pDoc->GetNodes().EndOfContent ,
3265 pDoc->GetNodes().EndOfContent ));
3266 pPam->Move( fnMoveBackward, fnGoDoc );
3267 pPam->SetMark();
3268 pPam->Move( fnMoveForward, fnGoDoc );
3270 pWrt->Write( pPam, *pDoc, aStream, rFileNm.GetStr() );
3272 delete pPam;
3275 void CheckTable( const SwTable& rTbl )
3277 const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
3278 const SwTableSortBoxes& rSrtArr = pTblNd->GetTable().GetTabSortBoxes();
3279 for( USHORT n = 0; n < rSrtArr.Count(); ++n )
3281 const SwTableBox* pBox = rSrtArr[ n ];
3282 const SwNode* pNd = pBox->GetSttNd();
3283 ASSERT( rNds[ *pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode" );
3286 #endif