xref: /trunk/main/sw/source/core/undo/untbl.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <UndoTable.hxx>
32 
33 #include <UndoRedline.hxx>
34 #include <UndoDelete.hxx>
35 #include <UndoSplitMove.hxx>
36 #include <UndoCore.hxx>
37 #include <hintids.hxx>
38 #include <hints.hxx>
39 #include <editeng/brkitem.hxx>
40 #include <fmtornt.hxx>
41 #include <fmtpdsc.hxx>
42 #include <doc.hxx>
43 #include <IDocumentUndoRedo.hxx>
44 #include <editsh.hxx>
45 #include <docary.hxx>
46 #include <ndtxt.hxx>
47 #include <swtable.hxx>
48 #include <pam.hxx>
49 #include <cntfrm.hxx>
50 #include <tblsel.hxx>
51 #include <swundo.hxx>           // fuer die UndoIds
52 #include <rolbck.hxx>
53 #include <ddefld.hxx>
54 #include <tabcol.hxx>
55 #include <tabfrm.hxx>
56 #include <rowfrm.hxx>
57 #include <cellfrm.hxx>
58 #include <swcache.hxx>
59 #include <tblafmt.hxx>
60 #include <poolfmt.hxx>
61 #include <mvsave.hxx>
62 #include <cellatr.hxx>
63 #include <swtblfmt.hxx>
64 #include <swddetbl.hxx>
65 #include <redline.hxx>
66 #include <node2lay.hxx>
67 #include <tblrwcl.hxx>
68 #include <fmtanchr.hxx>
69 #include <comcore.hrc>
70 #include <unochart.hxx>
71 #include <switerator.hxx>
72 
73 #ifndef DBG_UTIL
74 #define CHECK_TABLE(t)
75 #else
76 #ifdef DEBUG
77 #define CHECK_TABLE(t) (t).CheckConsistency();
78 #else
79 #define CHECK_TABLE(t)
80 #endif
81 #endif
82 
83 #ifndef DBG_UTIL
84     #define _DEBUG_REDLINE( pDoc )
85 #else
86     void lcl_DebugRedline( const SwDoc* pDoc );
87     #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc );
88 #endif
89 
90 extern void ClearFEShellTabCols();
91 
92 typedef SfxItemSet* SfxItemSetPtr;
93 SV_DECL_PTRARR_DEL( SfxItemSets, SfxItemSetPtr, 10, 5 )
94 
95 typedef SwUndoSaveSection* SwUndoSaveSectionPtr;
96 SV_DECL_PTRARR_DEL( SwUndoSaveSections, SwUndoSaveSectionPtr, 0, 10 )
97 
98 typedef SwUndoMove* SwUndoMovePtr;
99 SV_DECL_PTRARR_DEL( SwUndoMoves, SwUndoMovePtr, 0, 10 )
100 
101 struct SwTblToTxtSave;
102 typedef SwTblToTxtSave* SwTblToTxtSavePtr;
103 SV_DECL_PTRARR_DEL( SwTblToTxtSaves, SwTblToTxtSavePtr, 0, 10 )
104 
105 struct _UndoTblCpyTbl_Entry
106 {
107     sal_uLong nBoxIdx, nOffset;
108     SfxItemSet* pBoxNumAttr;
109     SwUndo* pUndo;
110 
111     // Was the last paragraph of the new and the first paragraph of the old content joined?
112     bool bJoin; // For redlining only
113 
114     _UndoTblCpyTbl_Entry( const SwTableBox& rBox );
115     ~_UndoTblCpyTbl_Entry();
116 };
117 typedef _UndoTblCpyTbl_Entry* _UndoTblCpyTbl_EntryPtr;
118 SV_DECL_PTRARR_DEL( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr, 0, 10 )
119 
120 class _SaveBox;
121 class _SaveLine;
122 
123 class _SaveTable
124 {
125     friend class _SaveBox;
126     friend class _SaveLine;
127     SfxItemSet aTblSet;
128     _SaveLine* pLine;
129     const SwTable* pSwTable;
130     SfxItemSets aSets;
131     SwFrmFmts aFrmFmts;
132     sal_uInt16 nLineCount;
133     sal_Bool bModifyBox : 1;
134     sal_Bool bSaveFormula : 1;
135     sal_Bool bNewModel : 1;
136 
137 public:
138     _SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt = USHRT_MAX,
139                 sal_Bool bSaveFml = sal_True );
140     ~_SaveTable();
141 
142     sal_uInt16 AddFmt( SwFrmFmt* pFmt, bool bIsLine );
143     void NewFrmFmt( const SwTableLine* , const SwTableBox*, sal_uInt16 nFmtPos,
144                     SwFrmFmt* pOldFmt );
145 
146     void RestoreAttr( SwTable& rTbl, sal_Bool bModifyBox = sal_False );
147     void SaveCntntAttrs( SwDoc* pDoc );
148     void CreateNew( SwTable& rTbl, sal_Bool bCreateFrms = sal_True,
149                     sal_Bool bRestoreChart = sal_True );
150     sal_Bool IsNewModel() const { return bNewModel; }
151 };
152 
153 class _SaveLine
154 {
155     friend class _SaveTable;
156     friend class _SaveBox;
157 
158     _SaveLine* pNext;
159     _SaveBox* pBox;
160     sal_uInt16 nItemSet;
161 
162 public:
163 
164     _SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl );
165     ~_SaveLine();
166 
167     void RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl );
168     void SaveCntntAttrs( SwDoc* pDoc );
169 
170     void CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl  );
171 };
172 
173 class _SaveBox
174 {
175     friend class _SaveLine;
176 
177     _SaveBox* pNext;
178     sal_uLong nSttNode;
179     long nRowSpan;
180     sal_uInt16 nItemSet;
181     union
182     {
183         SfxItemSets* pCntntAttrs;
184         _SaveLine* pLine;
185     } Ptrs;
186 
187 public:
188     _SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl );
189     ~_SaveBox();
190 
191     void RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl );
192     void SaveCntntAttrs( SwDoc* pDoc );
193 
194     void CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl );
195 };
196 
197 void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 );
198 void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos = 0 );
199 
200 #if defined( JP_DEBUG ) && defined(DBG_UTIL)
201 #include "shellio.hxx"
202 void DumpDoc( SwDoc* pDoc, const String& rFileNm );
203 void CheckTable( const SwTable& );
204 #define DUMPDOC(p,s)    DumpDoc( p, s);
205 #define CHECKTABLE(t) CheckTable( t );
206 #else
207 #define DUMPDOC(p,s)
208 #define CHECKTABLE(t)
209 #endif
210 
211 /* #130880: Crash in undo of table to text when the table has (freshly) merged cells
212 The order of cell content nodes in the nodes array is not given by the recursive table structure.
213 The algorithmn must not rely on this even it holds for a fresh loaded table in odt file format.
214 So we need to remember not only the start node position but the end node position as well.
215 */
216 
217 struct SwTblToTxtSave
218 {
219     sal_uLong m_nSttNd;
220     sal_uLong m_nEndNd;
221     xub_StrLen m_nCntnt;
222     SwHistory* m_pHstry;
223     // metadata references for first and last paragraph in cell
224     ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart;
225     ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd;
226 
227     SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCntnt );
228     ~SwTblToTxtSave() { delete m_pHstry; }
229 };
230 
231 SV_IMPL_PTRARR( SfxItemSets, SfxItemSetPtr )
232 SV_IMPL_PTRARR( SwUndoSaveSections, SwUndoSaveSectionPtr )
233 SV_IMPL_PTRARR( SwUndoMoves, SwUndoMovePtr )
234 SV_IMPL_PTRARR( SwTblToTxtSaves, SwTblToTxtSavePtr )
235 SV_IMPL_PTRARR( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr )
236 
237 sal_uInt16 __FAR_DATA aSave_BoxCntntSet[] = {
238     RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT,
239     RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
240     RES_CHRATR_POSTURE, RES_CHRATR_POSTURE,
241     RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT,
242     RES_PARATR_ADJUST, RES_PARATR_ADJUST,
243     0 };
244 
245 
246 
247 SwUndoInsTbl::SwUndoInsTbl( const SwPosition& rPos, sal_uInt16 nCl, sal_uInt16 nRw,
248                             sal_uInt16 nAdj, const SwInsertTableOptions& rInsTblOpts,
249                             const SwTableAutoFmt* pTAFmt,
250                             const SvUShorts* pColArr,
251                             const String & rName)
252     : SwUndo( UNDO_INSTABLE ),
253     aInsTblOpts( rInsTblOpts ), pDDEFldType( 0 ), pColWidth( 0 ), pRedlData( 0 ), pAutoFmt( 0 ),
254     nSttNode( rPos.nNode.GetIndex() ), nRows( nRw ), nCols( nCl ), nAdjust( nAdj )
255 {
256     if( pColArr )
257     {
258         pColWidth = new SvUShorts( 0, 1 );
259         pColWidth->Insert( pColArr, 0 );
260     }
261     if( pTAFmt )
262         pAutoFmt = new SwTableAutoFmt( *pTAFmt );
263 
264     // Redline beachten
265     SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc();
266     if( rDoc.IsRedlineOn() )
267     {
268         pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() );
269         SetRedlineMode( rDoc.GetRedlineMode() );
270     }
271 
272     sTblNm = rName;
273 }
274 
275 
276 SwUndoInsTbl::~SwUndoInsTbl()
277 {
278     delete pDDEFldType;
279     delete pColWidth;
280     delete pRedlData;
281     delete pAutoFmt;
282 }
283 
284 void SwUndoInsTbl::UndoImpl(::sw::UndoRedoContext & rContext)
285 {
286     SwDoc & rDoc = rContext.GetDoc();
287     SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
288 
289     SwTableNode* pTblNd = aIdx.GetNode().GetTableNode();
290     ASSERT( pTblNd, "kein TabellenNode" );
291     pTblNd->DelFrms();
292 
293     if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
294         rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX );
295     RemoveIdxFromSection( rDoc, nSttNode );
296 
297     // harte SeitenUmbrueche am nachfolgenden Node verschieben
298     SwCntntNode* pNextNd = rDoc.GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
299     if( pNextNd )
300     {
301         SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
302         const SfxPoolItem *pItem;
303 
304         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
305             sal_False, &pItem ) )
306             pNextNd->SetAttr( *pItem );
307 
308         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
309             sal_False, &pItem ) )
310             pNextNd->SetAttr( *pItem );
311     }
312 
313 
314     sTblNm = pTblNd->GetTable().GetFrmFmt()->GetName();
315     if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
316         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
317                                         GetDDEFldType()->Copy();
318 
319     rDoc.GetNodes().Delete( aIdx, pTblNd->EndOfSectionIndex() -
320                                 aIdx.GetIndex() + 1 );
321 
322     SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() );
323     rPam.DeleteMark();
324     rPam.GetPoint()->nNode = aIdx;
325     rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 );
326 }
327 
328 
329 void SwUndoInsTbl::RedoImpl(::sw::UndoRedoContext & rContext)
330 {
331     SwDoc & rDoc = rContext.GetDoc();
332 
333     SwPosition const aPos(SwNodeIndex(rDoc.GetNodes(), nSttNode));
334     const SwTable* pTbl = rDoc.InsertTable( aInsTblOpts, aPos, nRows, nCols,
335                                             nAdjust,
336                                             pAutoFmt, pColWidth );
337     ((SwFrmFmt*)pTbl->GetFrmFmt())->SetName( sTblNm );
338     SwTableNode* pTblNode = (SwTableNode*)rDoc.GetNodes()[nSttNode]->GetTableNode();
339 
340     if( pDDEFldType )
341     {
342         SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
343                                                             *pDDEFldType);
344         SwDDETable* pDDETbl = new SwDDETable( pTblNode->GetTable(), pNewType );
345         pTblNode->SetNewTable( pDDETbl );       // setze die DDE-Tabelle
346         delete pDDEFldType, pDDEFldType = 0;
347     }
348 
349     if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) ||
350         ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
351             rDoc.GetRedlineTbl().Count() ))
352     {
353         SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 );
354         SwCntntNode* pCNd = aPam.GetCntntNode( sal_False );
355         if( pCNd )
356             aPam.GetMark()->nContent.Assign( pCNd, 0 );
357 
358         if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
359         {
360             RedlineMode_t eOld = rDoc.GetRedlineMode();
361             rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE));
362 
363             rDoc.AppendRedline( new SwRedline( *pRedlData, aPam ), true);
364             rDoc.SetRedlineMode_intern( eOld );
365         }
366         else
367             rDoc.SplitRedline( aPam );
368     }
369 }
370 
371 
372 void SwUndoInsTbl::RepeatImpl(::sw::RepeatContext & rContext)
373 {
374     rContext.GetDoc().InsertTable(
375             aInsTblOpts, *rContext.GetRepeatPaM().GetPoint(),
376             nRows, nCols, nAdjust, pAutoFmt, pColWidth );
377 }
378 
379 SwRewriter SwUndoInsTbl::GetRewriter() const
380 {
381     SwRewriter aRewriter;
382 
383     aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE));
384     aRewriter.AddRule(UNDO_ARG2, sTblNm);
385     aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE));
386 
387     return aRewriter;
388 }
389 
390 // -----------------------------------------------------
391 
392 SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCnt )
393     : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 )
394 {
395     // Attributierung des gejointen Node merken.
396     SwTxtNode* pNd = rDoc.GetNodes()[ nNd ]->GetTxtNode();
397     if( pNd )
398     {
399         m_pHstry = new SwHistory;
400 
401         m_pHstry->Add( pNd->GetTxtColl(), nNd, ND_TEXTNODE );
402         if ( pNd->GetpSwpHints() )
403         {
404             m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0,
405                         pNd->GetTxt().Len(), false );
406         }
407         if( pNd->HasSwAttrSet() )
408             m_pHstry->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNd );
409 
410         if( !m_pHstry->Count() )
411             delete m_pHstry, m_pHstry = 0;
412 
413         // METADATA: store
414         m_pMetadataUndoStart = pNd->CreateUndo();
415     }
416 
417     // we also need to store the metadata reference of the _last_ paragraph
418     // we subtract 1 to account for the removed cell start/end node pair
419     // (after SectionUp, the end of the range points to the node after the cell)
420     if ( nEndIdx - 1 > nNd )
421     {
422         SwTxtNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTxtNode() );
423         if( pLastNode )
424         {
425             // METADATA: store
426             m_pMetadataUndoEnd = pLastNode->CreateUndo();
427         }
428     }
429 }
430 
431 SwUndoTblToTxt::SwUndoTblToTxt( const SwTable& rTbl, sal_Unicode cCh )
432     : SwUndo( UNDO_TABLETOTEXT ),
433     sTblNm( rTbl.GetFrmFmt()->GetName() ), pDDEFldType( 0 ), pHistory( 0 ),
434     nSttNd( 0 ), nEndNd( 0 ),
435     nAdjust( static_cast<sal_uInt16>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ),
436     cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() )
437 {
438     pTblSave = new _SaveTable( rTbl );
439     pBoxSaves = new SwTblToTxtSaves( (sal_uInt8)rTbl.GetTabSortBoxes().Count() );
440 
441     if( rTbl.IsA( TYPE( SwDDETable ) ) )
442         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)rTbl).GetDDEFldType()->Copy();
443 
444     bCheckNumFmt = rTbl.GetFrmFmt()->GetDoc()->IsInsTblFormatNum();
445 
446     pHistory = new SwHistory;
447     const SwTableNode* pTblNd = rTbl.GetTableNode();
448     sal_uLong nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex();
449 
450     const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts();
451     for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n )
452     {
453         SwFrmFmt* pFmt = rFrmFmtTbl[ n ];
454         SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
455         SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
456         if (pAPos &&
457             ((FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
458              (FLY_AT_PARA == pAnchor->GetAnchorId())) &&
459             nTblStt <= pAPos->nNode.GetIndex() &&
460             pAPos->nNode.GetIndex() < nTblEnd )
461         {
462             pHistory->Add( *pFmt );
463         }
464     }
465 
466     if( !pHistory->Count() )
467         delete pHistory, pHistory = 0;
468 }
469 
470 
471 SwUndoTblToTxt::~SwUndoTblToTxt()
472 {
473     delete pDDEFldType;
474     delete pTblSave;
475     delete pBoxSaves;
476     delete pHistory;
477 }
478 
479 
480 
481 void SwUndoTblToTxt::UndoImpl(::sw::UndoRedoContext & rContext)
482 {
483     SwDoc & rDoc = rContext.GetDoc();
484     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
485 
486     SwNodeIndex aFrmIdx( rDoc.GetNodes(), nSttNd );
487     SwNodeIndex aEndIdx( rDoc.GetNodes(), nEndNd );
488 
489     pPam->GetPoint()->nNode = aFrmIdx;
490     pPam->SetMark();
491     pPam->GetPoint()->nNode = aEndIdx;
492     rDoc.DelNumRules( *pPam );
493     pPam->DeleteMark();
494 
495     // dann sammel mal alle Uppers ein
496     SwNode2Layout aNode2Layout( aFrmIdx.GetNode() );
497 
498     // erzeuge die TabelleNode Structur
499     SwTableNode* pTblNd = rDoc.GetNodes().UndoTableToText( nSttNd, nEndNd, *pBoxSaves );
500     pTblNd->GetTable().SetTableModel( pTblSave->IsNewModel() );
501     SwTableFmt* pTableFmt = rDoc.MakeTblFrmFmt( sTblNm, rDoc.GetDfltFrmFmt() );
502     pTblNd->GetTable().RegisterToFormat( *pTableFmt );
503     pTblNd->GetTable().SetRowsToRepeat( nHdlnRpt );
504 
505     // erzeuge die alte Tabellen Struktur
506     pTblSave->CreateNew( pTblNd->GetTable() );
507 
508     if( pDDEFldType )
509     {
510         SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
511                                                             *pDDEFldType);
512         SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType );
513         pTblNd->SetNewTable( pDDETbl, sal_False );      // setze die DDE-Tabelle
514         delete pDDEFldType, pDDEFldType = 0;
515     }
516 
517     if( bCheckNumFmt )
518     {
519         SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes();
520         for( sal_uInt16 nBoxes = rBxs.Count(); nBoxes; )
521             rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], sal_False );
522     }
523 
524     if( pHistory )
525     {
526         sal_uInt16 nTmpEnd = pHistory->GetTmpEnd();
527         pHistory->TmpRollback( &rDoc, 0 );
528         pHistory->SetTmpEnd( nTmpEnd );
529     }
530 
531     aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(),
532                                    pTblNd->GetIndex(), pTblNd->GetIndex()+1 );
533 
534     // will man eine TabellenSelektion ??
535     pPam->DeleteMark();
536     pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
537     pPam->SetMark();
538     pPam->GetPoint()->nNode = *pPam->GetNode()->StartOfSectionNode();
539     pPam->Move( fnMoveForward, fnGoCntnt );
540     pPam->Exchange();
541     pPam->Move( fnMoveBackward, fnGoCntnt );
542 
543     ClearFEShellTabCols();
544 }
545 
546     // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
547 SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd,
548                                 const SwTblToTxtSaves& rSavedData )
549 {
550     SwNodeIndex aSttIdx( *this, nSttNd );
551     SwNodeIndex aEndIdx( *this, nEndNd+1 );
552 
553     SwTableNode * pTblNd = new SwTableNode( aSttIdx );
554     SwEndNode* pEndNd = new SwEndNode( aEndIdx, *pTblNd  );
555 
556     aEndIdx = *pEndNd;
557 
558     /* Set pTblNd as start of section for all nodes in [nSttNd, nEndNd].
559        Delete all Frames attached to the nodes in that range. */
560     SwNode* pNd;
561     {
562         sal_uLong n, nTmpEnd = aEndIdx.GetIndex();
563         for( n = pTblNd->GetIndex() + 1; n < nTmpEnd; ++n )
564         {
565             if( ( pNd = (*this)[ n ] )->IsCntntNode() )
566                 ((SwCntntNode*)pNd)->DelFrms();
567             pNd->pStartOfSection = pTblNd;
568         }
569     }
570 
571     // dann die Tabellen Struktur teilweise aufbauen. Erstmal eine Line
572     // in der alle Boxen stehen! Die korrekte Struktur kommt dann aus der
573     // SaveStruct
574     SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt();
575     SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt();
576     SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.Count(), 0 );
577     pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pLine, 0 );
578 
579     SvULongs aBkmkArr( 0, 4 );
580     for( sal_uInt16 n = rSavedData.Count(); n; )
581     {
582         SwTblToTxtSave* pSave = rSavedData[ --n ];
583         // if the start node was merged with last from prev. cell,
584         // subtract 1 from index to get the merged paragraph, and split that
585         aSttIdx = pSave->m_nSttNd - ( ( USHRT_MAX != pSave->m_nCntnt ) ? 1 : 0);
586         SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
587 
588         if( USHRT_MAX != pSave->m_nCntnt )
589         {
590             // an der ContentPosition splitten, das vorherige Zeichen
591             // loeschen (ist der Trenner!)
592             ASSERT( pTxtNd, "Wo ist der TextNode geblieben?" );
593             SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 );
594 
595             pTxtNd->EraseText( aCntPos, 1 );
596             SwCntntNode* pNewNd = pTxtNd->SplitCntntNode(
597                                         SwPosition( aSttIdx, aCntPos ));
598             if( aBkmkArr.Count() )
599                 _RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt,
600                                                      pSave->m_nCntnt + 1 );
601         }
602         else
603         {
604             if( aBkmkArr.Count() )
605                 aBkmkArr.Remove( 0, aBkmkArr.Count() );
606             if( pTxtNd )
607                 _SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(),
608                                 pTxtNd->GetTxt().Len(), aBkmkArr );
609         }
610 
611         if( pTxtNd )
612         {
613             // METADATA: restore
614             pTxtNd->GetTxtNode()->RestoreMetadata(pSave->m_pMetadataUndoStart);
615             if( pTxtNd->HasSwAttrSet() )
616                 pTxtNd->ResetAllAttr();
617 
618             if( pTxtNd->GetpSwpHints() )
619                 pTxtNd->ClearSwpHintsArr( false );
620         }
621 
622         if( pSave->m_pHstry )
623         {
624             sal_uInt16 nTmpEnd = pSave->m_pHstry->GetTmpEnd();
625             pSave->m_pHstry->TmpRollback( GetDoc(), 0 );
626             pSave->m_pHstry->SetTmpEnd( nTmpEnd );
627         }
628 
629         // METADATA: restore
630         // end points to node after cell
631         if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd )
632         {
633             SwTxtNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTxtNode();
634             if (pLastNode)
635             {
636                 pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd);
637             }
638         }
639 
640         aEndIdx = pSave->m_nEndNd;
641         SwStartNode* pSttNd = new SwStartNode( aSttIdx, ND_STARTNODE,
642                                                 SwTableBoxStartNode );
643         pSttNd->pStartOfSection = pTblNd;
644         new SwEndNode( aEndIdx, *pSttNd );
645 
646         for( sal_uLong i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i )
647         {
648             pNd = (*this)[ i ];
649             pNd->pStartOfSection = pSttNd;
650             if( pNd->IsStartNode() )
651                 i = pNd->EndOfSectionIndex();
652         }
653 
654         SwTableBox* pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
655         pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, 0 );
656     }
657     return pTblNd;
658 }
659 
660 
661 void SwUndoTblToTxt::RedoImpl(::sw::UndoRedoContext & rContext)
662 {
663     SwDoc & rDoc = rContext.GetDoc();
664     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
665 
666     pPam->GetPoint()->nNode = nSttNd;
667     pPam->GetPoint()->nContent.Assign( 0, 0 );
668     SwNodeIndex aSaveIdx( pPam->GetPoint()->nNode, -1 );
669 
670     pPam->SetMark();            // alle Indizies abmelden
671     pPam->DeleteMark();
672 
673     SwTableNode* pTblNd = pPam->GetNode()->GetTableNode();
674     ASSERT( pTblNd, "keinen TableNode gefunden" );
675 
676     if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
677         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
678                                                 GetDDEFldType()->Copy();
679 
680     rDoc.TableToText( pTblNd, cTrenner );
681 
682     aSaveIdx++;
683     SwCntntNode* pCNd = aSaveIdx.GetNode().GetCntntNode();
684     if( !pCNd && 0 == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) &&
685         0 == ( pCNd = rDoc.GetNodes().GoPrevious( &aSaveIdx )) )
686     {
687         ASSERT( sal_False, "wo steht denn nun der TextNode" );
688     }
689 
690     pPam->GetPoint()->nNode = aSaveIdx;
691     pPam->GetPoint()->nContent.Assign( pCNd, 0 );
692 
693     pPam->SetMark();            // alle Indizies abmelden
694     pPam->DeleteMark();
695 }
696 
697 
698 void SwUndoTblToTxt::RepeatImpl(::sw::RepeatContext & rContext)
699 {
700     SwPaM *const pPam = & rContext.GetRepeatPaM();
701     SwTableNode *const pTblNd = pPam->GetNode()->FindTableNode();
702     if( pTblNd )
703     {
704         // move cursor out of table
705         pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
706         pPam->Move( fnMoveForward, fnGoCntnt );
707         pPam->SetMark();
708         pPam->DeleteMark();
709 
710         rContext.GetDoc().TableToText( pTblNd, cTrenner );
711     }
712 }
713 
714 void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg )
715 {
716     nSttNd = rRg.aStart.GetIndex();
717     nEndNd = rRg.aEnd.GetIndex();
718 }
719 
720 void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, sal_uLong nNdIdx, sal_uLong nEndIdx, xub_StrLen nCntntIdx )
721 {
722     SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx );
723     pBoxSaves->Insert( pNew, pBoxSaves->Count() );
724 }
725 
726 // -----------------------------------------------------
727 
728 SwUndoTxtToTbl::SwUndoTxtToTbl( const SwPaM& rRg,
729                                 const SwInsertTableOptions& rInsTblOpts,
730                                 sal_Unicode cCh, sal_uInt16 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 )
735 {
736     if( pAFmt )
737         pAutoFmt = new SwTableAutoFmt( *pAFmt );
738 
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 );
744 }
745 
746 SwUndoTxtToTbl::~SwUndoTxtToTbl()
747 {
748     delete pDelBoxes;
749     delete pAutoFmt;
750 }
751 
752 void SwUndoTxtToTbl::UndoImpl(::sw::UndoRedoContext & rContext)
753 {
754     SwDoc & rDoc = rContext.GetDoc();
755 
756     sal_uLong nTblNd = nSttNode;
757     if( nSttCntnt )
758         ++nTblNd;       // Node wurde vorher gesplittet
759     SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd );
760     SwTableNode *const pTNd = aIdx.GetNode().GetTableNode();
761     OSL_ENSURE( pTNd, "SwUndoTxtToTbl: no TableNode" );
762 
763     RemoveIdxFromSection( rDoc, nTblNd );
764 
765     sTblNm = pTNd->GetTable().GetFrmFmt()->GetName();
766 
767     if( pHistory )
768     {
769         pHistory->TmpRollback( &rDoc, 0 );
770         pHistory->SetTmpEnd( pHistory->Count() );
771     }
772 
773     if( pDelBoxes )
774     {
775         SwTable& rTbl = pTNd->GetTable();
776         for( sal_uInt16 n = pDelBoxes->Count(); n; )
777         {
778             SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] );
779             if( pBox )
780                 ::_DeleteBox( rTbl, pBox, 0, sal_False, sal_False );
781             else {
782                 ASSERT( !this, "Wo ist die Box geblieben?" );
783             }
784         }
785     }
786 
787     SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() );
788     rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner );
789 
790     // join again at start?
791     SwPaM aPam(rDoc.GetNodes().GetEndOfContent());
792     SwPosition *const pPos = aPam.GetPoint();
793     if( nSttCntnt )
794     {
795         pPos->nNode = nTblNd;
796         pPos->nContent.Assign(pPos->nNode.GetNode().GetCntntNode(), 0);
797         if (aPam.Move(fnMoveBackward, fnGoCntnt))
798         {
799             SwNodeIndex & rIdx = aPam.GetPoint()->nNode;
800 
801             // dann die Crsr/etc. nochmal relativ verschieben
802             RemoveIdxRel( rIdx.GetIndex()+1, *pPos );
803 
804             rIdx.GetNode().GetCntntNode()->JoinNext();
805         }
806     }
807 
808     // join again at end?
809     if( bSplitEnd )
810     {
811         SwNodeIndex& rIdx = pPos->nNode;
812         rIdx = nEndNode;
813         SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode();
814         if( pTxtNd && pTxtNd->CanJoinNext() )
815         {
816             aPam.GetMark()->nContent.Assign( 0, 0 );
817             aPam.GetPoint()->nContent.Assign( 0, 0 );
818 
819             // dann die Crsr/etc. nochmal relativ verschieben
820             pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
821             RemoveIdxRel( nEndNode + 1, *pPos );
822 
823             pTxtNd->JoinNext();
824         }
825     }
826 
827     AddUndoRedoPaM(rContext);
828 }
829 
830 
831 void SwUndoTxtToTbl::RedoImpl(::sw::UndoRedoContext & rContext)
832 {
833     SwPaM & rPam( AddUndoRedoPaM(rContext) );
834     RemoveIdxFromRange(rPam, false);
835     SetPaM(rPam);
836 
837     SwTable const*const pTable = rContext.GetDoc().TextToTable(
838                 aInsTblOpts, rPam, cTrenner, nAdjust, pAutoFmt );
839     ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm );
840 }
841 
842 
843 void SwUndoTxtToTbl::RepeatImpl(::sw::RepeatContext & rContext)
844 {
845     // no Table In Table
846     if (!rContext.GetRepeatPaM().GetNode()->FindTableNode())
847     {
848         rContext.GetDoc().TextToTable( aInsTblOpts, rContext.GetRepeatPaM(),
849                                         cTrenner, nAdjust,
850                                         pAutoFmt );
851     }
852 }
853 
854 void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox )
855 {
856     if( !pDelBoxes )
857         pDelBoxes = new SvULongs;
858     pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() );
859 }
860 
861 SwHistory& SwUndoTxtToTbl::GetHistory()
862 {
863     if( !pHistory )
864         pHistory = new SwHistory;
865     return *pHistory;
866 }
867 
868 // -----------------------------------------------------
869 
870 SwUndoTblHeadline::SwUndoTblHeadline( const SwTable& rTbl, sal_uInt16 nOldHdl,
871                                       sal_uInt16 nNewHdl )
872     : SwUndo( UNDO_TABLEHEADLINE ),
873     nOldHeadline( nOldHdl ),
874     nNewHeadline( nNewHdl )
875 {
876     ASSERT( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" );
877     const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd();
878     ASSERT( pSttNd, "Box ohne Inhalt" );
879 
880     nTblNd = pSttNd->StartOfSectionIndex();
881 }
882 
883 void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext)
884 {
885     SwDoc & rDoc = rContext.GetDoc();
886     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
887     ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
888 
889     rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline );
890 }
891 
892 void SwUndoTblHeadline::RedoImpl(::sw::UndoRedoContext & rContext)
893 {
894     SwDoc & rDoc = rContext.GetDoc();
895 
896     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
897     ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
898 
899     rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline );
900 }
901 
902 void SwUndoTblHeadline::RepeatImpl(::sw::RepeatContext & rContext)
903 {
904     SwTableNode *const pTblNd =
905         rContext.GetRepeatPaM().GetNode()->FindTableNode();
906     if( pTblNd )
907     {
908         rContext.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline );
909     }
910 }
911 
912 
913 //////////////////////////////////////////////////////////////////////////
914 
915 
916 _SaveTable::_SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt, sal_Bool bSaveFml )
917     : aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ),
918     pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml )
919 {
920     bModifyBox = sal_False;
921     bNewModel = rTbl.IsNewModel();
922     aTblSet.Put( rTbl.GetFrmFmt()->GetAttrSet() );
923     pLine = new _SaveLine( 0, *rTbl.GetTabLines()[ 0 ], *this );
924 
925     _SaveLine* pLn = pLine;
926     if( USHRT_MAX == nLnCnt )
927         nLnCnt = rTbl.GetTabLines().Count();
928     for( sal_uInt16 n = 1; n < nLnCnt; ++n )
929         pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this );
930 
931     aFrmFmts.Remove( 0, aFrmFmts.Count() );
932     pSwTable = 0;
933 }
934 
935 
936 _SaveTable::~_SaveTable()
937 {
938     delete pLine;
939 }
940 
941 
942 sal_uInt16 _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine )
943 {
944     sal_uInt16 nRet = aFrmFmts.GetPos( pFmt );
945     if( USHRT_MAX == nRet )
946     {
947         // Kopie vom ItemSet anlegen
948         SfxItemSet* pSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
949             bIsLine ? aTableLineSetRange : aTableBoxSetRange );
950         pSet->Put( pFmt->GetAttrSet() );
951         //JP 20.04.98: Bug 49502 - wenn eine Formel gesetzt ist, nie den
952         //              Value mit sichern. Der muss gegebenfalls neu
953         //              errechnet werden!
954         //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern
955         const SfxPoolItem* pItem;
956         if( SFX_ITEM_SET == pSet->GetItemState( RES_BOXATR_FORMULA, sal_True, &pItem ))
957         {
958             pSet->ClearItem( RES_BOXATR_VALUE );
959             if( pSwTable && bSaveFormula )
960             {
961                 SwTableFmlUpdate aMsgHnt( pSwTable );
962                 aMsgHnt.eFlags = TBL_BOXNAME;
963                 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( pFmt );
964                 ((SwTblBoxFormula*)pItem)->ChangeState( &aMsgHnt );
965                 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( 0 );
966             }
967         }
968         aSets.Insert( pSet, (nRet = aSets.Count() ) );
969         aFrmFmts.Insert( pFmt, nRet );
970     }
971     return nRet;
972 }
973 
974 
975 void _SaveTable::RestoreAttr( SwTable& rTbl, sal_Bool bMdfyBox )
976 {
977     sal_uInt16 n;
978 
979     bModifyBox = bMdfyBox;
980 
981     // zuerst die Attribute des TabellenFrmFormates zurueck holen
982     SwFrmFmt* pFmt = rTbl.GetFrmFmt();
983     SfxItemSet& rFmtSet  = (SfxItemSet&)pFmt->GetAttrSet();
984     rFmtSet.ClearItem();
985     rFmtSet.Put( aTblSet );
986 
987     if( pFmt->IsInCache() )
988     {
989         SwFrm::GetCache().Delete( pFmt );
990         pFmt->SetInCache( sal_False );
991     }
992 
993     // zur Sicherheit alle Tableframes invalidieren
994     SwIterator<SwTabFrm,SwFmt> aIter( *pFmt );
995     for( SwTabFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
996         if( pLast->GetTable() == &rTbl )
997         {
998             pLast->InvalidateAll();
999             pLast->SetCompletePaint();
1000         }
1001 
1002     // FrmFmts mit Defaults (0) fuellen
1003     pFmt = 0;
1004     for( n = aSets.Count(); n; --n )
1005         aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1006 
1007     sal_uInt16 nLnCnt = nLineCount;
1008     if( USHRT_MAX == nLnCnt )
1009         nLnCnt = rTbl.GetTabLines().Count();
1010 
1011     _SaveLine* pLn = pLine;
1012     for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext )
1013     {
1014         if( !pLn )
1015         {
1016             ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1017             break;
1018         }
1019 
1020         pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this );
1021     }
1022 
1023     aFrmFmts.Remove( 0, aFrmFmts.Count() );
1024     bModifyBox = sal_False;
1025 }
1026 
1027 
1028 void _SaveTable::SaveCntntAttrs( SwDoc* pDoc )
1029 {
1030     pLine->SaveCntntAttrs( pDoc );
1031 }
1032 
1033 
1034 void _SaveTable::CreateNew( SwTable& rTbl, sal_Bool bCreateFrms,
1035                             sal_Bool bRestoreChart )
1036 {
1037     sal_uInt16 n;
1038 
1039     _FndBox aTmpBox( 0, 0 );
1040     //if( bRestoreChart )
1041     //    // ? TL_CHART2: notification or locking of controller required ?
1042     aTmpBox.DelFrms( rTbl );
1043 
1044     // zuerst die Attribute des TabellenFrmFormates zurueck holen
1045     SwFrmFmt* pFmt = rTbl.GetFrmFmt();
1046     SfxItemSet& rFmtSet  = (SfxItemSet&)pFmt->GetAttrSet();
1047     rFmtSet.ClearItem();
1048     rFmtSet.Put( aTblSet );
1049 
1050     if( pFmt->IsInCache() )
1051     {
1052         SwFrm::GetCache().Delete( pFmt );
1053         pFmt->SetInCache( sal_False );
1054     }
1055 
1056     // SwTableBox muss ein Format haben!!
1057     SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().Count(), 0 );
1058 
1059     // FrmFmts mit Defaults (0) fuellen
1060     pFmt = 0;
1061     for( n = aSets.Count(); n; --n )
1062         aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1063 
1064     pLine->CreateNew( rTbl, aParent, *this );
1065     aFrmFmts.Remove( 0, aFrmFmts.Count() );
1066 
1067     // die neuen Lines eintragen, die alten loeschen
1068     sal_uInt16 nOldLines = nLineCount;
1069     if( USHRT_MAX == nLineCount )
1070         nOldLines = rTbl.GetTabLines().Count();
1071 
1072     SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc();
1073     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
1074     for( n = 0; n < aParent.GetTabLines().Count(); ++n )
1075     {
1076         SwTableLine* pLn = aParent.GetTabLines()[ n ];
1077         pLn->SetUpper( 0 );
1078         if( n < nOldLines )
1079         {
1080             SwTableLine* pOld = rTbl.GetTabLines()[ n ];
1081 
1082             // TL_CHART2: notify chart about boxes to be removed
1083             const SwTableBoxes &rBoxes = pOld->GetTabBoxes();
1084             sal_uInt16 nBoxes = rBoxes.Count();
1085             for (sal_uInt16 k = 0;  k < nBoxes;  ++k)
1086             {
1087                 SwTableBox *pBox = rBoxes[k];
1088                 if (pPCD)
1089                     pPCD->DeleteBox( &rTbl, *pBox );
1090             }
1091 
1092             rTbl.GetTabLines().C40_REPLACE( SwTableLine, pLn, n );
1093             delete pOld;
1094         }
1095         else
1096             rTbl.GetTabLines().C40_INSERT( SwTableLine, pLn, n );
1097     }
1098 
1099     if( n < nOldLines )
1100     {
1101         // remove remaining lines...
1102 
1103         for (sal_uInt16 k1 = 0; k1 < nOldLines - n;  ++k1)
1104         {
1105             const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes();
1106             sal_uInt16 nBoxes = rBoxes.Count();
1107             for (sal_uInt16 k2 = 0;  k2 < nBoxes;  ++k2)
1108             {
1109                 SwTableBox *pBox = rBoxes[k2];
1110                 // TL_CHART2: notify chart about boxes to be removed
1111                 if (pPCD)
1112                     pPCD->DeleteBox( &rTbl, *pBox );
1113             }
1114         }
1115 
1116         rTbl.GetTabLines().DeleteAndDestroy( n, nOldLines - n );
1117     }
1118 
1119     aParent.GetTabLines().Remove( 0, n );
1120 
1121     if( bCreateFrms )
1122         aTmpBox.MakeFrms( rTbl );
1123     if( bRestoreChart )
1124     {
1125         // TL_CHART2: need to inform chart of probably changed cell names
1126         pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
1127     }
1128 }
1129 
1130 
1131 void _SaveTable::NewFrmFmt( const SwTableLine* pTblLn, const SwTableBox* pTblBx,
1132                             sal_uInt16 nFmtPos, SwFrmFmt* pOldFmt )
1133 {
1134     SwDoc* pDoc = pOldFmt->GetDoc();
1135 
1136     SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ];
1137     if( !pFmt )
1138     {
1139         if( pTblLn )
1140             pFmt = pDoc->MakeTableLineFmt();
1141         else
1142             pFmt = pDoc->MakeTableBoxFmt();
1143         pFmt->SetFmtAttr( *aSets[ nFmtPos ] );
1144         aFrmFmts.Replace( pFmt, nFmtPos );
1145     }
1146 
1147     //Erstmal die Frms ummelden.
1148     SwIterator<SwTabFrm,SwFmt> aIter( *pOldFmt );
1149     for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1150     {
1151         if( pTblLn ? ((SwRowFrm*)pLast)->GetTabLine() == pTblLn
1152                     : ((SwCellFrm*)pLast)->GetTabBox() == pTblBx )
1153         {
1154             pLast->RegisterToFormat(*pFmt);
1155             pLast->InvalidateAll();
1156             pLast->ReinitializeFrmSizeAttrFlags();
1157             if ( !pTblLn )
1158             {
1159                 ((SwCellFrm*)pLast)->SetDerivedVert( sal_False );
1160                 ((SwCellFrm*)pLast)->CheckDirChange();
1161             }
1162         }
1163     }
1164 
1165     //Jetzt noch mich selbst ummelden.
1166     if ( pTblLn )
1167         const_cast<SwTableLine*>(pTblLn)->RegisterToFormat( *pFmt );
1168     else if ( pTblBx )
1169         const_cast<SwTableBox*>(pTblBx)->RegisterToFormat( *pFmt );
1170 
1171     if( bModifyBox && !pTblLn )
1172     {
1173         const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ),
1174                          & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT );
1175         if( rOld != rNew )
1176             pFmt->ModifyNotification( (SfxPoolItem*)&rOld, (SfxPoolItem*)&rNew );
1177     }
1178 
1179     if( !pOldFmt->GetDepends() )
1180         delete pOldFmt;
1181 
1182 }
1183 
1184 
1185 _SaveLine::_SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl )
1186     : pNext( 0 )
1187 {
1188     if( pPrev )
1189         pPrev->pNext = this;
1190 
1191     nItemSet = rSTbl.AddFmt( rLine.GetFrmFmt(), true );
1192 
1193     pBox = new _SaveBox( 0, *rLine.GetTabBoxes()[ 0 ], rSTbl );
1194     _SaveBox* pBx = pBox;
1195     for( sal_uInt16 n = 1; n < rLine.GetTabBoxes().Count(); ++n )
1196         pBx = new _SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTbl );
1197 }
1198 
1199 
1200 _SaveLine::~_SaveLine()
1201 {
1202     delete pBox;
1203     delete pNext;
1204 }
1205 
1206 
1207 void _SaveLine::RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl )
1208 {
1209     rSTbl.NewFrmFmt( &rLine, 0, nItemSet, rLine.GetFrmFmt() );
1210 
1211     _SaveBox* pBx = pBox;
1212     for( sal_uInt16 n = 0; n < rLine.GetTabBoxes().Count(); ++n, pBx = pBx->pNext )
1213     {
1214         if( !pBx )
1215         {
1216             ASSERT( !this, "Anzahl der Boxen hat sich veraendert" );
1217             break;
1218         }
1219         pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl );
1220     }
1221 }
1222 
1223 
1224 void _SaveLine::SaveCntntAttrs( SwDoc* pDoc )
1225 {
1226     pBox->SaveCntntAttrs( pDoc );
1227     if( pNext )
1228         pNext->SaveCntntAttrs( pDoc );
1229 }
1230 
1231 
1232 void _SaveLine::CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl )
1233 {
1234     SwTableLineFmt* pFmt = (SwTableLineFmt*)rSTbl.aFrmFmts[ nItemSet ];
1235     if( !pFmt )
1236     {
1237         SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1238         pFmt = pDoc->MakeTableLineFmt();
1239         pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1240         rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1241     }
1242     SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent );
1243 
1244     rParent.GetTabLines().C40_INSERT( SwTableLine, pNew, rParent.GetTabLines().Count() );
1245 
1246     // HB, #127868# robustness: in some cases - which I
1247     // cannot reproduce nor see from the code - pNew seems
1248     // to be set to NULL in C40_INSERT.
1249     ASSERT(pNew, "Table line just created set to NULL in C40_INSERT");
1250 
1251     if (pNew)
1252     {
1253         pBox->CreateNew( rTbl, *pNew, rSTbl );
1254     }
1255 
1256     if( pNext )
1257         pNext->CreateNew( rTbl, rParent, rSTbl );
1258 }
1259 
1260 
1261 _SaveBox::_SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl )
1262     : pNext( 0 ), nSttNode( ULONG_MAX ), nRowSpan(0)
1263 {
1264     Ptrs.pLine = 0;
1265 
1266     if( pPrev )
1267         pPrev->pNext = this;
1268 
1269     nItemSet = rSTbl.AddFmt( rBox.GetFrmFmt(), false );
1270 
1271     if( rBox.GetSttNd() )
1272     {
1273         nSttNode = rBox.GetSttIdx();
1274         nRowSpan = rBox.getRowSpan();
1275     }
1276     else
1277     {
1278         Ptrs.pLine = new _SaveLine( 0, *rBox.GetTabLines()[ 0 ], rSTbl );
1279 
1280         _SaveLine* pLn = Ptrs.pLine;
1281         for( sal_uInt16 n = 1; n < rBox.GetTabLines().Count(); ++n )
1282             pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl );
1283     }
1284 }
1285 
1286 
1287 _SaveBox::~_SaveBox()
1288 {
1289     if( ULONG_MAX == nSttNode )     // keine EndBox
1290         delete Ptrs.pLine;
1291     else
1292         delete Ptrs.pCntntAttrs;
1293     delete pNext;
1294 }
1295 
1296 
1297 void _SaveBox::RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl )
1298 {
1299     rSTbl.NewFrmFmt( 0, &rBox, nItemSet, rBox.GetFrmFmt() );
1300 
1301     if( ULONG_MAX == nSttNode )     // keine EndBox
1302     {
1303         if( !rBox.GetTabLines().Count() )
1304         {
1305             ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1306         }
1307         else
1308         {
1309             _SaveLine* pLn = Ptrs.pLine;
1310             for( sal_uInt16 n = 0; n < rBox.GetTabLines().Count(); ++n, pLn = pLn->pNext )
1311             {
1312                 if( !pLn )
1313                 {
1314                     ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1315                     break;
1316                 }
1317 
1318                 pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTbl );
1319             }
1320         }
1321     }
1322     else if( rBox.GetSttNd() && rBox.GetSttIdx() == nSttNode )
1323     {
1324         if( Ptrs.pCntntAttrs )
1325         {
1326             SwNodes& rNds = rBox.GetFrmFmt()->GetDoc()->GetNodes();
1327             sal_uInt16 nSet = 0;
1328             sal_uLong nEnd = rBox.GetSttNd()->EndOfSectionIndex();
1329             for( sal_uLong n = nSttNode + 1; n < nEnd; ++n )
1330             {
1331                 SwCntntNode* pCNd = rNds[ n ]->GetCntntNode();
1332                 if( pCNd )
1333                 {
1334                     SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ];
1335                     if( pSet )
1336                     {
1337                         sal_uInt16 *pRstAttr = aSave_BoxCntntSet;
1338                         while( *pRstAttr )
1339                         {
1340                             pCNd->ResetAttr( *pRstAttr, *(pRstAttr+1) );
1341                             pRstAttr += 2;
1342                         }
1343                         pCNd->SetAttr( *pSet );
1344                     }
1345                     else
1346                         pCNd->ResetAllAttr();
1347                 }
1348             }
1349         }
1350     }
1351     else
1352     {
1353         ASSERT( !this, "Box nicht mehr am gleichen Node" );
1354     }
1355 }
1356 
1357 
1358 void _SaveBox::SaveCntntAttrs( SwDoc* pDoc )
1359 {
1360     if( ULONG_MAX == nSttNode )     // keine EndBox
1361     {
1362         // weiter in der Line
1363         Ptrs.pLine->SaveCntntAttrs( pDoc );
1364     }
1365     else
1366     {
1367         sal_uLong nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex();
1368         Ptrs.pCntntAttrs = new SfxItemSets( (sal_uInt8)(nEnd - nSttNode - 1 ), 5 );
1369         for( sal_uLong n = nSttNode + 1; n < nEnd; ++n )
1370         {
1371             SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode();
1372             if( pCNd )
1373             {
1374                 SfxItemSet* pSet = 0;
1375                 if( pCNd->HasSwAttrSet() )
1376                 {
1377                     pSet = new SfxItemSet( pDoc->GetAttrPool(),
1378                                             aSave_BoxCntntSet );
1379                     pSet->Put( *pCNd->GetpSwAttrSet() );
1380                 }
1381 
1382                 Ptrs.pCntntAttrs->Insert( pSet, Ptrs.pCntntAttrs->Count() );
1383             }
1384         }
1385     }
1386     if( pNext )
1387         pNext->SaveCntntAttrs( pDoc );
1388 }
1389 
1390 
1391 void _SaveBox::CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl )
1392 {
1393     SwTableBoxFmt* pFmt = (SwTableBoxFmt*)rSTbl.aFrmFmts[ nItemSet ];
1394     if( !pFmt )
1395     {
1396         SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1397         pFmt = pDoc->MakeTableBoxFmt();
1398         pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1399         rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1400     }
1401 
1402     if( ULONG_MAX == nSttNode )     // keine EndBox
1403     {
1404         SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent );
1405         rParent.GetTabBoxes().C40_INSERT( SwTableBox, pNew, rParent.GetTabBoxes().Count() );
1406 
1407         Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl );
1408     }
1409     else
1410     {
1411         // Box zum StartNode in der alten Tabelle suchen
1412         SwTableBox* pBox = rTbl.GetTblBox( nSttNode );
1413         ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1414 
1415         SwFrmFmt* pOld = pBox->GetFrmFmt();
1416         pBox->RegisterToFormat( *pFmt );
1417         if( !pOld->GetDepends() )
1418             delete pOld;
1419 
1420         pBox->setRowSpan( nRowSpan );
1421 
1422         SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
1423         pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
1424 
1425         pBox->SetUpper( &rParent );
1426         pTBoxes = &rParent.GetTabBoxes();
1427         pTBoxes->C40_INSERT( SwTableBox, pBox, pTBoxes->Count() );
1428     }
1429 
1430     if( pNext )
1431         pNext->CreateNew( rTbl, rParent, rSTbl );
1432 }
1433 
1434 
1435 //////////////////////////////////////////////////////////////////////////
1436 
1437 // UndoObject fuer Attribut Aenderung an der Tabelle
1438 
1439 
1440 SwUndoAttrTbl::SwUndoAttrTbl( const SwTableNode& rTblNd, sal_Bool bClearTabCols )
1441     : SwUndo( UNDO_TABLE_ATTR ),
1442     nSttNode( rTblNd.GetIndex() )
1443 {
1444     bClearTabCol = bClearTabCols;
1445     pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1446 }
1447 
1448 SwUndoAttrTbl::~SwUndoAttrTbl()
1449 {
1450     delete pSaveTbl;
1451 }
1452 
1453 void SwUndoAttrTbl::UndoImpl(::sw::UndoRedoContext & rContext)
1454 {
1455     SwDoc & rDoc = rContext.GetDoc();
1456     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1457     ASSERT( pTblNd, "kein TabellenNode" );
1458 
1459     if (pTblNd)
1460     {
1461         _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1462         pSaveTbl->RestoreAttr( pTblNd->GetTable() );
1463         delete pSaveTbl;
1464         pSaveTbl = pOrig;
1465     }
1466 
1467     if( bClearTabCol )
1468         ClearFEShellTabCols();
1469 }
1470 
1471 void SwUndoAttrTbl::RedoImpl(::sw::UndoRedoContext & rContext)
1472 {
1473     UndoImpl(rContext);
1474 }
1475 
1476 
1477 //////////////////////////////////////////////////////////////////////////
1478 
1479 // UndoObject fuer AutoFormat an der Tabelle
1480 
1481 
1482 SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd,
1483                                     const SwTableAutoFmt& rAFmt )
1484     : SwUndo( UNDO_TABLE_AUTOFMT ),
1485     nSttNode( rTblNd.GetIndex() ),
1486     bSaveCntntAttr( sal_False )
1487 {
1488     pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1489 
1490     if( rAFmt.IsFont() || rAFmt.IsJustify() )
1491     {
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 = sal_True;
1496     }
1497 }
1498 
1499 SwUndoTblAutoFmt::~SwUndoTblAutoFmt()
1500 {
1501     delete pSaveTbl;
1502 }
1503 
1504 void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox )
1505 {
1506     ::boost::shared_ptr<SwUndoTblNumFmt> const p(new SwUndoTblNumFmt(rBox));
1507     m_Undos.push_back(p);
1508 }
1509 
1510 
1511 void
1512 SwUndoTblAutoFmt::UndoRedo(bool const bUndo, ::sw::UndoRedoContext & rContext)
1513 {
1514     SwDoc & rDoc = rContext.GetDoc();
1515     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1516     ASSERT( pTblNd, "kein TabellenNode" );
1517 
1518     _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1519         // dann auch noch ueber die ContentNodes der EndBoxen und
1520         // und alle Absatz-Attribute zusammen sammeln
1521     if( bSaveCntntAttr )
1522         pOrig->SaveCntntAttrs( &rDoc );
1523 
1524     if (bUndo)
1525     {
1526         for (size_t n = m_Undos.size(); 0 < n; --n)
1527         {
1528             m_Undos.at(n-1)->UndoImpl(rContext);
1529         }
1530     }
1531 
1532     pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo );
1533     delete pSaveTbl;
1534     pSaveTbl = pOrig;
1535 }
1536 
1537 void SwUndoTblAutoFmt::UndoImpl(::sw::UndoRedoContext & rContext)
1538 {
1539     UndoRedo(true, rContext);
1540 }
1541 
1542 void SwUndoTblAutoFmt::RedoImpl(::sw::UndoRedoContext & rContext)
1543 {
1544     UndoRedo(false, rContext);
1545 }
1546 
1547 
1548 //////////////////////////////////////////////////////////////////////////
1549 
1550 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1551                                     const SwSelBoxes& rBoxes,
1552                                     const SwTableNode& rTblNd,
1553                                     long nMn, long nMx,
1554                                     sal_uInt16 nCnt, sal_Bool bFlg, sal_Bool bSmHght )
1555     : SwUndo( nAction ),
1556     aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ),
1557     nMin( nMn ), nMax( nMx ),
1558     nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1559     nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ),
1560     nSetColType( USHRT_MAX ),
1561     bFlag( bFlg ),
1562     bSameHeight( bSmHght )
1563 {
1564     Ptrs.pNewSttNds = 0;
1565 
1566     const SwTable& rTbl = rTblNd.GetTable();
1567     pSaveTbl = new _SaveTable( rTbl );
1568 
1569     // und die Selektion merken
1570     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1571         aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1572 }
1573 
1574 
1575 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1576                                     const SwSelBoxes& rBoxes,
1577                                     const SwTableNode& rTblNd )
1578     : SwUndo( nAction ),
1579     aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ),
1580     nMin( 0 ), nMax( 0 ),
1581     nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1582     nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ),
1583     nSetColType( USHRT_MAX ),
1584     bFlag( sal_False ),
1585     bSameHeight( sal_False )
1586 {
1587     Ptrs.pNewSttNds = 0;
1588 
1589     const SwTable& rTbl = rTblNd.GetTable();
1590     pSaveTbl = new _SaveTable( rTbl );
1591 
1592     // und die Selektion merken
1593     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1594         aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1595 }
1596 
1597 void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes )
1598 {
1599     if( rBoxes.Count() != aBoxes.Count() )
1600     {
1601         aBoxes.Remove( 0, aBoxes.Count() );
1602         for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1603             aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1604     }
1605 }
1606 
1607 SwUndoTblNdsChg::~SwUndoTblNdsChg()
1608 {
1609     delete pSaveTbl;
1610 
1611     if( IsDelBox() )
1612         delete Ptrs.pDelSects;
1613     else
1614         delete Ptrs.pNewSttNds;
1615 }
1616 
1617 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1618                                     const SwTableSortBoxes& rOld )
1619 {
1620     const SwTable& rTbl = rTblNd.GetTable();
1621     const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1622     sal_uInt16 n;
1623     sal_uInt16 i;
1624 
1625     ASSERT( ! IsDelBox(), "falsche Action" );
1626     Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 );
1627 
1628     for( n = 0, i = 0; n < rOld.Count(); ++i )
1629     {
1630         if( rOld[ n ] == rTblBoxes[ i ] )
1631             ++n;
1632         else
1633             // neue Box: sortiert einfuegen!!
1634             InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1635     }
1636 
1637     for( ; i < rTblBoxes.Count(); ++i )
1638         // neue Box: sortiert einfuegen!!
1639         InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1640 }
1641 
1642 
1643 SwTableLine* lcl_FindTableLine( const SwTable& rTable,
1644                                 const SwTableBox& rBox )
1645 {
1646     SwTableLine* pRet = NULL;
1647     // i63949: For nested cells we have to take nLineNo - 1, too, not 0!
1648     const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != NULL ) ?
1649                                   rBox.GetUpper()->GetUpper()->GetTabLines()
1650                                 : rTable.GetTabLines();
1651     const SwTableLine* pLine = rBox.GetUpper();
1652     sal_uInt16 nLineNo = rTableLines.C40_GETPOS( SwTableLine, pLine );
1653     pRet = rTableLines[nLineNo - 1];
1654 
1655     return pRet;
1656 }
1657 
1658 const SwTableLines& lcl_FindParentLines( const SwTable& rTable,
1659                                        const SwTableBox& rBox )
1660 {
1661     const SwTableLines& rRet =
1662         ( rBox.GetUpper()->GetUpper() != NULL ) ?
1663             rBox.GetUpper()->GetUpper()->GetTabLines() :
1664             rTable.GetTabLines();
1665 
1666     return rRet;
1667 }
1668 
1669 
1670 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1671                                     const SwTableSortBoxes& rOld,
1672                                     const SwSelBoxes& rBoxes,
1673                                     const SvULongs& rNodeCnts )
1674 {
1675     const SwTable& rTbl = rTblNd.GetTable();
1676     const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1677 
1678     ASSERT( ! IsDelBox(), "falsche Action" );
1679     Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 );
1680 
1681     ASSERT( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(),
1682         "unexpected boxes" );
1683     ASSERT( rOld.Count() <= rTblBoxes.Count(), "more unexpected boxes" );
1684     for( sal_uInt16 n = 0, i = 0; i < rTblBoxes.Count(); ++i )
1685     {
1686         if( ( n < rOld.Count() ) &&
1687             ( rOld[ n ] == rTblBoxes[ i ] ) )
1688         {
1689             // box already known? Then nothing to be done.
1690             ++n;
1691         }
1692         else
1693         {
1694             // new box found: insert (obey sort order)
1695             sal_uInt16 nInsPos;
1696             const SwTableBox* pBox = rTblBoxes[ i ];
1697             InsertSort( *Ptrs.pNewSttNds, pBox->GetSttIdx(), &nInsPos );
1698 
1699             // find the source box. It must be one in rBoxes.
1700             // We found the right one if it's in the same column as pBox.
1701             // No, if more than one selected cell in the same column has been splitted,
1702             // we have to look for the nearest one (i65201)!
1703             const SwTableBox* pSourceBox = NULL;
1704             const SwTableBox* pCheckBox = NULL;
1705             const SwTableLine* pBoxLine = pBox->GetUpper();
1706             sal_uInt16 nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine);
1707             sal_uInt16 nLineNo = 0;
1708             for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
1709             {
1710                 pCheckBox = rBoxes[j];
1711                 if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() )
1712                 {
1713                     const SwTableLine* pCheckLine = pCheckBox->GetUpper();
1714                     sal_uInt16 nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ).
1715                     C40_GETPOS( SwTableLine, pCheckLine );
1716                     if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff )
1717                     {
1718                         nLineNo = nCheckLine;
1719                         pSourceBox = pCheckBox;
1720                     }
1721                 }
1722             }
1723 
1724             // find the line number difference
1725             // (to help determine bNodesMoved flag below)
1726             nLineDiff = nLineDiff - nLineNo;
1727             ASSERT( pSourceBox, "Splitted source box not found!" );
1728             // find out how many nodes the source box used to have
1729             // (to help determine bNodesMoved flag below)
1730             sal_uInt16 nNdsPos = 0;
1731             while( rBoxes[ nNdsPos ] != pSourceBox )
1732                 ++nNdsPos;
1733             sal_uLong nNodes = rNodeCnts[ nNdsPos ];
1734 
1735             // When a new table cell is created, it either gets a new
1736             // node, or it gets node(s) from elsewhere. The undo must
1737             // know, of course, and thus we must determine here just
1738             // where pBox's nodes are from:
1739             // If 1) the source box has lost nodes, and
1740             //    2) we're in the node range that got nodes
1741             // then pBox received nodes from elsewhere.
1742             // If bNodesMoved is set for pBox the undo must move the
1743             // boxes back, otherwise it must delete them.
1744             // The bNodesMoved flag is stored in a seperate array
1745             // which mirrors Ptrs.pNewSttNds, i.e. Ptrs.pNewSttNds[i]
1746             // and aMvBoxes[i] belong together.
1747             sal_Bool bNodesMoved =
1748                 ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() -
1749                               pSourceBox->GetSttIdx() ) )
1750                 && ( nNodes - 1 > nLineDiff );
1751             aMvBoxes.insert( aMvBoxes.begin() + nInsPos, bNodesMoved );
1752         }
1753     }
1754 }
1755 
1756 
1757 void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd )
1758 {
1759     ASSERT( IsDelBox(), "falsche Action" );
1760     if( !Ptrs.pDelSects )
1761         Ptrs.pDelSects = new SwUndoSaveSections( 10, 5 );
1762 
1763     SwTableNode* pTblNd = pSttNd->FindTableNode();
1764     SwUndoSaveSection* pSave = new SwUndoSaveSection;
1765     pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd ));
1766 
1767     Ptrs.pDelSects->Insert( pSave, Ptrs.pDelSects->Count() );
1768     nSttNode = pTblNd->GetIndex();
1769 }
1770 
1771 
1772 void SwUndoTblNdsChg::UndoImpl(::sw::UndoRedoContext & rContext)
1773 {
1774     SwDoc & rDoc = rContext.GetDoc();
1775     SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
1776 
1777     SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode();
1778     OSL_ENSURE( pTblNd, "SwUndoTblNdsChg: no TableNode" );
1779 
1780     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1781     aMsgHnt.eFlags = TBL_BOXPTR;
1782     rDoc.UpdateTblFlds( &aMsgHnt );
1783 
1784     CHECK_TABLE( pTblNd->GetTable() )
1785 
1786     _FndBox aTmpBox( 0, 0 );
1787     // ? TL_CHART2: notification or locking of controller required ?
1788 
1789     SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
1790     std::vector< SwTableBox* > aDelBoxes;
1791     if( IsDelBox() )
1792     {
1793         // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
1794         // CreateNew werden sie korrekt verbunden.
1795         SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
1796         SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
1797 
1798         // die Sections wieder herstellen
1799         for( sal_uInt16 n = Ptrs.pDelSects->Count(); n; )
1800         {
1801             SwUndoSaveSection* pSave = (*Ptrs.pDelSects)[ --n ];
1802             pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode );
1803             if( pSave->GetHistory() )
1804                 pSave->GetHistory()->Rollback( &rDoc );
1805             SwTableBox* pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), aIdx,
1806                                                 pCpyBox->GetUpper() );
1807             rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
1808         }
1809         Ptrs.pDelSects->DeleteAndDestroy( 0, Ptrs.pDelSects->Count() );
1810     }
1811     else if( !aMvBoxes.empty() )
1812     {
1813         // dann muessen Nodes verschoben und nicht geloescht werden!
1814         // Dafuer brauchen wir aber ein temp Array
1815         SvULongs aTmp( 0, 5);
1816         aTmp.Insert( Ptrs.pNewSttNds, 0 );
1817 
1818         // von hinten anfangen
1819         for( sal_uInt16 n = aTmp.Count(); n; )
1820         {
1821             // Box aus der Tabellen-Struktur entfernen
1822             sal_uLong nIdx = aTmp[ --n ];
1823             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1824             ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1825 
1826             // TL_CHART2: notify chart about box to be removed
1827             if (pPCD)
1828                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1829 
1830             if( aMvBoxes[ n ] )
1831             {
1832                 SwNodeRange aRg( *pBox->GetSttNd(), 1,
1833                             *pBox->GetSttNd()->EndOfSectionNode() );
1834 
1835                 SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox );
1836                 SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 );
1837 
1838                 // alle StartNode Indizies anpassen
1839                 sal_uInt16 i = n;
1840                 sal_uLong nSttIdx = aInsPos.GetIndex() - 2,
1841                        nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
1842                 while( i && aTmp[ --i ] > nSttIdx )
1843                     aTmp[ i ] += nNdCnt;
1844 
1845                 // erst die Box loeschen
1846                 delete pBox;
1847                 // dann die Nodes verschieben,
1848                 rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, sal_False );
1849             }
1850             else
1851                 rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1852             aDelBoxes.insert( aDelBoxes.end(), pBox );
1853         }
1854     }
1855     else
1856     {
1857         // Remove nodes from nodes array (backwards!)
1858         for( sal_uInt16 n = Ptrs.pNewSttNds->Count(); n; )
1859         {
1860             sal_uLong nIdx = (*Ptrs.pNewSttNds)[ --n ];
1861             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1862             ASSERT( pBox, "Where's my table box?" );
1863             // TL_CHART2: notify chart about box to be removed
1864             if (pPCD)
1865                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1866             aDelBoxes.insert( aDelBoxes.end(), pBox );
1867             rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1868         }
1869     }
1870     // Remove boxes from table structure
1871     for( sal_uInt16 n = 0; n < aDelBoxes.size(); ++n )
1872     {
1873         SwTableBox* pCurrBox = aDelBoxes[n];
1874         SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes();
1875         pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pCurrBox ) );
1876         delete pCurrBox;
1877     }
1878 
1879     pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False );
1880 
1881     // TL_CHART2: need to inform chart of probably changed cell names
1882     rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
1883 
1884     if( IsDelBox() )
1885         nSttNode = pTblNd->GetIndex();
1886     ClearFEShellTabCols();
1887     CHECK_TABLE( pTblNd->GetTable() )
1888 }
1889 
1890 
1891 void SwUndoTblNdsChg::RedoImpl(::sw::UndoRedoContext & rContext)
1892 {
1893     SwDoc & rDoc = rContext.GetDoc();
1894 
1895     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1896     ASSERT( pTblNd, "kein TabellenNode" );
1897     CHECK_TABLE( pTblNd->GetTable() )
1898 
1899     SwSelBoxes aSelBoxes;
1900     for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n )
1901     {
1902         SwTableBox* pBox = pTblNd->GetTable().GetTblBox( aBoxes[ n ] );
1903         aSelBoxes.Insert( pBox );
1904     }
1905 
1906     // SelBoxes erzeugen und InsertCell/-Row/SplitTbl aufrufen
1907     switch( GetId() )
1908     {
1909     case UNDO_TABLE_INSCOL:
1910         if( USHRT_MAX == nSetColType )
1911             rDoc.InsertCol( aSelBoxes, nCount, bFlag );
1912         else
1913         {
1914             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nCurrBox );
1915             rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff,
1916                                         nRelDiff );
1917         }
1918         break;
1919 
1920     case UNDO_TABLE_INSROW:
1921         if( USHRT_MAX == nSetColType )
1922             rDoc.InsertRow( aSelBoxes, nCount, bFlag );
1923         else
1924         {
1925             SwTable& rTbl = pTblNd->GetTable();
1926             SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1927             TblChgMode eOldMode = rTbl.GetTblChgMode();
1928             rTbl.SetTblChgMode( (TblChgMode)nCount );
1929             rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, nRelDiff );
1930             rTbl.SetTblChgMode( eOldMode );
1931         }
1932         break;
1933 
1934     case UNDO_TABLE_SPLIT:
1935         rDoc.SplitTbl( aSelBoxes, bFlag, nCount, bSameHeight );
1936         break;
1937     case UNDO_TABLE_DELBOX:
1938     case UNDO_ROW_DELETE:
1939     case UNDO_COL_DELETE:
1940         if( USHRT_MAX == nSetColType )
1941         {
1942             SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1943             aMsgHnt.eFlags = TBL_BOXPTR;
1944             rDoc.UpdateTblFlds( &aMsgHnt );
1945             SwTable &rTable = pTblNd->GetTable();
1946             if( nMax > nMin && rTable.IsNewModel() )
1947                 rTable.PrepareDeleteCol( nMin, nMax );
1948             rTable.DeleteSel( &rDoc, aSelBoxes, 0, this, sal_True, sal_True );
1949         }
1950         else
1951         {
1952             SwTable& rTbl = pTblNd->GetTable();
1953 
1954             SwTableFmlUpdate aMsgHnt( &rTbl );
1955             aMsgHnt.eFlags = TBL_BOXPTR;
1956             rDoc.UpdateTblFlds( &aMsgHnt );
1957 
1958             SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1959             TblChgMode eOldMode = rTbl.GetTblChgMode();
1960             rTbl.SetTblChgMode( (TblChgMode)nCount );
1961 
1962             // need the SaveSections!
1963             rDoc.GetIDocumentUndoRedo().DoUndo( true );
1964             SwUndoTblNdsChg* pUndo = 0;
1965 
1966             switch( nSetColType & 0xff )
1967             {
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;
1982             }
1983 
1984             if( pUndo )
1985             {
1986                 Ptrs.pDelSects->Insert( pUndo->Ptrs.pDelSects, 0 );
1987                 pUndo->Ptrs.pDelSects->Remove( 0, pUndo->Ptrs.pDelSects->Count() );
1988 
1989                 delete pUndo;
1990             }
1991             rDoc.GetIDocumentUndoRedo().DoUndo( false );
1992 
1993             rTbl.SetTblChgMode( eOldMode );
1994         }
1995         nSttNode = pTblNd->GetIndex();
1996         break;
1997     default:
1998         ;
1999     }
2000     ClearFEShellTabCols();
2001     CHECK_TABLE( pTblNd->GetTable() )
2002 }
2003 
2004 
2005 //////////////////////////////////////////////////////////////////////////
2006 
2007 SwUndoTblMerge::SwUndoTblMerge( const SwPaM& rTblSel )
2008     : SwUndo( UNDO_TABLE_MERGE ), SwUndRng( rTblSel ), pHistory( 0 )
2009 {
2010     const SwTableNode* pTblNd = rTblSel.GetNode()->FindTableNode();
2011     ASSERT( pTblNd, "Wo ist TabllenNode" )
2012     pSaveTbl = new _SaveTable( pTblNd->GetTable() );
2013     pMoves = new SwUndoMoves;
2014     nTblNode = pTblNd->GetIndex();
2015 }
2016 
2017 SwUndoTblMerge::~SwUndoTblMerge()
2018 {
2019     delete pSaveTbl;
2020     delete pMoves;
2021     delete pHistory;
2022 }
2023 
2024 void SwUndoTblMerge::UndoImpl(::sw::UndoRedoContext & rContext)
2025 {
2026     SwDoc & rDoc = rContext.GetDoc();
2027     SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode );
2028 
2029     SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode();
2030     OSL_ENSURE( pTblNd, "SwUndoTblMerge: no TableNode" );
2031 
2032     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2033     aMsgHnt.eFlags = TBL_BOXPTR;
2034     rDoc.UpdateTblFlds( &aMsgHnt );
2035 
2036     _FndBox aTmpBox( 0, 0 );
2037     // ? TL_CHART2: notification or locking of controller required ?
2038 
2039 
2040     // 1. die geloeschten Boxen wiederherstellen:
2041 
2042     // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
2043     // CreateNew werden sie korrekt verbunden.
2044     SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
2045     SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
2046 
2047 DUMPDOC( &rDoc, "d:\\tmp\\tab_a.db" )
2048 CHECKTABLE(pTblNd->GetTable())
2049 
2050     SwSelBoxes aSelBoxes;
2051     SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD );
2052     sal_uInt16 n;
2053 
2054     for( n = 0; n < aBoxes.Count(); ++n )
2055     {
2056         aIdx = aBoxes[ n ];
2057         SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx,
2058                                             SwTableBoxStartNode, pColl );
2059         pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd,
2060                                 pCpyBox->GetUpper() );
2061         rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
2062 
2063         aSelBoxes.Insert( pBox );
2064     }
2065 
2066 DUMPDOC( &rDoc, "d:\\tmp\\tab_b.db" )
2067 CHECKTABLE(pTblNd->GetTable())
2068 
2069     SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
2070     // 2. die eingefuegten Boxen loeschen
2071     // die Nodes loeschen (von Hinten!!)
2072     for( n = aNewSttNds.Count(); n; )
2073     {
2074         // Box aus der Tabellen-Struktur entfernen
2075         sal_uLong nIdx = aNewSttNds[ --n ];
2076 
2077         if( !nIdx && n )
2078         {
2079             nIdx = aNewSttNds[ --n ];
2080             pBox = pTblNd->GetTable().GetTblBox( nIdx );
2081             ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
2082 
2083             if( !pSaveTbl->IsNewModel() )
2084                 rDoc.GetNodes().MakeTxtNode( SwNodeIndex(
2085                     *pBox->GetSttNd()->EndOfSectionNode() ), pColl );
2086 
2087             // das war der Trenner, -> die verschobenen herstellen
2088             for( sal_uInt16 i = pMoves->Count(); i; )
2089             {
2090                 SwTxtNode* pTxtNd = 0;
2091                 sal_uInt16 nDelPos = 0;
2092                 SwUndoMove* pUndo = (*pMoves)[ --i ];
2093                 if( !pUndo->IsMoveRange() )
2094                 {
2095                     pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode();
2096                     nDelPos = pUndo->GetDestSttCntnt() - 1;
2097                 }
2098                 pUndo->UndoImpl(rContext);
2099                 if( pUndo->IsMoveRange() )
2100                 {
2101                     // den ueberfluessigen Node loeschen
2102                     aIdx = pUndo->GetEndNode();
2103                     SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode();
2104                     if( pCNd )
2105                     {
2106                         SwNodeIndex aTmp( aIdx, -1 );
2107                         SwCntntNode *pMove = aTmp.GetNode().GetCntntNode();
2108                         if( pMove )
2109                             pCNd->MoveTo( *pMove );
2110                     }
2111                     rDoc.GetNodes().Delete( aIdx, 1 );
2112                 }
2113                 else if( pTxtNd )
2114                 {
2115                     // evt. noch ueberflussige Attribute loeschen
2116                     SwIndex aTmpIdx( pTxtNd, nDelPos );
2117                     if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
2118                         pTxtNd->RstAttr( aTmpIdx, pTxtNd->GetTxt().Len() -
2119                                                             nDelPos + 1 );
2120                     // das Trennzeichen loeschen
2121                     pTxtNd->EraseText( aTmpIdx, 1 );
2122                 }
2123 //              delete pUndo;
2124 DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) +
2125                 String(".db") )
2126             }
2127 //          pMoves->Remove( 0, pMoves->Count() );
2128             nIdx = pBox->GetSttIdx();
2129         }
2130         else
2131             pBox = pTblNd->GetTable().GetTblBox( nIdx );
2132 
2133         if( !pSaveTbl->IsNewModel() )
2134         {
2135             // TL_CHART2: notify chart about box to be removed
2136             if (pPCD)
2137                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
2138 
2139             SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
2140             pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
2141 
2142 
2143             // Indizies aus dem Bereich loeschen
2144             {
2145                 SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
2146                 rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ),
2147                             SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ),
2148                             SwPosition( aTmpIdx, SwIndex( 0, 0 )), sal_True );
2149             }
2150 
2151             delete pBox;
2152             rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
2153         }
2154     }
2155 DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" )
2156 CHECKTABLE(pTblNd->GetTable())
2157 
2158 
2159     pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False );
2160 
2161     // TL_CHART2: need to inform chart of probably changed cell names
2162     rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
2163 
2164     if( pHistory )
2165     {
2166         pHistory->TmpRollback( &rDoc, 0 );
2167         pHistory->SetTmpEnd( pHistory->Count() );
2168     }
2169 //  nTblNode = pTblNd->GetIndex();
2170 
2171     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2172     pPam->DeleteMark();
2173     pPam->GetPoint()->nNode = nSttNode;
2174     pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt );
2175     pPam->SetMark();
2176     pPam->DeleteMark();
2177 
2178 CHECKTABLE(pTblNd->GetTable())
2179     ClearFEShellTabCols();
2180 }
2181 
2182 void SwUndoTblMerge::RedoImpl(::sw::UndoRedoContext & rContext)
2183 {
2184     SwDoc & rDoc = rContext.GetDoc();
2185     SwPaM & rPam( AddUndoRedoPaM(rContext) );
2186     rDoc.MergeTbl(rPam);
2187 }
2188 
2189 void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos )
2190 {
2191     SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 );
2192     SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos );
2193     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
2194     pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ?
2195         IDocumentContentOperations::DOC_NO_DELFRMS :
2196         IDocumentContentOperations::DOC_MOVEDEFAULT );
2197     aTmp++;
2198     aTmp2++;
2199     pUndo->SetDestRange( aTmp2, rPos, aTmp );
2200 
2201     pMoves->Insert( pUndo, pMoves->Count() );
2202 }
2203 
2204 void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
2205 {
2206     // die Selektion merken
2207     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2208         InsertSort( aBoxes, rBoxes[n]->GetSttIdx() );
2209 
2210     // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben!
2211     aNewSttNds.Insert( (sal_uLong)0, aNewSttNds.Count() );
2212 
2213      // The new table model does not delete overlapped cells (by row span),
2214      // so the rBoxes array might be empty even some cells have been merged.
2215     if( rBoxes.Count() )
2216         nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex();
2217 }
2218 
2219 void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox )
2220 {
2221     if( !pHistory )
2222         pHistory = new SwHistory;
2223 
2224     SwNodeIndex aIdx( *rBox.GetSttNd(), 1 );
2225     SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
2226     if( !pCNd )
2227         pCNd = aIdx.GetNodes().GoNext( &aIdx );
2228 
2229     pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType());
2230     if( pCNd->HasSwAttrSet() )
2231         pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() );
2232 }
2233 
2234 
2235 //////////////////////////////////////////////////////////////////////////
2236 
2237 SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox,
2238                                     const SfxItemSet* pNewSet )
2239     : SwUndo( UNDO_TBLNUMFMT ),
2240     pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT )
2241 {
2242     bNewFmt = bNewFml = bNewValue = sal_False;
2243     nNode = rBox.GetSttIdx();
2244 
2245     nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet );
2246     SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2247 
2248     if( ULONG_MAX != nNdPos )
2249     {
2250         SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2251 
2252         pHistory = new SwHistory;
2253         SwRegHistory aRHst( *rBox.GetSttNd(), pHistory );
2254         // always save all text atttibutes because of possibly overlapping
2255         // areas of on/off
2256         pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0,
2257                             pTNd->GetTxt().Len(), true );
2258 
2259         if( pTNd->HasSwAttrSet() )
2260             pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos );
2261 
2262         aStr = pTNd->GetTxt();
2263         if( pTNd->GetpSwpHints() )
2264             pTNd->GetpSwpHints()->DeRegister();
2265     }
2266 
2267     pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange );
2268     pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() );
2269 
2270     if( pNewSet )
2271     {
2272         const SfxPoolItem* pItem;
2273         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT,
2274                 sal_False, &pItem ))
2275         {
2276             bNewFmt = sal_True;
2277             nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2278         }
2279         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA,
2280                 sal_False, &pItem ))
2281         {
2282             bNewFml = sal_True;
2283             aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula();
2284         }
2285         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE,
2286                 sal_False, &pItem ))
2287         {
2288             bNewValue = sal_True;
2289             fNewNum = ((SwTblBoxValue*)pItem)->GetValue();
2290         }
2291     }
2292 
2293     // wird die History ueberhaupt benoetigt ??
2294     if( pHistory && !pHistory->Count() )
2295         DELETEZ( pHistory );
2296 }
2297 
2298 SwUndoTblNumFmt::~SwUndoTblNumFmt()
2299 {
2300     delete pHistory;
2301     delete pBoxSet;
2302 }
2303 
2304 void SwUndoTblNumFmt::UndoImpl(::sw::UndoRedoContext & rContext)
2305 {
2306     ASSERT( pBoxSet, "Where's the stored item set?" )
2307 
2308     SwDoc & rDoc = rContext.GetDoc();
2309     SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]->
2310                             FindSttNodeByType( SwTableBoxStartNode );
2311     ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2312     SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2313                                     pSttNd->GetIndex() );
2314     ASSERT( pBox, "keine TabellenBox gefunden" );
2315 
2316     SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt();
2317     pFmt->SetFmtAttr( *pBoxSet );
2318     pBox->ChgFrmFmt( pFmt );
2319 
2320     if( ULONG_MAX == nNdPos )
2321         return;
2322 
2323     SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode();
2324     // wenn mehr als ein Node geloescht wurde, dann wurden auch
2325     // alle "Node"-Attribute gespeichert
2326     if( pTxtNd->HasSwAttrSet() )
2327         pTxtNd->ResetAllAttr();
2328 
2329     if( pTxtNd->GetpSwpHints() && aStr.Len() )
2330         pTxtNd->ClearSwpHintsArr( true );
2331 
2332     // ChgTextToNum(..) only acts when the strings are different. We
2333     // need to do the same here.
2334     if( pTxtNd->GetTxt() != aStr )
2335     {
2336         rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX );
2337 
2338         SwIndex aIdx( pTxtNd, 0 );
2339         if( aStr.Len() )
2340         {
2341             pTxtNd->EraseText( aIdx );
2342             pTxtNd->InsertText( aStr, aIdx,
2343                 IDocumentContentOperations::INS_NOHINTEXPAND );
2344         }
2345     }
2346 
2347     if( pHistory )
2348     {
2349         sal_uInt16 nTmpEnd = pHistory->GetTmpEnd();
2350         pHistory->TmpRollback( &rDoc, 0 );
2351         pHistory->SetTmpEnd( nTmpEnd );
2352     }
2353 
2354     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2355     pPam->DeleteMark();
2356     pPam->GetPoint()->nNode = nNode + 1;
2357     pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2358 }
2359 
2360 /** switch the RedlineMode on the given document, using
2361  * SetRedlineMode_intern. This class set the mode in the constructor,
2362  * and changes it back in the destructor, i.e. it uses the
2363  * initialization-is-resource-acquisition idiom.
2364  */
2365 class RedlineModeInternGuard
2366 {
2367     SwDoc& mrDoc;
2368     RedlineMode_t meOldRedlineMode;
2369 
2370 public:
2371     RedlineModeInternGuard(
2372         SwDoc& rDoc,                      /// change mode of this document
2373         RedlineMode_t eNewRedlineMode,    /// new redline mode
2374         RedlineMode_t eRedlineModeMask  = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/));
2375 
2376     ~RedlineModeInternGuard();
2377 };
2378 
2379 RedlineModeInternGuard::RedlineModeInternGuard(
2380     SwDoc& rDoc,
2381     RedlineMode_t eNewRedlineMode,
2382     RedlineMode_t eRedlineModeMask )
2383     : mrDoc( rDoc ),
2384       meOldRedlineMode( rDoc.GetRedlineMode() )
2385 {
2386     mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) |
2387                                      ( eNewRedlineMode & eRedlineModeMask ) ));
2388 }
2389 
2390 RedlineModeInternGuard::~RedlineModeInternGuard()
2391 {
2392     mrDoc.SetRedlineMode_intern( meOldRedlineMode );
2393 }
2394 
2395 
2396 
2397 void SwUndoTblNumFmt::RedoImpl(::sw::UndoRedoContext & rContext)
2398 {
2399     // konnte die Box veraendert werden ?
2400     if( !pBoxSet )
2401         return ;
2402 
2403     SwDoc & rDoc = rContext.GetDoc();
2404     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2405 
2406     pPam->DeleteMark();
2407     pPam->GetPoint()->nNode = nNode;
2408 
2409     SwNode * pNd = & pPam->GetPoint()->nNode.GetNode();
2410     SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode );
2411     ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2412     SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2413                                     pSttNd->GetIndex() );
2414     ASSERT( pBox, "keine TabellenBox gefunden" );
2415 
2416     SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
2417     if( bNewFmt || bNewFml || bNewValue )
2418     {
2419         SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2420                                 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2421 
2422         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2423         //              Sorge dafuer, das der Text auch entsprechend
2424         //              formatiert wird!
2425         pBoxFmt->LockModify();
2426 
2427         if( bNewFml )
2428             aBoxSet.Put( SwTblBoxFormula( aNewFml ));
2429         else
2430             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2431         if( bNewFmt )
2432             aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx ));
2433         else
2434             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2435         if( bNewValue )
2436             aBoxSet.Put( SwTblBoxValue( fNewNum ));
2437         else
2438             pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
2439         pBoxFmt->UnlockModify();
2440 
2441         // dvo: When redlining is (was) enabled, setting the attribute
2442         // will also change the cell content. To allow this, the
2443         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2444         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2445         pBoxFmt->SetFmtAttr( aBoxSet );
2446     }
2447     else if( NUMBERFORMAT_TEXT != nFmtIdx )
2448     {
2449         SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2450                             RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2451 
2452         aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
2453         aBoxSet.Put( SwTblBoxValue( fNum ));
2454 
2455         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2456         //              Sorge dafuer, das der Text auch entsprechend
2457         //              formatiert wird!
2458         pBoxFmt->LockModify();
2459         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2460         pBoxFmt->UnlockModify();
2461 
2462         // dvo: When redlining is (was) enabled, setting the attribute
2463         // will also change the cell content. To allow this, the
2464         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2465         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2466         pBoxFmt->SetFmtAttr( aBoxSet );
2467     }
2468     else
2469     {
2470         // es ist keine Zahl
2471 
2472         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2473         //              Sorge dafuer, das der Text auch entsprechend
2474         //              formatiert wird!
2475         pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
2476 
2477         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2478     }
2479 
2480     if( bNewFml )
2481     {
2482         // egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut
2483         SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() );
2484         rDoc.UpdateTblFlds( &aTblUpdate );
2485     }
2486 
2487     if( !pNd->IsCntntNode() )
2488         pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode );
2489     pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2490 }
2491 
2492 void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox )
2493 {
2494     nNode = rBox.GetSttIdx();
2495 }
2496 
2497 
2498 //////////////////////////////////////////////////////////////////////////
2499 
2500 _UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox )
2501     : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ),
2502     pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false )
2503 {
2504 }
2505 
2506 _UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry()
2507 {
2508     delete pUndo;
2509     delete pBoxNumAttr;
2510 }
2511 
2512 
2513 SwUndoTblCpyTbl::SwUndoTblCpyTbl()
2514     : SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 )
2515 {
2516     pArr = new _UndoTblCpyTbl_Entries;
2517 }
2518 
2519 SwUndoTblCpyTbl::~SwUndoTblCpyTbl()
2520 {
2521     delete pArr;
2522     delete pInsRowUndo;
2523 }
2524 
2525 void SwUndoTblCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2526 {
2527     SwDoc & rDoc = rContext.GetDoc();
2528     _DEBUG_REDLINE( &rDoc )
2529 
2530     SwTableNode* pTblNd = 0;
2531     for( sal_uInt16 n = pArr->Count(); n; )
2532     {
2533         _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ];
2534         sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2535         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2536         if( !pTblNd )
2537             pTblNd = pSNd->FindTableNode();
2538 
2539         SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2540 
2541         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2542         rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2543 
2544         // b62341295: Redline for copying tables
2545         const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode();
2546         SwPaM aPam( aInsIdx.GetNode(), *pEndNode );
2547         SwUndoDelete* pUndo = 0;
2548 
2549         if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2550         {
2551             bool bDeleteCompleteParagraph = false;
2552             bool bShiftPam = false;
2553             // There are a couple of different situations to consider during redlining
2554             if( pEntry->pUndo )
2555             {
2556                 SwUndoDelete *const pUndoDelete =
2557                     dynamic_cast<SwUndoDelete*>(pEntry->pUndo);
2558                 SwUndoRedlineDelete *const pUndoRedlineDelete =
2559                     dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo);
2560                 OSL_ASSERT(pUndoDelete || pUndoRedlineDelete);
2561                 if (pUndoRedlineDelete)
2562                 {
2563                     // The old content was not empty or he has been merged with the new content
2564                     bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged
2565                     // Set aTmpIdx to the beginning fo the old content
2566                     SwNodeIndex aTmpIdx( *pEndNode,
2567                             pUndoRedlineDelete->NodeDiff()-1 );
2568                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2569                     if( pTxt )
2570                     {
2571                         aPam.GetPoint()->nNode = *pTxt;
2572                         aPam.GetPoint()->nContent.Assign( pTxt,
2573                                 pUndoRedlineDelete->ContentStart() );
2574                     }
2575                     else
2576                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2577                 }
2578                 else if (pUndoDelete && pUndoDelete->IsDelFullPara())
2579                 {
2580                     // When the old content was an empty paragraph, but could not be joined
2581                     // with the new content (e.g. because of a section or table)
2582                     // We "save" the aPam.Point, we go one step backwards (because later on the
2583                     // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag
2584                     // for step forward later on.
2585                     bDeleteCompleteParagraph = true;
2586                     bShiftPam = true;
2587                     SwNodeIndex aTmpIdx( *pEndNode, -1 );
2588                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2589                     if( pTxt )
2590                     {
2591                         aPam.GetPoint()->nNode = *pTxt;
2592                         aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2593                     }
2594                     else
2595                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2596                 }
2597             }
2598             rDoc.DeleteRedline( aPam, true, USHRT_MAX );
2599 
2600             if( pEntry->pUndo )
2601             {
2602                 pEntry->pUndo->UndoImpl(rContext);
2603                 delete pEntry->pUndo;
2604                 pEntry->pUndo = 0;
2605             }
2606             if( bShiftPam )
2607             {
2608                 // The aPam.Point is at the moment at the last position of the new content and has to be
2609                 // moved to the first postion of the old content for the SwUndoDelete operation
2610                 SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 );
2611                 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2612                 if( pTxt )
2613                 {
2614                     aPam.GetPoint()->nNode = *pTxt;
2615                     aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2616                 }
2617                 else
2618                     *aPam.GetPoint() = SwPosition( aTmpIdx );
2619             }
2620             pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, sal_True );
2621         }
2622         else
2623         {
2624             pUndo = new SwUndoDelete( aPam, true );
2625             if( pEntry->pUndo )
2626             {
2627                 pEntry->pUndo->UndoImpl(rContext);
2628                 delete pEntry->pUndo;
2629                 pEntry->pUndo = 0;
2630             }
2631         }
2632         pEntry->pUndo = pUndo;
2633 
2634         aInsIdx = rBox.GetSttIdx() + 1;
2635         rDoc.GetNodes().Delete( aInsIdx, 1 );
2636 
2637         SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2638                                                 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2639         aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2640         if( aTmpSet.Count() )
2641         {
2642             SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2643             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2644             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2645         }
2646 
2647         if( pEntry->pBoxNumAttr )
2648         {
2649             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2650             delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2651         }
2652 
2653         if( aTmpSet.Count() )
2654         {
2655             pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2656                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2657                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2658             pEntry->pBoxNumAttr->Put( aTmpSet );
2659         }
2660 
2661         pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2662     }
2663 
2664     if( pInsRowUndo )
2665     {
2666         pInsRowUndo->UndoImpl(rContext);
2667     }
2668     _DEBUG_REDLINE( &rDoc )
2669 }
2670 
2671 void SwUndoTblCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2672 {
2673     SwDoc & rDoc = rContext.GetDoc();
2674     _DEBUG_REDLINE( &rDoc )
2675 
2676     if( pInsRowUndo )
2677     {
2678         pInsRowUndo->RedoImpl(rContext);
2679     }
2680 
2681     SwTableNode* pTblNd = 0;
2682     for( sal_uInt16 n = 0; n < pArr->Count(); ++n )
2683     {
2684         _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ];
2685         sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2686         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2687         if( !pTblNd )
2688             pTblNd = pSNd->FindTableNode();
2689 
2690         SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2691 
2692         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2693 
2694         // b62341295: Redline for copying tables - Start.
2695         rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2696         SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
2697         SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, sal_True );
2698         if( pEntry->pUndo )
2699         {
2700             pEntry->pUndo->UndoImpl(rContext);
2701             if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2702             {
2703                 // PrepareRedline has to be called with the beginning of the old content
2704                 // When new and old content has been joined, the rIter.pAktPam has been set
2705                 // by the Undo operation to this point.
2706                 // Otherwise aInsIdx has been moved during the Undo operation
2707                 if( pEntry->bJoin )
2708                 {
2709                     SwPaM const& rLastPam =
2710                         rContext.GetCursorSupplier().GetCurrentShellCursor();
2711                     pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(),
2712                                             pEntry->bJoin, true );
2713                 }
2714                 else
2715                 {
2716                     SwPosition aTmpPos( aInsIdx );
2717                     pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true );
2718                 }
2719             }
2720             delete pEntry->pUndo;
2721             pEntry->pUndo = 0;
2722         }
2723         pEntry->pUndo = pUndo;
2724         // b62341295: Redline for copying tables - End.
2725 
2726         aInsIdx = rBox.GetSttIdx() + 1;
2727         rDoc.GetNodes().Delete( aInsIdx, 1 );
2728 
2729         SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2730                                                 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2731         aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2732         if( aTmpSet.Count() )
2733         {
2734             SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2735             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2736             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2737         }
2738         if( pEntry->pBoxNumAttr )
2739         {
2740             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2741             delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2742         }
2743 
2744         if( aTmpSet.Count() )
2745         {
2746             pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2747                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2748                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2749             pEntry->pBoxNumAttr->Put( aTmpSet );
2750         }
2751 
2752         pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2753     }
2754     _DEBUG_REDLINE( &rDoc )
2755 }
2756 
2757 void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, sal_Bool bDelCntnt )
2758 {
2759     if( pArr->Count() && !bDelCntnt )
2760         return;
2761 
2762     _UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox );
2763     pArr->Insert( pEntry, pArr->Count() );
2764 
2765     SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2766     _DEBUG_REDLINE( pDoc )
2767     if( bDelCntnt )
2768     {
2769         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2770         pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
2771         SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
2772 
2773         if( !pDoc->IsRedlineOn() )
2774             pEntry->pUndo = new SwUndoDelete( aPam, sal_True );
2775     }
2776 
2777     pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(),
2778                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2779                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2780     pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() );
2781     if( !pEntry->pBoxNumAttr->Count() )
2782         delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2783     _DEBUG_REDLINE( pDoc )
2784 }
2785 
2786 void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, sal_Bool bDelCntnt )
2787 {
2788     _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ];
2789 
2790     // wurde der Inhalt geloescht, so loesche jetzt auch noch den temp.
2791     // erzeugten Node
2792     if( bDelCntnt )
2793     {
2794         SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2795         _DEBUG_REDLINE( pDoc )
2796 
2797         if( pDoc->IsRedlineOn() )
2798         {
2799             SwPosition aTmpPos( rIdx );
2800             pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false );
2801         }
2802         SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 );
2803         rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 );
2804         _DEBUG_REDLINE( pDoc )
2805     }
2806 
2807     pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2808 }
2809 
2810 // PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations.
2811 // bRedo is set by calling from Redo()
2812 // rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has
2813 // been merged.
2814 // rJoin is true if Redo() is calling and the content has already been merged
2815 
2816 SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox,
2817     const SwPosition& rPos, bool& rJoin, bool bRedo )
2818 {
2819     SwUndo *pUndo = 0;
2820     // b62341295: Redline for copying tables
2821     // What's to do?
2822     // Mark the cell content before rIdx as insertion,
2823     // mark the cell content behind rIdx as deletion
2824     // merge text nodes at rIdx if possible
2825     RedlineMode_t eOld = pDoc->GetRedlineMode();
2826     pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &
2827                                      ~nsRedlineMode_t::REDLINE_IGNORE ));
2828     SwPosition aInsertEnd( rPos );
2829     SwTxtNode* pTxt;
2830     if( !rJoin )
2831     {
2832         // If the content is not merged, the end of the insertion is at the end of the node
2833         // _before_ the given position rPos
2834         --aInsertEnd.nNode;
2835         pTxt = aInsertEnd.nNode.GetNode().GetTxtNode();
2836         if( pTxt )
2837         {
2838             aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2839             if( !bRedo && rPos.nNode.GetNode().GetTxtNode() )
2840             {   // Try to merge, if not called by Redo()
2841                 rJoin = true;
2842                 pTxt->JoinNext();
2843             }
2844         }
2845         else
2846             aInsertEnd.nContent = SwIndex( 0 );
2847     }
2848     // For joined (merged) contents the start of deletionm and end of insertion are identical
2849     // otherwise adjacent nodes.
2850     SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos );
2851     if( !rJoin )
2852     {
2853         pTxt = aDeleteStart.nNode.GetNode().GetTxtNode();
2854         if( pTxt )
2855             aDeleteStart.nContent.Assign( pTxt, 0 );
2856     }
2857     SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) );
2858     pTxt = aCellEnd.nNode.GetNode().GetTxtNode();
2859     if( pTxt )
2860         aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2861     if( aDeleteStart != aCellEnd )
2862     {   // If the old (deleted) part is not empty, here we are...
2863         SwPaM aDeletePam( aDeleteStart, aCellEnd );
2864         pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE );
2865         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true );
2866     }
2867     else if( !rJoin ) // If the old part is empty and joined, we are finished
2868     {   // if it is not joined, we have to delete this empty paragraph
2869         aCellEnd = SwPosition(
2870             SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() ));
2871         SwPaM aTmpPam( aDeleteStart, aCellEnd );
2872         pUndo = new SwUndoDelete( aTmpPam, sal_True );
2873     }
2874     SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) );
2875     pTxt = aCellStart.nNode.GetNode().GetTxtNode();
2876     if( pTxt )
2877         aCellStart.nContent.Assign( pTxt, 0 );
2878     if( aCellStart != aInsertEnd ) // An empty insertion will not been marked
2879     {
2880         SwPaM aTmpPam( aCellStart, aInsertEnd );
2881         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true );
2882     }
2883 
2884     pDoc->SetRedlineMode_intern( eOld );
2885     return pUndo;
2886 }
2887 
2888 
2889 sal_Bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes,
2890                                 sal_uInt16 nCnt )
2891 {
2892     SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]->
2893                                 GetSttNd()->FindTableNode();
2894 
2895     SwTableSortBoxes aTmpLst( 0, 5 );
2896     pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd,
2897                                        0, 0, nCnt, sal_True, sal_False );
2898     aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2899 
2900     sal_Bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, sal_True );
2901     if( bRet )
2902         pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2903     else
2904         delete pInsRowUndo, pInsRowUndo = 0;
2905     return bRet;
2906 }
2907 
2908 sal_Bool SwUndoTblCpyTbl::IsEmpty() const
2909 {
2910     return !pInsRowUndo && !pArr->Count();
2911 }
2912 
2913 
2914 //////////////////////////////////////////////////////////////////////////
2915 
2916 SwUndoCpyTbl::SwUndoCpyTbl()
2917     : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 )
2918 {
2919 }
2920 
2921 SwUndoCpyTbl::~SwUndoCpyTbl()
2922 {
2923     delete pDel;
2924 }
2925 
2926 void SwUndoCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2927 {
2928     SwDoc & rDoc = rContext.GetDoc();
2929     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode();
2930 
2931     // harte SeitenUmbrueche am nachfolgenden Node verschieben
2932     SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2933     if( pNextNd )
2934     {
2935         SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt();
2936         const SfxPoolItem *pItem;
2937 
2938         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2939             sal_False, &pItem ) )
2940             pNextNd->SetAttr( *pItem );
2941 
2942         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2943             sal_False, &pItem ) )
2944             pNextNd->SetAttr( *pItem );
2945     }
2946 
2947     SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 );
2948     pDel = new SwUndoDelete( aPam, sal_True );
2949 }
2950 
2951 void SwUndoCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2952 {
2953     pDel->UndoImpl(rContext);
2954     delete pDel, pDel = 0;
2955 }
2956 
2957 
2958 //////////////////////////////////////////////////////////////////////////
2959 
2960 SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd,
2961     SwSaveRowSpan* pRowSp, sal_uInt16 eMode, sal_Bool bNewSize )
2962     : SwUndo( UNDO_SPLIT_TABLE ),
2963     nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ),
2964     pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize )
2965 {
2966     switch( nMode )
2967     {
2968     case HEADLINE_BOXATRCOLLCOPY:
2969             pHistory = new SwHistory;
2970             // kein break;
2971     case HEADLINE_BORDERCOPY:
2972     case HEADLINE_BOXATTRCOPY:
2973         pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, sal_False );
2974         break;
2975     }
2976 }
2977 
2978 SwUndoSplitTbl::~SwUndoSplitTbl()
2979 {
2980     delete pSavTbl;
2981     delete pHistory;
2982     delete mpSaveRowSpan;
2983 }
2984 
2985 void SwUndoSplitTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2986 {
2987     SwDoc *const pDoc = & rContext.GetDoc();
2988     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2989 
2990     pPam->DeleteMark();
2991     SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2992     rIdx = nTblNode + nOffset;
2993 
2994     //Den implizit erzeugten Absatz wieder entfernen.
2995     pDoc->GetNodes().Delete( rIdx, 1 );
2996 
2997     rIdx = nTblNode + nOffset;
2998     SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
2999     SwTable& rTbl = pTblNd->GetTable();
3000 
3001     SwTableFmlUpdate aMsgHnt( &rTbl );
3002     aMsgHnt.eFlags = TBL_BOXPTR;
3003     pDoc->UpdateTblFlds( &aMsgHnt );
3004 
3005     switch( nMode )
3006     {
3007     case HEADLINE_BOXATRCOLLCOPY:
3008         if( pHistory )
3009             pHistory->TmpRollback( pDoc, nFmlEnd );
3010 
3011         // kein break
3012     case HEADLINE_BOXATTRCOPY:
3013     case HEADLINE_BORDERCOPY:
3014         {
3015             pSavTbl->CreateNew( rTbl, sal_False );
3016             pSavTbl->RestoreAttr( rTbl );
3017         }
3018         break;
3019 
3020     case HEADLINE_CNTNTCOPY:
3021         // die erzeugte 1. Line muss wieder entfernt werden
3022         {
3023             SwSelBoxes aSelBoxes;
3024             SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 );
3025             rTbl.SelLineFromBox( pBox, aSelBoxes, sal_True );
3026             _FndBox aTmpBox( 0, 0 );
3027             aTmpBox.SetTableLines( aSelBoxes, rTbl );
3028             aTmpBox.DelFrms( rTbl );
3029             rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, sal_False, sal_False );
3030         }
3031         break;
3032     }
3033 
3034     pDoc->GetNodes().MergeTable( rIdx );
3035 
3036     if( pHistory )
3037     {
3038         pHistory->TmpRollback( pDoc, 0 );
3039         pHistory->SetTmpEnd( pHistory->Count() );
3040     }
3041     if( mpSaveRowSpan )
3042     {
3043         pTblNd = rIdx.GetNode().FindTableNode();
3044         if( pTblNd )
3045             pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan );
3046     }
3047     ClearFEShellTabCols();
3048 }
3049 
3050 void SwUndoSplitTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3051 {
3052     SwDoc *const pDoc = & rContext.GetDoc();
3053     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3054 
3055     pPam->DeleteMark();
3056     pPam->GetPoint()->nNode = nTblNode;
3057     pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3058 
3059     ClearFEShellTabCols();
3060 }
3061 
3062 void SwUndoSplitTbl::RepeatImpl(::sw::RepeatContext & rContext)
3063 {
3064     SwPaM *const pPam = & rContext.GetRepeatPaM();
3065     SwDoc *const pDoc = & rContext.GetDoc();
3066 
3067     pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3068     ClearFEShellTabCols();
3069 }
3070 
3071 void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory )
3072 {
3073     if( !pHistory )
3074         pHistory = new SwHistory;
3075 
3076     nFmlEnd = rHistory.Count();
3077     pHistory->Move( 0, &rHistory );
3078 }
3079 
3080 
3081 //////////////////////////////////////////////////////////////////////////
3082 
3083 SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd,
3084                                 const SwTableNode& rDelTblNd,
3085                                 sal_Bool bWithPrv, sal_uInt16 nMd )
3086     : SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ),
3087     pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv )
3088 {
3089     // Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt
3090     if( bWithPrev )
3091         nTblNode = rDelTblNd.EndOfSectionIndex() - 1;
3092     else
3093         nTblNode = rTblNd.EndOfSectionIndex() - 1;
3094 
3095     aName = rDelTblNd.GetTable().GetFrmFmt()->GetName();
3096     pSavTbl = new _SaveTable( rDelTblNd.GetTable() );
3097 
3098     pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0;
3099 }
3100 
3101 SwUndoMergeTbl::~SwUndoMergeTbl()
3102 {
3103     delete pSavTbl;
3104     delete pSavHdl;
3105     delete pHistory;
3106 }
3107 
3108 void SwUndoMergeTbl::UndoImpl(::sw::UndoRedoContext & rContext)
3109 {
3110     SwDoc *const pDoc = & rContext.GetDoc();
3111     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3112 
3113     pPam->DeleteMark();
3114     SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
3115     rIdx = nTblNode;
3116 
3117     SwTableNode* pTblNd = rIdx.GetNode().FindTableNode();
3118     SwTable* pTbl = &pTblNd->GetTable();
3119 
3120     SwTableFmlUpdate aMsgHnt( pTbl );
3121     aMsgHnt.eFlags = TBL_BOXPTR;
3122     pDoc->UpdateTblFlds( &aMsgHnt );
3123 
3124     //Lines fuer das Layout-Update herausuchen.
3125     _FndBox aFndBox( 0, 0 );
3126     aFndBox.SetTableLines( *pTbl );
3127     aFndBox.DelFrms( *pTbl );
3128     // ? TL_CHART2: notification or locking of controller required ?
3129 
3130     SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, sal_True, sal_False );
3131 
3132     //Layout updaten
3133     aFndBox.MakeFrms( *pTbl );
3134     // ? TL_CHART2: notification or locking of controller required ?
3135 
3136     if( bWithPrev )
3137     {
3138         // den Namen umsetzen
3139         pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() );
3140         pSavHdl->RestoreAttr( pNew->GetTable() );
3141     }
3142     else
3143         pTbl = &pNew->GetTable();
3144     pTbl->GetFrmFmt()->SetName( aName );
3145 
3146 //  pSavTbl->CreateNew( *pTbl, sal_False );
3147     pSavTbl->RestoreAttr( *pTbl );
3148 
3149 
3150     if( pHistory )
3151     {
3152         pHistory->TmpRollback( pDoc, 0 );
3153         pHistory->SetTmpEnd( pHistory->Count() );
3154     }
3155 
3156     // fuer die neue Tabelle die Frames anlegen
3157     SwNodeIndex aTmpIdx( *pNew );
3158     pNew->MakeFrms( &aTmpIdx );
3159 
3160     // Cursor  irgendwo in den Content stellen
3161     SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx );
3162     pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3163 
3164     ClearFEShellTabCols();
3165 
3166     // TL_CHART2: need to inform chart of probably changed cell names
3167     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
3168     if (pPCD)
3169     {
3170         pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() );
3171         pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() );
3172     }
3173 }
3174 
3175 void SwUndoMergeTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3176 {
3177     SwDoc *const pDoc = & rContext.GetDoc();
3178     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3179 
3180     pPam->DeleteMark();
3181     pPam->GetPoint()->nNode = nTblNode;
3182     if( bWithPrev )
3183         pPam->GetPoint()->nNode = nTblNode + 3;
3184     else
3185         pPam->GetPoint()->nNode = nTblNode;
3186 
3187     pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3188 
3189     ClearFEShellTabCols();
3190 }
3191 
3192 void SwUndoMergeTbl::RepeatImpl(::sw::RepeatContext & rContext)
3193 {
3194     SwDoc *const pDoc = & rContext.GetDoc();
3195     SwPaM *const pPam = & rContext.GetRepeatPaM();
3196 
3197     pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3198     ClearFEShellTabCols();
3199 }
3200 
3201 void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory )
3202 {
3203     if( !pHistory )
3204         pHistory = new SwHistory;
3205     pHistory->Move( 0, &rHistory );
3206 }
3207 
3208 
3209 //////////////////////////////////////////////////////////////////////////
3210 
3211 void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos )
3212 {
3213     sal_uInt16 nO   = rArr.Count(), nM, nU = 0;
3214     if( nO > 0 )
3215     {
3216         nO--;
3217         while( nU <= nO )
3218         {
3219             nM = nU + ( nO - nU ) / 2;
3220             if( *(rArr.GetData() + nM) == nIdx )
3221             {
3222                 ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3223                 return;
3224             }
3225             if( *(rArr.GetData() + nM) < nIdx )
3226                 nU = nM + 1;
3227             else if( nM == 0 )
3228                 break;
3229             else
3230                 nO = nM - 1;
3231         }
3232     }
3233     rArr.Insert( nIdx, nU );
3234     if( pInsPos )
3235         *pInsPos = nU;
3236 }
3237 
3238 void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos )
3239 {
3240     sal_uInt16 nO   = rArr.Count(), nM, nU = 0;
3241     if( nO > 0 )
3242     {
3243         nO--;
3244         while( nU <= nO )
3245         {
3246             nM = nU + ( nO - nU ) / 2;
3247             if( *(rArr.GetData() + nM) == nIdx )
3248             {
3249                 ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3250                 return;
3251             }
3252             if( *(rArr.GetData() + nM) < nIdx )
3253                 nU = nM + 1;
3254             else if( nM == 0 )
3255                 break;
3256             else
3257                 nO = nM - 1;
3258         }
3259     }
3260     rArr.Insert( nIdx, nU );
3261     if( pInsPos )
3262         *pInsPos = nU;
3263 }
3264 
3265 #if defined( JP_DEBUG ) && defined(DBG_UTIL)
3266 
3267 
3268 void DumpDoc( SwDoc* pDoc, const String& rFileNm )
3269 {
3270     Writer* pWrt = SwIoSystem::GetWriter( "DEBUG" );
3271     if( pWrt )
3272     {
3273         SvFileStream aStream( rFileNm, STREAM_STD_WRITE );
3274         SwPaM* pPam = new SwPaM( pDoc, SwPosition( pDoc->GetNodes().EndOfContent ,
3275                                                  pDoc->GetNodes().EndOfContent ));
3276         pPam->Move( fnMoveBackward, fnGoDoc );
3277         pPam->SetMark();
3278         pPam->Move( fnMoveForward, fnGoDoc );
3279 
3280         pWrt->Write( pPam, *pDoc, aStream, rFileNm.GetStr() );
3281 
3282         delete pPam;
3283     }
3284 }
3285 void CheckTable( const SwTable& rTbl )
3286 {
3287     const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
3288     const SwTableSortBoxes& rSrtArr = pTblNd->GetTable().GetTabSortBoxes();
3289     for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n )
3290     {
3291         const SwTableBox* pBox = rSrtArr[ n ];
3292         const SwNode* pNd = pBox->GetSttNd();
3293         ASSERT( rNds[ *pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode"  );
3294     }
3295 }
3296 #endif
3297 
3298 
3299