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