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