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