xref: /trunk/main/sw/source/core/undo/untbl.cxx (revision 300d4866)
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 );
IsNewModel() const146     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 );
~SwTblToTxtSaveSwTblToTxtSave224     ~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 
SwUndoInsTbl(const SwPosition & rPos,sal_uInt16 nCl,sal_uInt16 nRw,sal_uInt16 nAdj,const SwInsertTableOptions & rInsTblOpts,const SwTableAutoFmt * pTAFmt,const SvUShorts * pColArr,const String & rName)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 
~SwUndoInsTbl()272 SwUndoInsTbl::~SwUndoInsTbl()
273 {
274 	delete pDDEFldType;
275 	delete pColWidth;
276 	delete pRedlData;
277 	delete pAutoFmt;
278 }
279 
UndoImpl(::sw::UndoRedoContext & rContext)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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
RepeatImpl(::sw::RepeatContext & rContext)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 
GetRewriter() const375 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 
SwTblToTxtSave(SwDoc & rDoc,sal_uLong nNd,sal_uLong nEndIdx,xub_StrLen nCnt)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 
SwUndoTblToTxt(const SwTable & rTbl,sal_Unicode cCh)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 
~SwUndoTblToTxt()467 SwUndoTblToTxt::~SwUndoTblToTxt()
468 {
469 	delete pDDEFldType;
470 	delete pTblSave;
471 	delete pBoxSaves;
472 	delete pHistory;
473 }
474 
475 
476 
UndoImpl(::sw::UndoRedoContext & rContext)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
UndoTableToText(sal_uLong nSttNd,sal_uLong nEndNd,const SwTblToTxtSaves & rSavedData)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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
RepeatImpl(::sw::RepeatContext & rContext)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 
SetRange(const SwNodeRange & rRg)710 void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg )
711 {
712 	nSttNd = rRg.aStart.GetIndex();
713 	nEndNd = rRg.aEnd.GetIndex();
714 }
715 
AddBoxPos(SwDoc & rDoc,sal_uLong nNdIdx,sal_uLong nEndIdx,xub_StrLen nCntntIdx)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 
SwUndoTxtToTbl(const SwPaM & rRg,const SwInsertTableOptions & rInsTblOpts,sal_Unicode cCh,sal_uInt16 nAdj,const SwTableAutoFmt * pAFmt)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 
~SwUndoTxtToTbl()742 SwUndoTxtToTbl::~SwUndoTxtToTbl()
743 {
744 	delete pDelBoxes;
745 	delete pAutoFmt;
746 }
747 
UndoImpl(::sw::UndoRedoContext & rContext)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( sal_False, "Where was the box?" );
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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
RepeatImpl(::sw::RepeatContext & rContext)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 
AddFillBox(const SwTableBox & rBox)850 void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox )
851 {
852 	if( !pDelBoxes )
853 		pDelBoxes = new SvULongs;
854 	pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() );
855 }
856 
GetHistory()857 SwHistory& SwUndoTxtToTbl::GetHistory()
858 {
859 	if( !pHistory )
860 		pHistory = new SwHistory;
861 	return *pHistory;
862 }
863 
864 // -----------------------------------------------------
865 
SwUndoTblHeadline(const SwTable & rTbl,sal_uInt16 nOldHdl,sal_uInt16 nNewHdl)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 
UndoImpl(::sw::UndoRedoContext & rContext)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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
RepeatImpl(::sw::RepeatContext & rContext)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 
_SaveTable(const SwTable & rTbl,sal_uInt16 nLnCnt,sal_Bool bSaveFml)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 
~_SaveTable()932 _SaveTable::~_SaveTable()
933 {
934 	delete pLine;
935 }
936 
937 
AddFmt(SwFrmFmt * pFmt,bool bIsLine)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 
RestoreAttr(SwTable & rTbl,sal_Bool bMdfyBox)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( sal_False, "Number of Lines has changed" );
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 
SaveCntntAttrs(SwDoc * pDoc)1024 void _SaveTable::SaveCntntAttrs( SwDoc* pDoc )
1025 {
1026 	pLine->SaveCntntAttrs( pDoc );
1027 }
1028 
1029 
CreateNew(SwTable & rTbl,sal_Bool bCreateFrms,sal_Bool bRestoreChart)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 
NewFrmFmt(const SwTableLine * pTblLn,const SwTableBox * pTblBx,sal_uInt16 nFmtPos,SwFrmFmt * pOldFmt)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 
_SaveLine(_SaveLine * pPrev,const SwTableLine & rLine,_SaveTable & rSTbl)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 
~_SaveLine()1196 _SaveLine::~_SaveLine()
1197 {
1198 	delete pBox;
1199 	delete pNext;
1200 }
1201 
1202 
RestoreAttr(SwTableLine & rLine,_SaveTable & rSTbl)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( sal_False, "Number of boxes has changed" );
1213 			break;
1214 		}
1215 		pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl );
1216 	}
1217 }
1218 
1219 
SaveCntntAttrs(SwDoc * pDoc)1220 void _SaveLine::SaveCntntAttrs( SwDoc* pDoc )
1221 {
1222 	pBox->SaveCntntAttrs( pDoc );
1223 	if( pNext )
1224 		pNext->SaveCntntAttrs( pDoc );
1225 }
1226 
1227 
CreateNew(SwTable & rTbl,SwTableBox & rParent,_SaveTable & rSTbl)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 
_SaveBox(_SaveBox * pPrev,const SwTableBox & rBox,_SaveTable & rSTbl)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 
~_SaveBox()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 
RestoreAttr(SwTableBox & rBox,_SaveTable & rSTbl)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( sal_False, "Number of Lines has changed" );
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( sal_False, "Number of Lines has changed" );
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( sal_False, "Box no longer at the same node" );
1350 	}
1351 }
1352 
1353 
SaveCntntAttrs(SwDoc * pDoc)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 
CreateNew(SwTable & rTbl,SwTableLine & rParent,_SaveTable & rSTbl)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 
SwUndoAttrTbl(const SwTableNode & rTblNd,sal_Bool bClearTabCols)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 
~SwUndoAttrTbl()1444 SwUndoAttrTbl::~SwUndoAttrTbl()
1445 {
1446 	delete pSaveTbl;
1447 }
1448 
UndoImpl(::sw::UndoRedoContext & rContext)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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
SwUndoTblAutoFmt(const SwTableNode & rTblNd,const SwTableAutoFmt & rAFmt)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 
~SwUndoTblAutoFmt()1495 SwUndoTblAutoFmt::~SwUndoTblAutoFmt()
1496 {
1497 	delete pSaveTbl;
1498 }
1499 
SaveBoxCntnt(const SwTableBox & rBox)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
UndoRedo(bool const bUndo,::sw::UndoRedoContext & rContext)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 
UndoImpl(::sw::UndoRedoContext & rContext)1533 void SwUndoTblAutoFmt::UndoImpl(::sw::UndoRedoContext & rContext)
1534 {
1535     UndoRedo(true, rContext);
1536 }
1537 
RedoImpl(::sw::UndoRedoContext & rContext)1538 void SwUndoTblAutoFmt::RedoImpl(::sw::UndoRedoContext & rContext)
1539 {
1540     UndoRedo(false, rContext);
1541 }
1542 
1543 
1544 //////////////////////////////////////////////////////////////////////////
1545 
SwUndoTblNdsChg(SwUndoId nAction,const SwSelBoxes & rBoxes,const SwTableNode & rTblNd,long nMn,long nMx,sal_uInt16 nCnt,sal_Bool bFlg,sal_Bool bSmHght)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 
SwUndoTblNdsChg(SwUndoId nAction,const SwSelBoxes & rBoxes,const SwTableNode & rTblNd)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 
ReNewBoxes(const SwSelBoxes & rBoxes)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 
~SwUndoTblNdsChg()1603 SwUndoTblNdsChg::~SwUndoTblNdsChg()
1604 {
1605 	delete pSaveTbl;
1606 
1607 	if( IsDelBox() )
1608 		delete Ptrs.pDelSects;
1609 	else
1610 		delete Ptrs.pNewSttNds;
1611 }
1612 
SaveNewBoxes(const SwTableNode & rTblNd,const SwTableSortBoxes & rOld)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 
lcl_FindTableLine(const SwTable & rTable,const SwTableBox & rBox)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 
lcl_FindParentLines(const SwTable & rTable,const SwTableBox & rBox)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 
SaveNewBoxes(const SwTableNode & rTblNd,const SwTableSortBoxes & rOld,const SwSelBoxes & rBoxes,const SvULongs & rNodeCnts)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 separate 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 
SaveSection(SwStartNode * pSttNd)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 
UndoImpl(::sw::UndoRedoContext & rContext)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 
RedoImpl(::sw::UndoRedoContext & rContext)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 
SwUndoTblMerge(const SwPaM & rTblSel)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 
~SwUndoTblMerge()2013 SwUndoTblMerge::~SwUndoTblMerge()
2014 {
2015 	delete pSaveTbl;
2016 	delete pMoves;
2017 	delete pHistory;
2018 }
2019 
UndoImpl(::sw::UndoRedoContext & rContext)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->RstTxtAttr( aTmpIdx, pTxtNd->GetTxt().Len() - nDelPos + 1 );
2115                     // das Trennzeichen loeschen
2116                     pTxtNd->EraseText( aTmpIdx, 1 );
2117                 }
2118 DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) +
2119 				String(".db") )
2120 			}
2121 			nIdx = pBox->GetSttIdx();
2122 		}
2123 		else
2124 			pBox = pTblNd->GetTable().GetTblBox( nIdx );
2125 
2126         if( !pSaveTbl->IsNewModel() )
2127         {
2128             // TL_CHART2: notify chart about box to be removed
2129             if (pPCD)
2130                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
2131 
2132             SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
2133             pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
2134 
2135 
2136             // Indizies aus dem Bereich loeschen
2137             {
2138                 SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
2139                 rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ),
2140                             SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ),
2141                             SwPosition( aTmpIdx, SwIndex( 0, 0 )), sal_True );
2142             }
2143 
2144             delete pBox;
2145             rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
2146         }
2147 	}
2148 DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" )
2149 CHECKTABLE(pTblNd->GetTable())
2150 
2151 
2152 	pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False );
2153 
2154     // TL_CHART2: need to inform chart of probably changed cell names
2155     rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
2156 
2157 	if( pHistory )
2158 	{
2159 		pHistory->TmpRollback( &rDoc, 0 );
2160 		pHistory->SetTmpEnd( pHistory->Count() );
2161 	}
2162 //	nTblNode = pTblNd->GetIndex();
2163 
2164     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2165 	pPam->DeleteMark();
2166 	pPam->GetPoint()->nNode = nSttNode;
2167 	pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt );
2168 	pPam->SetMark();
2169 	pPam->DeleteMark();
2170 
2171 CHECKTABLE(pTblNd->GetTable())
2172 	ClearFEShellTabCols();
2173 }
2174 
RedoImpl(::sw::UndoRedoContext & rContext)2175 void SwUndoTblMerge::RedoImpl(::sw::UndoRedoContext & rContext)
2176 {
2177     SwDoc & rDoc = rContext.GetDoc();
2178     SwPaM & rPam( AddUndoRedoPaM(rContext) );
2179     rDoc.MergeTbl(rPam);
2180 }
2181 
MoveBoxCntnt(SwDoc * pDoc,SwNodeRange & rRg,SwNodeIndex & rPos)2182 void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos )
2183 {
2184 	SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 );
2185 	SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos );
2186     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
2187     pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ?
2188         IDocumentContentOperations::DOC_NO_DELFRMS :
2189         IDocumentContentOperations::DOC_MOVEDEFAULT );
2190 	aTmp++;
2191 	aTmp2++;
2192 	pUndo->SetDestRange( aTmp2, rPos, aTmp );
2193 
2194 	pMoves->Insert( pUndo, pMoves->Count() );
2195 }
2196 
SetSelBoxes(const SwSelBoxes & rBoxes)2197 void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
2198 {
2199 	// die Selektion merken
2200 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2201 		InsertSort( aBoxes, rBoxes[n]->GetSttIdx() );
2202 
2203 	// als Trennung fuers einfuegen neuer Boxen nach dem Verschieben!
2204 	aNewSttNds.Insert( (sal_uLong)0, aNewSttNds.Count() );
2205 
2206      // The new table model does not delete overlapped cells (by row span),
2207      // so the rBoxes array might be empty even some cells have been merged.
2208     if( rBoxes.Count() )
2209         nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex();
2210 }
2211 
SaveCollection(const SwTableBox & rBox)2212 void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox )
2213 {
2214 	if( !pHistory )
2215 		pHistory = new SwHistory;
2216 
2217 	SwNodeIndex aIdx( *rBox.GetSttNd(), 1 );
2218 	SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
2219 	if( !pCNd )
2220 		pCNd = aIdx.GetNodes().GoNext( &aIdx );
2221 
2222 	pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType());
2223     if( pCNd->HasSwAttrSet() )
2224         pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() );
2225 }
2226 
2227 
2228 //////////////////////////////////////////////////////////////////////////
2229 
SwUndoTblNumFmt(const SwTableBox & rBox,const SfxItemSet * pNewSet)2230 SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox,
2231 									const SfxItemSet* pNewSet )
2232 	: SwUndo( UNDO_TBLNUMFMT ),
2233 	pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT )
2234 {
2235 	bNewFmt = bNewFml = bNewValue = sal_False;
2236 	nNode = rBox.GetSttIdx();
2237 
2238 	nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet );
2239     SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2240 
2241 	if( ULONG_MAX != nNdPos )
2242 	{
2243 		SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2244 
2245 		pHistory = new SwHistory;
2246 		SwRegHistory aRHst( *rBox.GetSttNd(), pHistory );
2247         // always save all text atttibutes because of possibly overlapping
2248         // areas of on/off
2249         pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0,
2250                             pTNd->GetTxt().Len(), true );
2251 
2252         if( pTNd->HasSwAttrSet() )
2253             pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos );
2254 
2255 		aStr = pTNd->GetTxt();
2256 		if( pTNd->GetpSwpHints() )
2257 			pTNd->GetpSwpHints()->DeRegister();
2258     }
2259 
2260     pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange );
2261     pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() );
2262 
2263     if( pNewSet )
2264     {
2265         const SfxPoolItem* pItem;
2266         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT,
2267                 sal_False, &pItem ))
2268         {
2269             bNewFmt = sal_True;
2270             nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2271         }
2272         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA,
2273                 sal_False, &pItem ))
2274         {
2275             bNewFml = sal_True;
2276             aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula();
2277         }
2278         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE,
2279                 sal_False, &pItem ))
2280         {
2281             bNewValue = sal_True;
2282             fNewNum = ((SwTblBoxValue*)pItem)->GetValue();
2283         }
2284 	}
2285 
2286 	// wird die History ueberhaupt benoetigt ??
2287 	if( pHistory && !pHistory->Count() )
2288 		DELETEZ( pHistory );
2289 }
2290 
~SwUndoTblNumFmt()2291 SwUndoTblNumFmt::~SwUndoTblNumFmt()
2292 {
2293 	delete pHistory;
2294 	delete pBoxSet;
2295 }
2296 
UndoImpl(::sw::UndoRedoContext & rContext)2297 void SwUndoTblNumFmt::UndoImpl(::sw::UndoRedoContext & rContext)
2298 {
2299 	ASSERT( pBoxSet, "Where's the stored item set?" )
2300 
2301     SwDoc & rDoc = rContext.GetDoc();
2302 	SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]->
2303 							FindSttNodeByType( SwTableBoxStartNode );
2304 	ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2305 	SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2306 									pSttNd->GetIndex() );
2307 	ASSERT( pBox, "keine TabellenBox gefunden" );
2308 
2309 	SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt();
2310     pFmt->SetFmtAttr( *pBoxSet );
2311 	pBox->ChgFrmFmt( pFmt );
2312 
2313     if( ULONG_MAX == nNdPos )
2314         return;
2315 
2316 	SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode();
2317 	// wenn mehr als ein Node geloescht wurde, dann wurden auch
2318 	// alle "Node"-Attribute gespeichert
2319     if( pTxtNd->HasSwAttrSet() )
2320 		pTxtNd->ResetAllAttr();
2321 
2322 	if( pTxtNd->GetpSwpHints() && aStr.Len() )
2323         pTxtNd->ClearSwpHintsArr( true );
2324 
2325     // ChgTextToNum(..) only acts when the strings are different. We
2326     // need to do the same here.
2327     if( pTxtNd->GetTxt() != aStr )
2328     {
2329         rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX );
2330 
2331         SwIndex aIdx( pTxtNd, 0 );
2332         if( aStr.Len() )
2333         {
2334             pTxtNd->EraseText( aIdx );
2335             pTxtNd->InsertText( aStr, aIdx,
2336                 IDocumentContentOperations::INS_NOHINTEXPAND );
2337         }
2338     }
2339 
2340 	if( pHistory )
2341 	{
2342 		sal_uInt16 nTmpEnd = pHistory->GetTmpEnd();
2343 		pHistory->TmpRollback( &rDoc, 0 );
2344 		pHistory->SetTmpEnd( nTmpEnd );
2345 	}
2346 
2347     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2348 	pPam->DeleteMark();
2349 	pPam->GetPoint()->nNode = nNode + 1;
2350 	pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2351 }
2352 
2353 /** switch the RedlineMode on the given document, using
2354  * SetRedlineMode_intern. This class set the mode in the constructor,
2355  * and changes it back in the destructor, i.e. it uses the
2356  * initialization-is-resource-acquisition idiom.
2357  */
2358 class RedlineModeInternGuard
2359 {
2360     SwDoc& mrDoc;
2361     RedlineMode_t meOldRedlineMode;
2362 
2363 public:
2364     RedlineModeInternGuard(
2365         SwDoc& rDoc,                      /// change mode of this document
2366         RedlineMode_t eNewRedlineMode,    /// new redline mode
2367         RedlineMode_t eRedlineModeMask  = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/));
2368 
2369     ~RedlineModeInternGuard();
2370 };
2371 
RedlineModeInternGuard(SwDoc & rDoc,RedlineMode_t eNewRedlineMode,RedlineMode_t eRedlineModeMask)2372 RedlineModeInternGuard::RedlineModeInternGuard(
2373     SwDoc& rDoc,
2374     RedlineMode_t eNewRedlineMode,
2375     RedlineMode_t eRedlineModeMask )
2376     : mrDoc( rDoc ),
2377       meOldRedlineMode( rDoc.GetRedlineMode() )
2378 {
2379     mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) |
2380 									 ( eNewRedlineMode & eRedlineModeMask ) ));
2381 }
2382 
~RedlineModeInternGuard()2383 RedlineModeInternGuard::~RedlineModeInternGuard()
2384 {
2385     mrDoc.SetRedlineMode_intern( meOldRedlineMode );
2386 }
2387 
2388 
2389 
RedoImpl(::sw::UndoRedoContext & rContext)2390 void SwUndoTblNumFmt::RedoImpl(::sw::UndoRedoContext & rContext)
2391 {
2392 	// konnte die Box veraendert werden ?
2393 	if( !pBoxSet )
2394 		return ;
2395 
2396     SwDoc & rDoc = rContext.GetDoc();
2397     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2398 
2399 	pPam->DeleteMark();
2400 	pPam->GetPoint()->nNode = nNode;
2401 
2402     SwNode * pNd = & pPam->GetPoint()->nNode.GetNode();
2403 	SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode );
2404 	ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2405 	SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2406 									pSttNd->GetIndex() );
2407 	ASSERT( pBox, "keine TabellenBox gefunden" );
2408 
2409 	SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
2410 	if(	bNewFmt || bNewFml || bNewValue )
2411 	{
2412 		SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2413 								RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2414 
2415 		// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2416 		//				Sorge dafuer, das der Text auch entsprechend
2417 		//				formatiert wird!
2418 		pBoxFmt->LockModify();
2419 
2420 		if( bNewFml )
2421 			aBoxSet.Put( SwTblBoxFormula( aNewFml ));
2422 		else
2423             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2424 		if( bNewFmt )
2425 			aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx ));
2426 		else
2427             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2428 		if( bNewValue )
2429 			aBoxSet.Put( SwTblBoxValue( fNewNum ));
2430 		else
2431             pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
2432 		pBoxFmt->UnlockModify();
2433 
2434         // dvo: When redlining is (was) enabled, setting the attribute
2435         // will also change the cell content. To allow this, the
2436         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2437         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2438         pBoxFmt->SetFmtAttr( aBoxSet );
2439 	}
2440 	else if( NUMBERFORMAT_TEXT != nFmtIdx )
2441 	{
2442 		SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2443 							RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2444 
2445 		aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
2446 		aBoxSet.Put( SwTblBoxValue( fNum ));
2447 
2448 		// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2449 		//				Sorge dafuer, das der Text auch entsprechend
2450 		//				formatiert wird!
2451 		pBoxFmt->LockModify();
2452         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2453 		pBoxFmt->UnlockModify();
2454 
2455         // dvo: When redlining is (was) enabled, setting the attribute
2456         // will also change the cell content. To allow this, the
2457         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2458         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2459         pBoxFmt->SetFmtAttr( aBoxSet );
2460 	}
2461 	else
2462 	{
2463 		// es ist keine Zahl
2464 
2465 		// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2466 		//				Sorge dafuer, das der Text auch entsprechend
2467 		//				formatiert wird!
2468         pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
2469 
2470         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2471 	}
2472 
2473 	if( bNewFml )
2474 	{
2475 		// egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut
2476 		SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() );
2477 		rDoc.UpdateTblFlds( &aTblUpdate );
2478 	}
2479 
2480 	if( !pNd->IsCntntNode() )
2481 		pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode );
2482 	pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2483 }
2484 
SetBox(const SwTableBox & rBox)2485 void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox )
2486 {
2487 	nNode = rBox.GetSttIdx();
2488 }
2489 
2490 
2491 //////////////////////////////////////////////////////////////////////////
2492 
_UndoTblCpyTbl_Entry(const SwTableBox & rBox)2493 _UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox )
2494 	: nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ),
2495 	pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false )
2496 {
2497 }
2498 
~_UndoTblCpyTbl_Entry()2499 _UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry()
2500 {
2501 	delete pUndo;
2502 	delete pBoxNumAttr;
2503 }
2504 
2505 
SwUndoTblCpyTbl()2506 SwUndoTblCpyTbl::SwUndoTblCpyTbl()
2507 	: SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 )
2508 {
2509 	pArr = new _UndoTblCpyTbl_Entries;
2510 }
2511 
~SwUndoTblCpyTbl()2512 SwUndoTblCpyTbl::~SwUndoTblCpyTbl()
2513 {
2514 	delete pArr;
2515 	delete pInsRowUndo;
2516 }
2517 
UndoImpl(::sw::UndoRedoContext & rContext)2518 void SwUndoTblCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2519 {
2520     SwDoc & rDoc = rContext.GetDoc();
2521     _DEBUG_REDLINE( &rDoc )
2522 
2523 	SwTableNode* pTblNd = 0;
2524 	for( sal_uInt16 n = pArr->Count(); n; )
2525 	{
2526 		_UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ];
2527 		sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2528         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2529 		if( !pTblNd )
2530 			pTblNd = pSNd->FindTableNode();
2531 
2532 		SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2533 
2534 		SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2535 		rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2536 
2537         // b62341295: Redline for copying tables
2538         const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode();
2539 		SwPaM aPam( aInsIdx.GetNode(), *pEndNode );
2540         SwUndoDelete* pUndo = 0;
2541 
2542         if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2543         {
2544             bool bDeleteCompleteParagraph = false;
2545             bool bShiftPam = false;
2546             // There are a couple of different situations to consider during redlining
2547             if( pEntry->pUndo )
2548             {
2549                 SwUndoDelete *const pUndoDelete =
2550                     dynamic_cast<SwUndoDelete*>(pEntry->pUndo);
2551                 SwUndoRedlineDelete *const pUndoRedlineDelete =
2552                     dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo);
2553                 OSL_ASSERT(pUndoDelete || pUndoRedlineDelete);
2554                 if (pUndoRedlineDelete)
2555                 {
2556                     // The old content was not empty or he has been merged with the new content
2557                     bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged
2558                     // Set aTmpIdx to the beginning fo the old content
2559                     SwNodeIndex aTmpIdx( *pEndNode,
2560                             pUndoRedlineDelete->NodeDiff()-1 );
2561                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2562                     if( pTxt )
2563                     {
2564                         aPam.GetPoint()->nNode = *pTxt;
2565                         aPam.GetPoint()->nContent.Assign( pTxt,
2566                                 pUndoRedlineDelete->ContentStart() );
2567                     }
2568                     else
2569                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2570                 }
2571                 else if (pUndoDelete && pUndoDelete->IsDelFullPara())
2572                 {
2573                     // When the old content was an empty paragraph, but could not be joined
2574                     // with the new content (e.g. because of a section or table)
2575                     // We "save" the aPam.Point, we go one step backwards (because later on the
2576                     // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag
2577                     // for step forward later on.
2578                     bDeleteCompleteParagraph = true;
2579                     bShiftPam = true;
2580                     SwNodeIndex aTmpIdx( *pEndNode, -1 );
2581                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2582                     if( pTxt )
2583                     {
2584                         aPam.GetPoint()->nNode = *pTxt;
2585                         aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2586                     }
2587                     else
2588                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2589                 }
2590             }
2591             rDoc.DeleteRedline( aPam, true, USHRT_MAX );
2592 
2593             if( pEntry->pUndo )
2594             {
2595                 pEntry->pUndo->UndoImpl(rContext);
2596                 delete pEntry->pUndo;
2597                 pEntry->pUndo = 0;
2598             }
2599             if( bShiftPam )
2600             {
2601                 // The aPam.Point is at the moment at the last position of the new content and has to be
2602                 // moved to the first position of the old content for the SwUndoDelete operation
2603                 SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 );
2604                 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2605                 if( pTxt )
2606                 {
2607                     aPam.GetPoint()->nNode = *pTxt;
2608                     aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2609                 }
2610                 else
2611                     *aPam.GetPoint() = SwPosition( aTmpIdx );
2612             }
2613             pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, sal_True );
2614         }
2615         else
2616         {
2617             pUndo = new SwUndoDelete( aPam, true );
2618             if( pEntry->pUndo )
2619             {
2620                 pEntry->pUndo->UndoImpl(rContext);
2621                 delete pEntry->pUndo;
2622                 pEntry->pUndo = 0;
2623             }
2624         }
2625 		pEntry->pUndo = pUndo;
2626 
2627 		aInsIdx = rBox.GetSttIdx() + 1;
2628 		rDoc.GetNodes().Delete( aInsIdx, 1 );
2629 
2630 		SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2631 												RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2632 		aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2633 		if( aTmpSet.Count() )
2634 		{
2635 			SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2636             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2637             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2638 		}
2639 
2640 		if( pEntry->pBoxNumAttr )
2641 		{
2642             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2643 			delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2644 		}
2645 
2646 		if( aTmpSet.Count() )
2647 		{
2648 			pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2649 									RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2650 									RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2651 			pEntry->pBoxNumAttr->Put( aTmpSet );
2652 		}
2653 
2654 		pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2655 	}
2656 
2657 	if( pInsRowUndo )
2658     {
2659         pInsRowUndo->UndoImpl(rContext);
2660     }
2661     _DEBUG_REDLINE( &rDoc )
2662 }
2663 
RedoImpl(::sw::UndoRedoContext & rContext)2664 void SwUndoTblCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2665 {
2666     SwDoc & rDoc = rContext.GetDoc();
2667     _DEBUG_REDLINE( &rDoc )
2668 
2669 	if( pInsRowUndo )
2670     {
2671         pInsRowUndo->RedoImpl(rContext);
2672     }
2673 
2674 	SwTableNode* pTblNd = 0;
2675 	for( sal_uInt16 n = 0; n < pArr->Count(); ++n )
2676 	{
2677 		_UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ];
2678 		sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2679         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2680 		if( !pTblNd )
2681 			pTblNd = pSNd->FindTableNode();
2682 
2683 		SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2684 
2685 		SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2686 
2687         // b62341295: Redline for copying tables - Start.
2688 		rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2689 		SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
2690         SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, sal_True );
2691 		if( pEntry->pUndo )
2692         {
2693             pEntry->pUndo->UndoImpl(rContext);
2694             if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2695             {
2696                 // PrepareRedline has to be called with the beginning of the old content
2697                 // When new and old content has been joined, the rIter.pAktPam has been set
2698                 // by the Undo operation to this point.
2699                 // Otherwise aInsIdx has been moved during the Undo operation
2700                 if( pEntry->bJoin )
2701                 {
2702                     SwPaM const& rLastPam =
2703                         rContext.GetCursorSupplier().GetCurrentShellCursor();
2704                     pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(),
2705                                             pEntry->bJoin, true );
2706                 }
2707                 else
2708                 {
2709                     SwPosition aTmpPos( aInsIdx );
2710                     pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true );
2711                 }
2712             }
2713 			delete pEntry->pUndo;
2714             pEntry->pUndo = 0;
2715 		}
2716 		pEntry->pUndo = pUndo;
2717         // b62341295: Redline for copying tables - End.
2718 
2719 		aInsIdx = rBox.GetSttIdx() + 1;
2720 		rDoc.GetNodes().Delete( aInsIdx, 1 );
2721 
2722 		SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2723 												RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2724 		aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2725 		if( aTmpSet.Count() )
2726 		{
2727 			SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2728             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2729             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2730 		}
2731 		if( pEntry->pBoxNumAttr )
2732 		{
2733             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2734 			delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2735 		}
2736 
2737 		if( aTmpSet.Count() )
2738 		{
2739 			pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2740 									RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2741 									RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2742 			pEntry->pBoxNumAttr->Put( aTmpSet );
2743 		}
2744 
2745 		pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2746 	}
2747     _DEBUG_REDLINE( &rDoc )
2748 }
2749 
AddBoxBefore(const SwTableBox & rBox,sal_Bool bDelCntnt)2750 void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, sal_Bool bDelCntnt )
2751 {
2752     if( pArr->Count() && !bDelCntnt )
2753 		return;
2754 
2755 	_UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox );
2756 	pArr->Insert( pEntry, pArr->Count() );
2757 
2758 	SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2759     _DEBUG_REDLINE( pDoc )
2760 	if( bDelCntnt )
2761 	{
2762 		SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2763 		pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
2764 		SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
2765 
2766         if( !pDoc->IsRedlineOn() )
2767             pEntry->pUndo = new SwUndoDelete( aPam, sal_True );
2768 	}
2769 
2770 	pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(),
2771 									RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2772 									RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2773 	pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() );
2774 	if( !pEntry->pBoxNumAttr->Count() )
2775 		delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2776     _DEBUG_REDLINE( pDoc )
2777 }
2778 
AddBoxAfter(const SwTableBox & rBox,const SwNodeIndex & rIdx,sal_Bool bDelCntnt)2779 void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, sal_Bool bDelCntnt )
2780 {
2781 	_UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ];
2782 
2783 	// wurde der Inhalt geloescht, so loesche jetzt auch noch den temp.
2784 	// erzeugten Node
2785 	if( bDelCntnt )
2786 	{
2787         SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2788         _DEBUG_REDLINE( pDoc )
2789 
2790         if( pDoc->IsRedlineOn() )
2791         {
2792             SwPosition aTmpPos( rIdx );
2793             pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false );
2794         }
2795 		SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 );
2796 		rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 );
2797         _DEBUG_REDLINE( pDoc )
2798     }
2799 
2800 	pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2801 }
2802 
2803 // PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations.
2804 // bRedo is set by calling from Redo()
2805 // rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has
2806 // been merged.
2807 // rJoin is true if Redo() is calling and the content has already been merged
2808 
PrepareRedline(SwDoc * pDoc,const SwTableBox & rBox,const SwPosition & rPos,bool & rJoin,bool bRedo)2809 SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox,
2810     const SwPosition& rPos, bool& rJoin, bool bRedo )
2811 {
2812     SwUndo *pUndo = 0;
2813     // b62341295: Redline for copying tables
2814     // What's to do?
2815     // Mark the cell content before rIdx as insertion,
2816     // mark the cell content behind rIdx as deletion
2817     // merge text nodes at rIdx if possible
2818     RedlineMode_t eOld = pDoc->GetRedlineMode();
2819     pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &
2820 									 ~nsRedlineMode_t::REDLINE_IGNORE ));
2821     SwPosition aInsertEnd( rPos );
2822     SwTxtNode* pTxt;
2823     if( !rJoin )
2824     {
2825         // If the content is not merged, the end of the insertion is at the end of the node
2826         // _before_ the given position rPos
2827         --aInsertEnd.nNode;
2828         pTxt = aInsertEnd.nNode.GetNode().GetTxtNode();
2829         if( pTxt )
2830         {
2831             aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2832             if( !bRedo && rPos.nNode.GetNode().GetTxtNode() )
2833             {   // Try to merge, if not called by Redo()
2834                 rJoin = true;
2835                 pTxt->JoinNext();
2836             }
2837         }
2838         else
2839             aInsertEnd.nContent = SwIndex( 0 );
2840     }
2841     // For joined (merged) contents the start of deletionm and end of insertion are identical
2842     // otherwise adjacent nodes.
2843     SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos );
2844     if( !rJoin )
2845     {
2846         pTxt = aDeleteStart.nNode.GetNode().GetTxtNode();
2847         if( pTxt )
2848             aDeleteStart.nContent.Assign( pTxt, 0 );
2849     }
2850     SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) );
2851     pTxt = aCellEnd.nNode.GetNode().GetTxtNode();
2852     if( pTxt )
2853         aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2854     if( aDeleteStart != aCellEnd )
2855     {   // If the old (deleted) part is not empty, here we are...
2856         SwPaM aDeletePam( aDeleteStart, aCellEnd );
2857         pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE );
2858         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true );
2859     }
2860     else if( !rJoin ) // If the old part is empty and joined, we are finished
2861     {   // if it is not joined, we have to delete this empty paragraph
2862         aCellEnd = SwPosition(
2863             SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() ));
2864         SwPaM aTmpPam( aDeleteStart, aCellEnd );
2865         pUndo = new SwUndoDelete( aTmpPam, sal_True );
2866     }
2867     SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) );
2868     pTxt = aCellStart.nNode.GetNode().GetTxtNode();
2869     if( pTxt )
2870         aCellStart.nContent.Assign( pTxt, 0 );
2871     if( aCellStart != aInsertEnd ) // An empty insertion will not been marked
2872     {
2873         SwPaM aTmpPam( aCellStart, aInsertEnd );
2874         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true );
2875     }
2876 
2877     pDoc->SetRedlineMode_intern( eOld );
2878     return pUndo;
2879 }
2880 
2881 
InsertRow(SwTable & rTbl,const SwSelBoxes & rBoxes,sal_uInt16 nCnt)2882 sal_Bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes,
2883 								sal_uInt16 nCnt )
2884 {
2885 	SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]->
2886 								GetSttNd()->FindTableNode();
2887 
2888 	SwTableSortBoxes aTmpLst( 0, 5 );
2889 	pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd,
2890 									   0, 0, nCnt, sal_True, sal_False );
2891 	aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2892 
2893 	sal_Bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, sal_True );
2894 	if( bRet )
2895 		pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2896 	else
2897 		delete pInsRowUndo, pInsRowUndo = 0;
2898 	return bRet;
2899 }
2900 
IsEmpty() const2901 sal_Bool SwUndoTblCpyTbl::IsEmpty() const
2902 {
2903 	return !pInsRowUndo && !pArr->Count();
2904 }
2905 
2906 
2907 //////////////////////////////////////////////////////////////////////////
2908 
SwUndoCpyTbl()2909 SwUndoCpyTbl::SwUndoCpyTbl()
2910 	: SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 )
2911 {
2912 }
2913 
~SwUndoCpyTbl()2914 SwUndoCpyTbl::~SwUndoCpyTbl()
2915 {
2916 	delete pDel;
2917 }
2918 
UndoImpl(::sw::UndoRedoContext & rContext)2919 void SwUndoCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2920 {
2921     SwDoc & rDoc = rContext.GetDoc();
2922 	SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode();
2923 
2924 	// harte SeitenUmbrueche am nachfolgenden Node verschieben
2925 	SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2926 	if( pNextNd )
2927 	{
2928 		SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt();
2929 		const SfxPoolItem *pItem;
2930 
2931 		if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2932 			sal_False, &pItem ) )
2933 			pNextNd->SetAttr( *pItem );
2934 
2935 		if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2936 			sal_False, &pItem ) )
2937 			pNextNd->SetAttr( *pItem );
2938 	}
2939 
2940 	SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 );
2941 	pDel = new SwUndoDelete( aPam, sal_True );
2942 }
2943 
RedoImpl(::sw::UndoRedoContext & rContext)2944 void SwUndoCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2945 {
2946     pDel->UndoImpl(rContext);
2947 	delete pDel, pDel = 0;
2948 }
2949 
2950 
2951 //////////////////////////////////////////////////////////////////////////
2952 
SwUndoSplitTbl(const SwTableNode & rTblNd,SwSaveRowSpan * pRowSp,sal_uInt16 eMode,sal_Bool bNewSize)2953 SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd,
2954     SwSaveRowSpan* pRowSp, sal_uInt16 eMode, sal_Bool bNewSize )
2955 	: SwUndo( UNDO_SPLIT_TABLE ),
2956     nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ),
2957 	pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize )
2958 {
2959 	switch( nMode )
2960 	{
2961 	case HEADLINE_BOXATRCOLLCOPY:
2962 			pHistory = new SwHistory;
2963 			// kein break;
2964 	case HEADLINE_BORDERCOPY:
2965 	case HEADLINE_BOXATTRCOPY:
2966 		pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, sal_False );
2967 		break;
2968 	}
2969 }
2970 
~SwUndoSplitTbl()2971 SwUndoSplitTbl::~SwUndoSplitTbl()
2972 {
2973 	delete pSavTbl;
2974 	delete pHistory;
2975     delete mpSaveRowSpan;
2976 }
2977 
UndoImpl(::sw::UndoRedoContext & rContext)2978 void SwUndoSplitTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2979 {
2980     SwDoc *const pDoc = & rContext.GetDoc();
2981     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2982 
2983 	pPam->DeleteMark();
2984 	SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2985 	rIdx = nTblNode + nOffset;
2986 
2987 	//Den implizit erzeugten Absatz wieder entfernen.
2988 	pDoc->GetNodes().Delete( rIdx, 1 );
2989 
2990 	rIdx = nTblNode + nOffset;
2991 	SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
2992 	SwTable& rTbl = pTblNd->GetTable();
2993 
2994 	SwTableFmlUpdate aMsgHnt( &rTbl );
2995 	aMsgHnt.eFlags = TBL_BOXPTR;
2996 	pDoc->UpdateTblFlds( &aMsgHnt );
2997 
2998 	switch( nMode )
2999 	{
3000 	case HEADLINE_BOXATRCOLLCOPY:
3001 		if( pHistory )
3002 			pHistory->TmpRollback( pDoc, nFmlEnd );
3003 
3004 		// kein break
3005 	case HEADLINE_BOXATTRCOPY:
3006 	case HEADLINE_BORDERCOPY:
3007 		{
3008 			pSavTbl->CreateNew( rTbl, sal_False );
3009 			pSavTbl->RestoreAttr( rTbl );
3010 		}
3011 		break;
3012 
3013 	case HEADLINE_CNTNTCOPY:
3014 		// die erzeugte 1. Line muss wieder entfernt werden
3015 		{
3016 			SwSelBoxes aSelBoxes;
3017 			SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 );
3018 			rTbl.SelLineFromBox( pBox, aSelBoxes, sal_True );
3019             _FndBox aTmpBox( 0, 0 );
3020             aTmpBox.SetTableLines( aSelBoxes, rTbl );
3021             aTmpBox.DelFrms( rTbl );
3022 			rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, sal_False, sal_False );
3023 		}
3024 		break;
3025 	}
3026 
3027 	pDoc->GetNodes().MergeTable( rIdx );
3028 
3029 	if( pHistory )
3030 	{
3031 		pHistory->TmpRollback( pDoc, 0 );
3032 		pHistory->SetTmpEnd( pHistory->Count() );
3033 	}
3034     if( mpSaveRowSpan )
3035     {
3036         pTblNd = rIdx.GetNode().FindTableNode();
3037         if( pTblNd )
3038             pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan );
3039     }
3040 	ClearFEShellTabCols();
3041 }
3042 
RedoImpl(::sw::UndoRedoContext & rContext)3043 void SwUndoSplitTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3044 {
3045     SwDoc *const pDoc = & rContext.GetDoc();
3046     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3047 
3048 	pPam->DeleteMark();
3049 	pPam->GetPoint()->nNode = nTblNode;
3050 	pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3051 
3052 	ClearFEShellTabCols();
3053 }
3054 
RepeatImpl(::sw::RepeatContext & rContext)3055 void SwUndoSplitTbl::RepeatImpl(::sw::RepeatContext & rContext)
3056 {
3057     SwPaM *const pPam = & rContext.GetRepeatPaM();
3058     SwDoc *const pDoc = & rContext.GetDoc();
3059 
3060 	pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3061 	ClearFEShellTabCols();
3062 }
3063 
SaveFormula(SwHistory & rHistory)3064 void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory )
3065 {
3066 	if( !pHistory )
3067 		pHistory = new SwHistory;
3068 
3069 	nFmlEnd = rHistory.Count();
3070 	pHistory->Move( 0, &rHistory );
3071 }
3072 
3073 
3074 //////////////////////////////////////////////////////////////////////////
3075 
SwUndoMergeTbl(const SwTableNode & rTblNd,const SwTableNode & rDelTblNd,sal_Bool bWithPrv,sal_uInt16 nMd)3076 SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd,
3077 								const SwTableNode& rDelTblNd,
3078 								sal_Bool bWithPrv, sal_uInt16 nMd )
3079 	: SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ),
3080 	pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv )
3081 {
3082 	// Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt
3083 	if( bWithPrev )
3084 		nTblNode = rDelTblNd.EndOfSectionIndex() - 1;
3085 	else
3086 		nTblNode = rTblNd.EndOfSectionIndex() - 1;
3087 
3088 	aName = rDelTblNd.GetTable().GetFrmFmt()->GetName();
3089 	pSavTbl = new _SaveTable( rDelTblNd.GetTable() );
3090 
3091 	pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0;
3092 }
3093 
~SwUndoMergeTbl()3094 SwUndoMergeTbl::~SwUndoMergeTbl()
3095 {
3096 	delete pSavTbl;
3097 	delete pSavHdl;
3098 	delete pHistory;
3099 }
3100 
UndoImpl(::sw::UndoRedoContext & rContext)3101 void SwUndoMergeTbl::UndoImpl(::sw::UndoRedoContext & rContext)
3102 {
3103     SwDoc *const pDoc = & rContext.GetDoc();
3104     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3105 
3106 	pPam->DeleteMark();
3107 	SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
3108 	rIdx = nTblNode;
3109 
3110 	SwTableNode* pTblNd = rIdx.GetNode().FindTableNode();
3111 	SwTable* pTbl = &pTblNd->GetTable();
3112 
3113 	SwTableFmlUpdate aMsgHnt( pTbl );
3114 	aMsgHnt.eFlags = TBL_BOXPTR;
3115 	pDoc->UpdateTblFlds( &aMsgHnt );
3116 
3117 	//Lines fuer das Layout-Update herausuchen.
3118 	_FndBox aFndBox( 0, 0 );
3119 	aFndBox.SetTableLines( *pTbl );
3120 	aFndBox.DelFrms( *pTbl );
3121     // ? TL_CHART2: notification or locking of controller required ?
3122 
3123 	SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, sal_True, sal_False );
3124 
3125 	//Layout updaten
3126 	aFndBox.MakeFrms( *pTbl );
3127     // ? TL_CHART2: notification or locking of controller required ?
3128 
3129 	if( bWithPrev )
3130 	{
3131 		// den Namen umsetzen
3132 		pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() );
3133 		pSavHdl->RestoreAttr( pNew->GetTable() );
3134 	}
3135 	else
3136 		pTbl = &pNew->GetTable();
3137 	pTbl->GetFrmFmt()->SetName( aName );
3138 
3139 //	pSavTbl->CreateNew( *pTbl, sal_False );
3140 	pSavTbl->RestoreAttr( *pTbl );
3141 
3142 
3143 	if( pHistory )
3144 	{
3145 		pHistory->TmpRollback( pDoc, 0 );
3146 		pHistory->SetTmpEnd( pHistory->Count() );
3147 	}
3148 
3149 	// fuer die neue Tabelle die Frames anlegen
3150 	SwNodeIndex aTmpIdx( *pNew );
3151 	pNew->MakeFrms( &aTmpIdx );
3152 
3153 	// Cursor  irgendwo in den Content stellen
3154 	SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx );
3155 	pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3156 
3157 	ClearFEShellTabCols();
3158 
3159     // TL_CHART2: need to inform chart of probably changed cell names
3160     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
3161     if (pPCD)
3162     {
3163         pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() );
3164         pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() );
3165     }
3166 }
3167 
RedoImpl(::sw::UndoRedoContext & rContext)3168 void SwUndoMergeTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3169 {
3170     SwDoc *const pDoc = & rContext.GetDoc();
3171     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3172 
3173 	pPam->DeleteMark();
3174 	pPam->GetPoint()->nNode = nTblNode;
3175 	if( bWithPrev )
3176 		pPam->GetPoint()->nNode = nTblNode + 3;
3177 	else
3178 		pPam->GetPoint()->nNode = nTblNode;
3179 
3180 	pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3181 
3182 	ClearFEShellTabCols();
3183 }
3184 
RepeatImpl(::sw::RepeatContext & rContext)3185 void SwUndoMergeTbl::RepeatImpl(::sw::RepeatContext & rContext)
3186 {
3187     SwDoc *const pDoc = & rContext.GetDoc();
3188     SwPaM *const pPam = & rContext.GetRepeatPaM();
3189 
3190 	pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3191 	ClearFEShellTabCols();
3192 }
3193 
SaveFormula(SwHistory & rHistory)3194 void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory )
3195 {
3196 	if( !pHistory )
3197 		pHistory = new SwHistory;
3198 	pHistory->Move( 0, &rHistory );
3199 }
3200 
3201 
3202 //////////////////////////////////////////////////////////////////////////
3203 
InsertSort(SvUShorts & rArr,sal_uInt16 nIdx,sal_uInt16 * pInsPos)3204 void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos )
3205 {
3206 	sal_uInt16 nO	= rArr.Count(), nM, nU = 0;
3207 	if( nO > 0 )
3208 	{
3209 		nO--;
3210 		while( nU <= nO )
3211 		{
3212 			nM = nU + ( nO - nU ) / 2;
3213 			if( *(rArr.GetData() + nM) == nIdx )
3214 			{
3215 				ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3216 				return;
3217 			}
3218 			if( *(rArr.GetData() + nM) < nIdx )
3219 				nU = nM + 1;
3220 			else if( nM == 0 )
3221 				break;
3222 			else
3223 				nO = nM - 1;
3224 		}
3225 	}
3226 	rArr.Insert( nIdx, nU );
3227 	if( pInsPos )
3228 		*pInsPos = nU;
3229 }
3230 
InsertSort(SvULongs & rArr,sal_uLong nIdx,sal_uInt16 * pInsPos)3231 void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos )
3232 {
3233 	sal_uInt16 nO	= rArr.Count(), nM, nU = 0;
3234 	if( nO > 0 )
3235 	{
3236 		nO--;
3237 		while( nU <= nO )
3238 		{
3239 			nM = nU + ( nO - nU ) / 2;
3240 			if( *(rArr.GetData() + nM) == nIdx )
3241 			{
3242 				ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3243 				return;
3244 			}
3245 			if( *(rArr.GetData() + nM) < nIdx )
3246 				nU = nM + 1;
3247 			else if( nM == 0 )
3248 				break;
3249 			else
3250 				nO = nM - 1;
3251 		}
3252 	}
3253 	rArr.Insert( nIdx, nU );
3254 	if( pInsPos )
3255 		*pInsPos = nU;
3256 }
3257 
3258 #if defined( JP_DEBUG ) && defined(DBG_UTIL)
3259 
3260 
DumpDoc(SwDoc * pDoc,const String & rFileNm)3261 void DumpDoc( SwDoc* pDoc, const String& rFileNm )
3262 {
3263 	Writer* pWrt = SwIoSystem::GetWriter( "DEBUG" );
3264 	if( pWrt )
3265 	{
3266 		SvFileStream aStream( rFileNm, STREAM_STD_WRITE );
3267 		SwPaM* pPam = new SwPaM( pDoc, SwPosition( pDoc->GetNodes().EndOfContent ,
3268 												 pDoc->GetNodes().EndOfContent ));
3269 		pPam->Move( fnMoveBackward, fnGoDoc );
3270 		pPam->SetMark();
3271 		pPam->Move( fnMoveForward, fnGoDoc );
3272 
3273 		pWrt->Write( pPam, *pDoc, aStream, rFileNm.GetStr() );
3274 
3275 		delete pPam;
3276 	}
3277 }
CheckTable(const SwTable & rTbl)3278 void CheckTable( const SwTable& rTbl )
3279 {
3280 	const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
3281 	const SwTableSortBoxes& rSrtArr = pTblNd->GetTable().GetTabSortBoxes();
3282 	for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n )
3283 	{
3284 		const SwTableBox* pBox = rSrtArr[ n ];
3285 		const SwNode* pNd = pBox->GetSttNd();
3286 		ASSERT( rNds[ *pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode"  );
3287 	}
3288 }
3289 #endif
3290 
3291 
3292