xref: /trunk/main/sw/source/core/table/swtable.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <ctype.h>
32 #include <float.h>
33 #include <hintids.hxx>
34 #include <hints.hxx>  	// fuer SwAttrSetChg
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/shaditem.hxx>
37 #include <editeng/adjitem.hxx>
38 #include <editeng/colritem.hxx>
39 #include <sfx2/linkmgr.hxx>
40 #include <editeng/boxitem.hxx>
41 #include <fmtfsize.hxx>
42 #include <fmtornt.hxx>
43 #include <fmtpdsc.hxx>
44 #include <fldbas.hxx>
45 #include <fmtfld.hxx>
46 #include <frmatr.hxx>
47 #include <doc.hxx>
48 #include <docary.hxx> 	// fuer RedlineTbl()
49 #include <frame.hxx>
50 #include <swtable.hxx>
51 #include <ndtxt.hxx>
52 #include <tabcol.hxx>
53 #include <tabfrm.hxx>
54 #include <cellfrm.hxx>
55 #include <rowfrm.hxx>
56 #include <swserv.hxx>
57 #include <expfld.hxx>
58 #include <mdiexp.hxx>
59 #include <cellatr.hxx>
60 #include <txatbase.hxx>
61 #include <htmltbl.hxx>
62 #include <swtblfmt.hxx>
63 #include <ndindex.hxx>
64 #include <tblrwcl.hxx>
65 #include <shellres.hxx>
66 #include <viewsh.hxx>
67 #include <redline.hxx>
68 #include <list>
69 #include <switerator.hxx>
70 
71 #ifndef DBG_UTIL
72 #define CHECK_TABLE(t)
73 #else
74 #ifdef DEBUG
75 #define CHECK_TABLE(t) (t).CheckConsistency();
76 #else
77 #define CHECK_TABLE(t)
78 #endif
79 #endif
80 
81 using namespace com::sun::star;
82 
83 TYPEINIT1( SwTable, SwClient );
84 TYPEINIT1( SwTableBox, SwClient );
85 TYPEINIT1( SwTableLine, SwClient );
86 TYPEINIT1( SwTableFmt, SwFrmFmt );
87 TYPEINIT1( SwTableBoxFmt, SwFrmFmt );
88 TYPEINIT1( SwTableLineFmt, SwFrmFmt );
89 
90 SV_IMPL_PTRARR(SwTableLines,SwTableLine*);
91 SV_IMPL_PTRARR(SwTableBoxes,SwTableBox*);
92 SV_IMPL_PTRARR_SORT(SwTableSortBoxes,SwTableBoxPtr);
93 
94 SV_IMPL_REF( SwServerObject )
95 
96 #define COLFUZZY 20
97 
98 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
99 					sal_Bool bChgAlign,sal_uLong nNdPos );
100 //----------------------------------
101 
102 class SwTableBox_Impl
103 {
104 	Color *mpUserColor, *mpNumFmtColor;
105     long mnRowSpan;
106     bool mbDummyFlag;
107 
108 	void SetNewCol( Color** ppCol, const Color* pNewCol );
109 public:
110 	SwTableBox_Impl() : mpUserColor(0), mpNumFmtColor(0), mnRowSpan(1),
111         mbDummyFlag( false ) {}
112 	~SwTableBox_Impl() { delete mpUserColor; delete mpNumFmtColor; }
113 
114 	const Color* GetSaveUserColor()	const		{ return mpUserColor; }
115 	const Color* GetSaveNumFmtColor() const 	{ return mpNumFmtColor; }
116 	void SetSaveUserColor(const Color* p )		{ SetNewCol( &mpUserColor, p ); }
117 	void SetSaveNumFmtColor( const Color* p )	{ SetNewCol( &mpNumFmtColor, p ); }
118     long getRowSpan() const { return mnRowSpan; }
119     void setRowSpan( long nNewRowSpan ) { mnRowSpan = nNewRowSpan; }
120     bool getDummyFlag() const { return mbDummyFlag; }
121     void setDummyFlag( bool bDummy ) { mbDummyFlag = bDummy; }
122 };
123 
124 // ----------- Inlines -----------------------------
125 
126 inline const Color* SwTableBox::GetSaveUserColor() const
127 {
128 	return pImpl ? pImpl->GetSaveUserColor() : 0;
129 }
130 
131 inline const Color* SwTableBox::GetSaveNumFmtColor() const
132 {
133 	return pImpl ? pImpl->GetSaveNumFmtColor() : 0;
134 }
135 
136 inline void SwTableBox::SetSaveUserColor(const Color* p )
137 {
138 	if( pImpl )
139 		pImpl->SetSaveUserColor( p );
140 	else if( p )
141 		( pImpl = new SwTableBox_Impl ) ->SetSaveUserColor( p );
142 }
143 
144 inline void SwTableBox::SetSaveNumFmtColor( const Color* p )
145 {
146 	if( pImpl )
147 		pImpl->SetSaveNumFmtColor( p );
148 	else if( p )
149 		( pImpl = new SwTableBox_Impl )->SetSaveNumFmtColor( p );
150 }
151 
152 long SwTableBox::getRowSpan() const
153 {
154     return pImpl ? pImpl->getRowSpan() : 1;
155 }
156 
157 void SwTableBox::setRowSpan( long nNewRowSpan )
158 {
159     if( !pImpl )
160     {
161         if( nNewRowSpan == 1 )
162             return;
163         pImpl = new SwTableBox_Impl();
164     }
165     pImpl->setRowSpan( nNewRowSpan );
166 }
167 
168 bool SwTableBox::getDummyFlag() const
169 {
170     return pImpl ? pImpl->getDummyFlag() : false;
171 }
172 
173 void SwTableBox::setDummyFlag( bool bDummy )
174 {
175     if( !pImpl )
176     {
177         if( !bDummy )
178             return;
179         pImpl = new SwTableBox_Impl();
180     }
181     pImpl->setDummyFlag( bDummy );
182 }
183 
184 //JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten)
185 String& lcl_TabToBlankAtSttEnd( String& rTxt )
186 {
187 	sal_Unicode c;
188 	xub_StrLen n;
189 
190 	for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
191 		if( '\x9' == c )
192 			rTxt.SetChar( n, ' ' );
193 	for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
194 		if( '\x9' == c )
195 			rTxt.SetChar( n, ' ' );
196 	return rTxt;
197 }
198 
199 String& lcl_DelTabsAtSttEnd( String& rTxt )
200 {
201 	sal_Unicode c;
202 	xub_StrLen n;
203 
204 	for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
205 		if( '\x9' == c )
206 			rTxt.Erase( n--, 1 );
207 	for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
208 		if( '\x9' == c )
209 			rTxt.Erase( n, 1 );
210 	return rTxt;
211 }
212 
213 void _InsTblBox( SwDoc* pDoc, SwTableNode* pTblNd,
214 						SwTableLine* pLine, SwTableBoxFmt* pBoxFrmFmt,
215 						SwTableBox* pBox,
216 						sal_uInt16 nInsPos, sal_uInt16 nCnt )
217 {
218 	ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
219 	SwNodeIndex aIdx( *pBox->GetSttNd(), +1 );
220 	SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
221 	if( !pCNd )
222 		pCNd = pDoc->GetNodes().GoNext( &aIdx );
223 	ASSERT( pCNd, "Box ohne ContentNode" );
224 
225 	if( pCNd->IsTxtNode() )
226 	{
227 		if( pBox->GetSaveNumFmtColor() && pCNd->GetpSwAttrSet() )
228 		{
229 			SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() );
230 			if( pBox->GetSaveUserColor() )
231 				aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR ));
232 			else
233 				aAttrSet.ClearItem( RES_CHRATR_COLOR );
234 			pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
235 									((SwTxtNode*)pCNd)->GetTxtColl(),
236 									&aAttrSet, nInsPos, nCnt );
237 		}
238 		else
239 			pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
240 									((SwTxtNode*)pCNd)->GetTxtColl(),
241 									pCNd->GetpSwAttrSet(),
242 									nInsPos, nCnt );
243 	}
244 	else
245 		pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
246 				(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
247 				nInsPos, nCnt );
248 
249     long nRowSpan = pBox->getRowSpan();
250     if( nRowSpan != 1 )
251     {
252 		SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
253         for( sal_uInt16 i = 0; i < nCnt; ++i )
254         {
255             pBox = rTblBoxes[ i + nInsPos ];
256             pBox->setRowSpan( nRowSpan );
257         }
258     }
259 }
260 
261 /*************************************************************************
262 |*
263 |*	SwTable::SwTable()
264 |*
265 |*************************************************************************/
266 SwTable::SwTable( SwTableFmt* pFmt )
267 	: SwClient( pFmt ),
268 	pHTMLLayout( 0 ),
269     pTableNode( 0 ),
270 	nGrfsThatResize( 0 ),
271     nRowsToRepeat( 1 ),
272     bModifyLocked( sal_False ),
273     bNewModel( sal_True )
274 {
275 	// default Wert aus den Optionen setzen
276 	eTblChgMode = (TblChgMode)GetTblChgDefaultMode();
277 }
278 
279 SwTable::SwTable( const SwTable& rTable )
280 	: SwClient( rTable.GetFrmFmt() ),
281 	pHTMLLayout( 0 ),
282     pTableNode( 0 ),
283 	eTblChgMode( rTable.eTblChgMode ),
284 	nGrfsThatResize( 0 ),
285     nRowsToRepeat( rTable.GetRowsToRepeat() ),
286     bModifyLocked( sal_False ),
287     bNewModel( rTable.bNewModel )
288 {
289 }
290 
291 void DelBoxNode( SwTableSortBoxes& rSortCntBoxes )
292 {
293 	for( sal_uInt16 n = 0; n < rSortCntBoxes.Count(); ++n )
294 		rSortCntBoxes[ n ]->pSttNd = 0;
295 }
296 
297 SwTable::~SwTable()
298 {
299 	if( refObj.Is() )
300 	{
301 		SwDoc* pDoc = GetFrmFmt()->GetDoc();
302 		if( !pDoc->IsInDtor() )			// dann aus der Liste entfernen
303 			pDoc->GetLinkManager().RemoveServer( &refObj );
304 
305 		refObj->Closed();
306 	}
307 
308 	// ist die Tabelle der letzte Client im FrameFormat, kann dieses
309 	// geloescht werden
310 	SwTableFmt* pFmt = (SwTableFmt*)GetFrmFmt();
311 	pFmt->Remove( this );				// austragen,
312 
313 	if( !pFmt->GetDepends() )
314 		pFmt->GetDoc()->DelTblFrmFmt( pFmt );	// und loeschen
315 
316 	// Loesche die Pointer aus dem SortArray der Boxen, die
317 	// Objecte bleiben erhalten und werden vom DTOR der Lines/Boxes
318 	// Arrays geloescht.
319 	//JP: reicht leider nicht, es muessen die Pointer auf den StartNode
320 	//	der Section geloescht werden
321 	DelBoxNode( aSortCntBoxes );
322 	aSortCntBoxes.Remove( (sal_uInt16)0, aSortCntBoxes.Count() );
323 	delete pHTMLLayout;
324 }
325 
326 /*************************************************************************
327 |*
328 |*	SwTable::Modify()
329 |*
330 |*************************************************************************/
331 inline void FmtInArr( SvPtrarr& rFmtArr, SwFmt* pBoxFmt )
332 {
333 	sal_Bool bRet = USHRT_MAX != rFmtArr.GetPos( (VoidPtr)pBoxFmt );
334 	if( !bRet )
335 		rFmtArr.Insert( (VoidPtr)pBoxFmt, rFmtArr.Count() );
336 }
337 
338 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
339 						 const long nNew, SvPtrarr& rFmtArr );
340 
341 void lcl_ModifyLines( SwTableLines &rLines, const long nOld,
342 						 const long nNew, SvPtrarr& rFmtArr, const bool bCheckSum )
343 {
344 	for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
345 		::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFmtArr );
346     if( bCheckSum )
347     {
348         for( sal_uInt16 i = 0; i < rFmtArr.Count(); ++i )
349         {
350             SwFmt* pFmt = (SwFmt*)rFmtArr[i];
351             sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
352             nBox *= nNew;
353             nBox /= nOld;
354 			SwFmtFrmSize aNewBox( ATT_VAR_SIZE, SwTwips(nBox), 0 );
355 			pFmt->LockModify();
356             pFmt->SetFmtAttr( aNewBox );
357 			pFmt->UnlockModify();
358         }
359     }
360 }
361 
362 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
363 						 const long nNew, SvPtrarr& rFmtArr )
364 {
365     sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths
366     sal_uInt64 nOriginalSum = 0; // Sum of original widths
367 	for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
368 	{
369 		SwTableBox &rBox = *rBoxes[i];
370 		if ( rBox.GetTabLines().Count() )
371         {
372             // For SubTables the rounding problem will not be solved :-(
373 			::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFmtArr, false );
374         }
375 		//Die Box anpassen
376 		SwFrmFmt *pFmt = rBox.GetFrmFmt();
377         sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
378         nOriginalSum += nBox;
379         nBox *= nNew;
380         nBox /= nOld;
381         sal_uInt64 nWishedSum = nOriginalSum;
382         nWishedSum *= nNew;
383         nWishedSum /= nOld;
384         nWishedSum -= nSum;
385         if( nWishedSum > 0 )
386         {
387             if( nBox == nWishedSum )
388                 FmtInArr( rFmtArr, pFmt );
389             else
390             {
391                 nBox = nWishedSum;
392                 pFmt = rBox.ClaimFrmFmt();
393                 SwFmtFrmSize aNewBox( ATT_VAR_SIZE, static_cast< SwTwips >(nBox), 0 );
394                 pFmt->LockModify();
395                 pFmt->SetFmtAttr( aNewBox );
396                 pFmt->UnlockModify();
397             }
398         }
399         else {
400             ASSERT( false, "Rounding error" );
401         }
402         nSum += nBox;
403 	}
404 }
405 
406 void SwTable::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
407 {
408 	// fange SSize Aenderungen ab, um die Lines/Boxen anzupassen
409 	sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
410 	const SwFmtFrmSize* pNewSize = 0, *pOldSize = 0;
411 
412 	if( RES_ATTRSET_CHG == nWhich )
413 	{
414 		if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState(
415 			RES_FRM_SIZE, sal_False, (const SfxPoolItem**)&pNewSize ))
416 			pOldSize = &((SwAttrSetChg*)pOld)->GetChgSet()->GetFrmSize();
417 	}
418 	else if( RES_FRM_SIZE == nWhich )
419 	{
420 		pOldSize = (const SwFmtFrmSize*)pOld;
421 		pNewSize = (const SwFmtFrmSize*)pNew;
422 	}
423     else
424         CheckRegistration( pOld, pNew );
425 
426 	if( pOldSize || pNewSize )
427 	{
428 		if ( !IsModifyLocked() )
429 		{
430 			ASSERT( pOldSize && pOldSize->Which() == RES_FRM_SIZE &&
431 					pNewSize && pNewSize->Which() == RES_FRM_SIZE,
432 					"Kein Old oder New fuer FmtFrmSize-Modify der SwTable." );
433             AdjustWidths( pOldSize->GetWidth(), pNewSize->GetWidth() );
434 		}
435 	}
436 }
437 
438 void SwTable::AdjustWidths( const long nOld, const long nNew )
439 {
440     SvPtrarr aFmtArr( (sal_uInt8)aLines[0]->GetTabBoxes().Count(), 1 );
441     ::lcl_ModifyLines( aLines, nOld, nNew, aFmtArr, true );
442 }
443 
444 /*************************************************************************
445 |*
446 |*	SwTable::GetTabCols()
447 |*
448 |*************************************************************************/
449 void lcl_RefreshHidden( SwTabCols &rToFill, sal_uInt16 nPos )
450 {
451 	for ( sal_uInt16 i = 0; i < rToFill.Count(); ++i )
452 	{
453 		if ( Abs((long)(nPos - rToFill[i])) <= COLFUZZY )
454 		{
455             rToFill.SetHidden( i, sal_False );
456 			break;
457 		}
458 	}
459 }
460 
461 void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox,
462                    const SwFrmFmt *pTabFmt, const sal_Bool bHidden,
463 				   const FASTBOOL bRefreshHidden )
464 {
465 	const long nWish = pTabFmt->GetFrmSize().GetWidth();
466 	const long nAct  = rToFill.GetRight() - rToFill.GetLeft();  // +1 why?
467 
468 	//Der Wert fuer die linke Kante der Box errechnet sich aus den
469 	//Breiten der vorhergehenden Boxen.
470 	sal_uInt16 nPos = 0;
471     sal_uInt16 nSum = 0;
472     sal_uInt16 nLeftMin = 0;
473     sal_uInt16 nRightMax = 0;
474 	const SwTableBox  *pCur  = pBox;
475 	const SwTableLine *pLine = pBox->GetUpper();
476 	while ( pLine )
477 	{	const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
478 		for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
479 		{
480             SwTwips nWidth = rBoxes[i]->GetFrmFmt()->GetFrmSize().GetWidth();
481             nSum = (sal_uInt16)(nSum + nWidth);
482 			sal_uInt64 nTmp = nSum;
483             nTmp *= nAct;
484 			nTmp /= nWish;
485             if (rBoxes[i] != pCur)
486             {
487                 if ( pLine == pBox->GetUpper() || 0 == nLeftMin )
488                     nLeftMin = (sal_uInt16)(nTmp - nPos);
489 			    nPos = (sal_uInt16)nTmp;
490             }
491             else
492             {
493                 nSum = (sal_uInt16)(nSum - nWidth);
494                 if ( 0 == nRightMax )
495                     nRightMax = (sal_uInt16)(nTmp - nPos);
496                 break;
497             }
498 		}
499 		pCur  = pLine->GetUpper();
500 		pLine = pCur ? pCur->GetUpper() : 0;
501 	}
502 
503     sal_Bool bInsert = !bRefreshHidden;
504 	for ( sal_uInt16 j = 0; bInsert && (j < rToFill.Count()); ++j )
505 	{
506         long nCmp = rToFill[j];
507 		if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
508 			 (nPos <= (nCmp + COLFUZZY)) )
509 		{
510 			bInsert = sal_False;		//Hat ihn schon.
511 		}
512 		else if ( nPos < nCmp )
513 		{
514     		bInsert = sal_False;
515             rToFill.Insert( nPos, bHidden, j );
516 		}
517 	}
518 	if ( bInsert )
519         rToFill.Insert( nPos, bHidden, rToFill.Count() );
520 	else if ( bRefreshHidden )
521 		::lcl_RefreshHidden( rToFill, nPos );
522 
523     if ( bHidden && !bRefreshHidden )
524     {
525         // calculate minimum/maximum values for the existing entries:
526         nLeftMin = nPos - nLeftMin;
527         nRightMax = nPos + nRightMax;
528 
529         // check if nPos is entry:
530         bool bFoundPos = false;
531         bool bFoundMax = false;
532     	for ( sal_uInt16 j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j )
533         {
534             SwTabColsEntry& rEntry = rToFill.GetEntry( j );
535             long nCmp = rToFill[j];
536 
537             if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
538 			     (nPos <= (nCmp + COLFUZZY)) )
539             {
540                 // check if nLeftMin is > old minimum for entry nPos:
541                 const long nOldMin = rEntry.nMin;
542                 if ( nLeftMin > nOldMin )
543                     rEntry.nMin = nLeftMin;
544                 // check if nRightMin is < old maximum for entry nPos:
545                 const long nOldMax = rEntry.nMax;
546                 if ( nRightMax < nOldMax )
547                     rEntry.nMax = nRightMax;
548 
549                 bFoundPos = true;
550             }
551 	    	else if ( (nRightMax >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
552 			          (nRightMax <= (nCmp + COLFUZZY)) )
553             {
554                 // check if nPos is > old minimum for entry nRightMax:
555                 const long nOldMin = rEntry.nMin;
556                 if ( nPos > nOldMin )
557                     rEntry.nMin = nPos;
558 
559                 bFoundMax = true;
560             }
561         }
562     }
563 }
564 
565 void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill,
566 						const SwFrmFmt *pTabFmt, FASTBOOL bRefreshHidden )
567 {
568 	if ( pBox->GetTabLines().Count() )
569 	{
570 		const SwTableLines &rLines = pBox->GetTabLines();
571 		for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
572 		{	const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
573 			for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
574 				::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFmt, bRefreshHidden);
575 		}
576 	}
577 	else
578 		::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_False, bRefreshHidden );
579 }
580 
581 void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill,
582 						 const SwFrmFmt *pTabFmt )
583 {
584 	for ( sal_uInt16 i = 0; i < pLine->GetTabBoxes().Count(); ++i )
585 	{
586 		const SwTableBox *pBox = pLine->GetTabBoxes()[i];
587 		if ( pBox->GetSttNd() )
588 			::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_True, sal_False );
589 		else
590 			for ( sal_uInt16 j = 0; j < pBox->GetTabLines().Count(); ++j )
591 				::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFmt );
592 	}
593 }
594 
595 // MS: Sonst Absturz auf der DEC-Kiste
596 //
597 #if defined(ALPHA) && defined(WNT)
598 #pragma optimize("", off)
599 #endif
600 
601 void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart,
602 			  sal_Bool bRefreshHidden, sal_Bool bCurRowOnly ) const
603 {
604 	//MA 30. Nov. 95: Opt: wenn bHidden gesetzt ist, wird nur das Hidden
605 	//Array aktualisiert.
606 	if ( bRefreshHidden )
607 	{
608 		//Korrekturen entfernen
609 		sal_uInt16 i;
610 		for ( i = 0; i < rToFill.Count(); ++i )
611         {
612             SwTabColsEntry& rEntry = rToFill.GetEntry( i );
613             rEntry.nPos -= rToFill.GetLeft();
614             rEntry.nMin -= rToFill.GetLeft();
615             rEntry.nMax -= rToFill.GetLeft();
616         }
617 
618 		//Alle sind hidden, dann die sichtbaren eintragen.
619         for ( i = 0; i < rToFill.Count(); ++i )
620             rToFill.SetHidden( i, sal_True );
621 	}
622 	else
623 	{
624 		rToFill.Remove( 0, rToFill.Count() );
625     }
626 
627 	//Eingetragen werden:
628 	//1. Alle Boxen unterhalb der dem Start uebergeordneten Line sowie
629 	//	 deren untergeordnete Boxen falls vorhanden.
630 	//2. Ausgehend von der Line die uebergeordnete Box sowie deren Nachbarn;
631 	//	 nicht aber deren untergeordnete.
632 	//3. Mit der der Boxenkette uebergeordneten Line wieder wie 2. bis einer
633 	//	 Line keine Box (sondern die Table) uebergeordnet ist.
634 	//Es werden nur diejenigen Boxen eingetragen, die keine weiteren Zeilen
635 	//enhalten. Die eintragende Funktion sorgt dafuer, dass keine doppelten
636 	//eingetragen werden. Um dies zu gewaehrleisten wird mit einer gewissen
637 	//Unschaerfe gearbeitet (um Rundungsfehler auszuschalten).
638 	//Es werden nur die linken Kanten der Boxen eingetragen.
639 	//Am Schluss wird der Erste wieder ausgetragen denn er ist bereits vom
640 	//Rand abgedeckt.
641 
642 	//4. Nochmalige abscannen der Tabelle und eintragen _aller_ Boxen,
643 	//	 jetzt aber als Hidden.
644 
645 	const SwFrmFmt *pTabFmt = GetFrmFmt();
646 
647 	//1.
648 	const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
649 
650     sal_uInt16 i;
651 	for ( i = 0; i < rBoxes.Count(); ++i )
652 		::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFmt, bRefreshHidden );
653 
654 	//2. und 3.
655 	const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
656 								pStart->GetUpper()->GetUpper()->GetUpper() : 0;
657 	while ( pLine )
658 	{
659         const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
660         for ( sal_uInt16 k = 0; k < rBoxes2.Count(); ++k )
661             ::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
662 									  pTabFmt, sal_False, bRefreshHidden );
663 		pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
664 	}
665 
666 	if ( !bRefreshHidden )
667 	{
668 		//4.
669 		if ( !bCurRowOnly )
670 		{
671 			for ( i = 0; i < aLines.Count(); ++i )
672 				::lcl_ProcessLineGet( aLines[i], rToFill, pTabFmt );
673 		}
674 
675 		rToFill.Remove( 0, 1 );
676     }
677 
678 	//Die Koordinaten sind jetzt relativ zum linken Rand der Tabelle - also
679 	//relativ zum nLeft vom SwTabCols. Die Werte werden aber relativ zum
680 	//linken Rand - also nLeftMin vom SwTabCols - erwartet.
681 	//Alle Werte muessen also um nLeft erweitert werden.
682 	for ( i = 0; i < rToFill.Count(); ++i )
683     {
684         SwTabColsEntry& rEntry = rToFill.GetEntry( i );
685         rEntry.nPos += rToFill.GetLeft();
686         rEntry.nMin += rToFill.GetLeft();
687         rEntry.nMax += rToFill.GetLeft();
688     }
689 }
690 
691 #if defined(ALPHA) && defined(WNT)
692 #pragma optimize("", on)
693 #endif
694 
695 /*************************************************************************
696 |*
697 |*	SwTable::SetTabCols()
698 |*
699 |*************************************************************************/
700 //Struktur zur Parameteruebergabe
701 struct Parm
702 {
703 	const SwTabCols &rNew;
704 	const SwTabCols &rOld;
705 	long nNewWish,
706 		 nOldWish;
707 	SvPtrarr aBoxArr;
708 	SwShareBoxFmts aShareFmts;
709 
710 	Parm( const SwTabCols &rN, const SwTabCols &rO ) :
711 		rNew( rN ), rOld( rO ), aBoxArr( 10, 1 ) {}
712 };
713 inline sal_Bool BoxInArr( SvPtrarr& rArr, SwTableBox* pBox )
714 {
715 	sal_Bool bRet = USHRT_MAX != rArr.GetPos( (VoidPtr)pBox );
716 	if( !bRet )
717 		rArr.Insert( (VoidPtr)pBox, rArr.Count() );
718 	return bRet;
719 }
720 
721 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm );
722 
723 void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
724 {
725 	SwTableBoxes &rBoxes = pLine->GetTabBoxes();
726 	for ( int i = rBoxes.Count()-1; i >= 0; --i )
727         ::lcl_ProcessBoxSet( rBoxes[ static_cast< sal_uInt16 >(i) ], rParm );
728 }
729 
730 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
731 {
732 	if ( pBox->GetTabLines().Count() )
733 	{	SwTableLines &rLines = pBox->GetTabLines();
734 		for ( int i = rLines.Count()-1; i >= 0; --i )
735             lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], rParm );
736 	}
737 	else
738 	{
739 		//Aktuelle Position (linke und rechte Kante berechnen) und im
740 		//alten TabCols suchen. Im neuen TabCols die Werte vergleichen und
741 		//wenn es Unterschiede gibt die Box entsprechend anpassen.
742 		//Wenn an der veraenderten Kante kein Nachbar existiert werden auch
743 		//alle uebergeordneten Boxen angepasst.
744 
745 		const long nOldAct = rParm.rOld.GetRight() -
746 							 rParm.rOld.GetLeft(); // +1 why?
747 
748 		//Der Wert fuer die linke Kante der Box errechnet sich aus den
749 		//Breiten der vorhergehenden Boxen plus dem linken Rand
750 		long nLeft = rParm.rOld.GetLeft();
751 		const  SwTableBox  *pCur  = pBox;
752 		const  SwTableLine *pLine = pBox->GetUpper();
753 
754 		while ( pLine )
755 		{	const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
756 			for ( sal_uInt16 i = 0; (i < rBoxes.Count()) && (rBoxes[i] != pCur); ++i)
757 			{
758 				sal_uInt64 nWidth = rBoxes[i]->GetFrmFmt()->
759 										GetFrmSize().GetWidth();
760 				nWidth *= nOldAct;
761 				nWidth /= rParm.nOldWish;
762 				nLeft += (sal_uInt16)nWidth;
763 			}
764 			pCur  = pLine->GetUpper();
765 			pLine = pCur ? pCur->GetUpper() : 0;
766 		}
767 		long nLeftDiff;
768 		long nRightDiff = 0;
769 		if ( nLeft != rParm.rOld.GetLeft() ) //Es gibt noch Boxen davor.
770 		{
771 			//Rechte Kante ist linke Kante plus Breite.
772 			sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
773 			nWidth *= nOldAct;
774 			nWidth /= rParm.nOldWish;
775 			long nRight = nLeft + (long)nWidth;
776 			sal_uInt16 nLeftPos  = USHRT_MAX,
777 				   nRightPos = USHRT_MAX;
778 			for ( sal_uInt16 i = 0; i < rParm.rOld.Count(); ++i )
779 			{
780 				if ( nLeft >= (rParm.rOld[i] - COLFUZZY) &&
781 					 nLeft <= (rParm.rOld[i] + COLFUZZY) )
782 					nLeftPos = i;
783 				else if ( nRight >= (rParm.rOld[i] - COLFUZZY) &&
784 						  nRight <= (rParm.rOld[i] + COLFUZZY) )
785 					nRightPos = i;
786 			}
787 			nLeftDiff = nLeftPos != USHRT_MAX ?
788 					(int)rParm.rOld[nLeftPos] - (int)rParm.rNew[nLeftPos] : 0;
789 			nRightDiff= nRightPos!= USHRT_MAX ?
790 					(int)rParm.rNew[nRightPos] - (int)rParm.rOld[nRightPos] : 0;
791 		}
792 		else	//Die erste Box.
793 		{
794 			nLeftDiff = (long)rParm.rOld.GetLeft() - (long)rParm.rNew.GetLeft();
795 			if ( rParm.rOld.Count() )
796 			{
797 				//Differnz zu der Kante berechnen, von der die erste Box
798 				//beruehrt wird.
799 				sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
800 				nWidth *= nOldAct;
801 				nWidth /= rParm.nOldWish;
802 				long nTmp = (long)nWidth;
803 				nTmp += rParm.rOld.GetLeft();
804 				sal_uInt16 nLeftPos = USHRT_MAX;
805 				for ( sal_uInt16 i = 0; i < rParm.rOld.Count() &&
806 									nLeftPos == USHRT_MAX; ++i )
807 				{
808 					if ( nTmp >= (rParm.rOld[i] - COLFUZZY) &&
809 						 nTmp <= (rParm.rOld[i] + COLFUZZY) )
810 						nLeftPos = i;
811 				}
812 				if ( nLeftPos != USHRT_MAX )
813 					nRightDiff = (long)rParm.rNew[nLeftPos] -
814 								 (long)rParm.rOld[nLeftPos];
815 			}
816 //MA 11. Feb. 99: #61577# 0 sollte doch gerade richtig sein, weil die
817 //Kante doch schon in SetTabCols() korrigiert wurde.
818 //			else
819 //				nRightDiff = (long)rParm.rNew.GetRight() -
820 //							 (long)rParm.rOld.GetRight();
821 		}
822 
823         if( pBox->getRowSpan() == 1 )
824         {
825             SwTableBoxes& rTblBoxes = pBox->GetUpper()->GetTabBoxes();
826             sal_uInt16 nPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox );
827             if( nPos && rTblBoxes[ nPos - 1 ]->getRowSpan() != 1 )
828                 nLeftDiff = 0;
829             if( nPos + 1 < rTblBoxes.Count() &&
830                 rTblBoxes[ nPos + 1 ]->getRowSpan() != 1 )
831                 nRightDiff = 0;
832         }
833         else
834             nLeftDiff = nRightDiff = 0;
835 
836 		if ( nLeftDiff || nRightDiff )
837 		{
838 			//Die Differenz ist der tatsaechliche Differenzbetrag; die
839 			//Attribute der Boxen um diesen Betrag anzupassen macht keinen
840 			//Sinn wenn die Tabelle gestrecht ist. Der Differenzbetrag muss
841 			//entsprechend umgerechnet werden.
842 			long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
843 			nLeftDiff *= rParm.nNewWish;
844 			nLeftDiff /= nTmp;
845 			nRightDiff *= rParm.nNewWish;
846 			nRightDiff /= nTmp;
847 			long nDiff = nLeftDiff + nRightDiff;
848 
849 			//Box und alle uebergeordneten um den Differenzbetrag anpassen.
850             while ( pBox )
851 			{
852                 SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
853                 aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
854                 if ( aFmtFrmSize.GetWidth() < 0 )
855                     aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
856                 rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
857 
858                 // The outer cells of the last row are responsible to adjust a surrounding cell.
859                 // Last line check:
860                 if ( pBox->GetUpper()->GetUpper() &&
861                      pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines()
862                         [pBox->GetUpper()->GetUpper()->GetTabLines().Count()-1])
863                 {
864                    pBox = 0;
865                 }
866                 else
867                 {
868                     // Middle cell check:
869                     if ( pBox != pBox->GetUpper()->GetTabBoxes()[0] )
870                         nDiff = nRightDiff;
871 
872                     if ( pBox != pBox->GetUpper()->GetTabBoxes()
873                                 [pBox->GetUpper()->GetTabBoxes().Count()-1] )
874                         nDiff -= nRightDiff;
875 
876                     pBox = nDiff ? pBox->GetUpper()->GetUpper() : 0;
877                 }
878             }
879 		}
880 	}
881 }
882 
883 void lcl_ProcessBoxPtr( SwTableBox *pBox, SvPtrarr &rBoxArr,
884 						   sal_Bool bBefore )
885 {
886 	if ( pBox->GetTabLines().Count() )
887 	{
888 		const SwTableLines &rLines = pBox->GetTabLines();
889 		for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
890 		{
891 			const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
892 			for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
893 				::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore );
894 		}
895 	}
896 	else if ( bBefore )
897 		rBoxArr.Insert( (VoidPtr)pBox, 0 );
898 	else
899 		rBoxArr.Insert( (VoidPtr)pBox, rBoxArr.Count() );
900 }
901 
902 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm );
903 
904 void lcl_AdjustLines( SwTableLines &rLines, const long nDiff, Parm &rParm )
905 {
906 	for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
907 	{
908 		SwTableBox *pBox = rLines[i]->GetTabBoxes()
909 								[rLines[i]->GetTabBoxes().Count()-1];
910 		lcl_AdjustBox( pBox, nDiff, rParm );
911 	}
912 }
913 
914 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm )
915 {
916 	if ( pBox->GetTabLines().Count() )
917 		::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm );
918 
919 	//Groesse der Box anpassen.
920 	SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
921 	aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
922 //#30009#		if ( aFmtFrmSize.GetWidth() < 0 )
923 //			aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
924 
925 	rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
926 }
927 
928 void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld,
929 						  const SwTableBox *pStart, sal_Bool bCurRowOnly )
930 {
931     CHECK_TABLE( *this )
932 
933 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
934 
935     // FME: Made rOld const. The caller is responsible for passing correct
936     // values of rOld. Therefore we do not have to call GetTabCols anymore:
937     //GetTabCols( rOld, pStart );
938 
939 	Parm aParm( rNew, rOld );
940 
941 	ASSERT( rOld.Count() == rNew.Count(), "Columnanzahl veraendert.");
942 
943 	//Raender verarbeiten. Groesse der Tabelle und ein paar Boxen mussen
944 	//angepasst werden. Bei der Groesseneinstellung darf allerdings das
945 	//Modify nicht verarbeitet werden - dieses wuerde alle Boxen anpassen
946 	//und das koennen wir ueberhaupt nicht gebrauchen.
947 	SwFrmFmt *pFmt = GetFrmFmt();
948 	aParm.nOldWish = aParm.nNewWish = pFmt->GetFrmSize().GetWidth();
949 	if ( (rOld.GetLeft() != rNew.GetLeft()) ||
950 		 (rOld.GetRight()!= rNew.GetRight()) )
951 	{
952 		LockModify();
953 		{
954 			SvxLRSpaceItem aLR( pFmt->GetLRSpace() );
955             SvxShadowItem aSh( pFmt->GetShadow() );
956 
957             SwTwips nShRight = aSh.CalcShadowSpace( SHADOW_RIGHT );
958             SwTwips nShLeft = aSh.CalcShadowSpace( SHADOW_LEFT );
959 
960 			aLR.SetLeft ( rNew.GetLeft() - nShLeft );
961             aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight );
962             pFmt->SetFmtAttr( aLR );
963 
964 			//Die Ausrichtung der Tabelle muss entsprechend angepasst werden,
965 			//das geschieht so, dass die Tabelle genauso stehenbleibt wie der
966 			//Anwender sie gerade hingezuppelt hat.
967 			SwFmtHoriOrient aOri( pFmt->GetHoriOrient() );
968 			if(text::HoriOrientation::NONE != aOri.GetHoriOrient())
969 			{
970 				const sal_Bool bLeftDist = rNew.GetLeft() != nShLeft;
971 				const sal_Bool bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax();
972 				if(!bLeftDist && !bRightDist)
973 					aOri.SetHoriOrient( text::HoriOrientation::FULL );
974 				else if(!bRightDist && rNew.GetLeft() > nShLeft )
975 					aOri.SetHoriOrient( text::HoriOrientation::RIGHT );
976 				else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax())
977 					aOri.SetHoriOrient( text::HoriOrientation::LEFT );
978 				else
979 					aOri.SetHoriOrient( text::HoriOrientation::NONE );
980 			}
981             pFmt->SetFmtAttr( aOri );
982 		}
983 		const long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why?
984 		long nTabDiff = 0;
985 
986 		if ( rOld.GetLeft() != rNew.GetLeft() )
987 		{
988 			nTabDiff = rOld.GetLeft() - rNew.GetLeft();
989 			nTabDiff *= aParm.nOldWish;
990 			nTabDiff /= nAct;
991 		}
992 		if ( rOld.GetRight() != rNew.GetRight() )
993 		{
994 			long nDiff = rNew.GetRight() - rOld.GetRight();
995 			nDiff *= aParm.nOldWish;
996 			nDiff /= nAct;
997 			nTabDiff += nDiff;
998             if( !IsNewModel() )
999                 ::lcl_AdjustLines( GetTabLines(), nDiff, aParm );
1000 		}
1001 
1002 		//Groesse der Tabelle anpassen. Es muss beachtet werden, das die
1003 		//Tabelle gestrecht sein kann.
1004 		if ( nTabDiff )
1005 		{
1006 			aParm.nNewWish += nTabDiff;
1007 			if ( aParm.nNewWish < 0 )
1008 				aParm.nNewWish = USHRT_MAX;	//Uuups! Eine Rolle rueckwaerts.
1009 			SwFmtFrmSize aSz( pFmt->GetFrmSize() );
1010 			if ( aSz.GetWidth() != aParm.nNewWish )
1011 			{
1012 				aSz.SetWidth( aParm.nNewWish );
1013 				aSz.SetWidthPercent( 0 );
1014                 pFmt->SetFmtAttr( aSz );
1015 			}
1016 		}
1017 		UnlockModify();
1018 	}
1019 
1020     if( IsNewModel() )
1021         NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly );
1022     else
1023 	{
1024 		if ( bCurRowOnly )
1025 		{
1026 			//Um die aktuelle Zeile anzupassen muessen wir analog zu dem
1027 			//Verfahren zum fuellen der TabCols (siehe GetTabCols()) die
1028 			//Boxen der aktuellen Zeile abklappern.
1029 			//Leider muessen wir auch hier dafuer sorgen, dass die Boxen von
1030 			//hinten nach vorne bzw. von innen nach aussen veraendert werden.
1031 			//Der beste Weg hierzu scheint mir darin zu liegen die
1032 			//entsprechenden Boxen in einem PtrArray vorzumerken.
1033 
1034 			const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
1035 			for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1036 				::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, sal_False );
1037 
1038 			const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
1039 									pStart->GetUpper()->GetUpper()->GetUpper() : 0;
1040 			const SwTableBox  *pExcl = pStart->GetUpper()->GetUpper();
1041 			while ( pLine )
1042 			{
1043                 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
1044 				sal_Bool bBefore = sal_True;
1045                 for ( sal_uInt16 i = 0; i < rBoxes2.Count(); ++i )
1046 				{
1047                     if ( rBoxes2[i] != pExcl )
1048                         ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore );
1049 					else
1050 						bBefore = sal_False;
1051 				}
1052 				pExcl = pLine->GetUpper();
1053 				pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
1054 			}
1055 			//Nachdem wir haufenweise Boxen (hoffentlich alle und in der richtigen
1056 			//Reihenfolge) eingetragen haben, brauchen diese nur noch rueckwaerts
1057 			//verarbeitet zu werden.
1058             for ( int j = aParm.aBoxArr.Count()-1; j >= 0; --j )
1059 			{
1060                 SwTableBox *pBox = (SwTableBox*)aParm.aBoxArr[ static_cast< sal_uInt16 >(j)];
1061 				::lcl_ProcessBoxSet( pBox, aParm );
1062 			}
1063 		}
1064 		else
1065 		{	//Die gesamte Tabelle anzupassen ist 'einfach'.
1066 			//Es werden alle Boxen, die keine Lines mehr enthalten angepasst.
1067 			//Diese Boxen passen alle uebergeordneten Boxen entsprechend mit an.
1068 			//Um uns nicht selbst hereinzulegen muss natuerlich rueckwaerst
1069 			//gearbeitet werden!
1070 			SwTableLines &rLines = GetTabLines();
1071 			for ( int i = rLines.Count()-1; i >= 0; --i )
1072                 ::lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], aParm );
1073 		}
1074 	}
1075 
1076 #ifdef DBG_UTIL
1077 	{
1078 // steht im tblrwcl.cxx
1079 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1080 		// checke doch mal ob die Tabellen korrekte Breiten haben
1081 		SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth();
1082 		for( sal_uInt16 n = 0; n < aLines.Count(); ++n  )
1083 			_CheckBoxWidth( *aLines[ n ], nSize );
1084 	}
1085 #endif
1086 }
1087 
1088 typedef std::pair<sal_uInt16, sal_uInt16> ColChange;
1089 typedef std::list< ColChange > ChangeList;
1090 
1091 static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew,
1092     Parm& rParm, sal_uInt16 nColFuzzy )
1093 {
1094     ChangeList::iterator pCurr = rOldNew.begin();
1095     if( pCurr == rOldNew.end() )
1096         return;
1097     sal_uInt16 nCount = pLine->GetTabBoxes().Count();
1098     sal_uInt16 i = 0;
1099     SwTwips nBorder = 0;
1100     SwTwips nRest = 0;
1101     while( i < nCount )
1102     {
1103         SwTableBox* pBox = pLine->GetTabBoxes()[i++];
1104         SwTwips nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1105         SwTwips nNewWidth = nWidth - nRest;
1106         nRest = 0;
1107         nBorder += nWidth;
1108         if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first )
1109         {
1110             nBorder -= nColFuzzy;
1111             while( pCurr != rOldNew.end() && nBorder > pCurr->first )
1112                 ++pCurr;
1113             if( pCurr != rOldNew.end() )
1114             {
1115                 nBorder += nColFuzzy;
1116                 if( nBorder + nColFuzzy >= pCurr->first )
1117                 {
1118                     if( pCurr->second == pCurr->first )
1119                         nRest = 0;
1120                     else
1121                         nRest = pCurr->second - nBorder;
1122                     nNewWidth += nRest;
1123                     ++pCurr;
1124                 }
1125             }
1126         }
1127         if( nNewWidth != nWidth )
1128         {
1129             if( nNewWidth < 0 )
1130             {
1131                 nRest += 1 - nNewWidth;
1132                 nNewWidth = 1;
1133             }
1134             SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
1135             aFmtFrmSize.SetWidth( nNewWidth );
1136             rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
1137         }
1138     }
1139 }
1140 
1141 static void lcl_CalcNewWidths( std::list<sal_uInt16> &rSpanPos, ChangeList& rChanges,
1142     SwTableLine* pLine, long nWish, long nWidth, bool bTop )
1143 {
1144     if( !rChanges.size() )
1145     {
1146         rSpanPos.clear();
1147         return;
1148     }
1149     if( !rSpanPos.size() )
1150     {
1151         rChanges.clear();
1152         return;
1153     }
1154     std::list<sal_uInt16> aNewSpanPos;
1155     ChangeList aNewChanges;
1156     ChangeList::iterator pCurr = rChanges.begin();
1157     aNewChanges.push_back( *pCurr ); // Nullposition
1158     std::list<sal_uInt16>::iterator pSpan = rSpanPos.begin();
1159     sal_uInt16 nCurr = 0;
1160     sal_uInt16 nOrgSum = 0;
1161     bool bRowSpan = false;
1162     sal_uInt16 nRowSpanCount = 0;
1163     sal_uInt16 nCount = pLine->GetTabBoxes().Count();
1164     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1165     {
1166         SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1167         SwTwips nCurrWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1168         const long nRowSpan = pBox->getRowSpan();
1169         const bool bCurrRowSpan = bTop ? nRowSpan < 0 :
1170             ( nRowSpan > 1 || nRowSpan < -1 );
1171         if( bRowSpan || bCurrRowSpan )
1172             aNewSpanPos.push_back( nRowSpanCount );
1173         bRowSpan = bCurrRowSpan;
1174         nOrgSum = (sal_uInt16)(nOrgSum + nCurrWidth);
1175         sal_uInt64 nSum = nOrgSum;
1176         nSum *= nWidth;
1177         nSum /= nWish;
1178         nSum *= nWish;
1179         nSum /= nWidth;
1180         sal_uInt16 nPos = (sal_uInt16)nSum;
1181         while( pCurr != rChanges.end() && pCurr->first < nPos )
1182         {
1183 #ifdef DBG_UTIL
1184             sal_uInt16 nTemp = pCurr->first;
1185             nTemp = pCurr->second;
1186 #endif
1187             ++nCurr;
1188             ++pCurr;
1189         }
1190         bool bNew = true;
1191         if( pCurr != rChanges.end() && pCurr->first <= nPos &&
1192             pCurr->first != pCurr->second )
1193         {
1194             while( pSpan != rSpanPos.end() && *pSpan < nCurr )
1195                 ++pSpan;
1196             if( pSpan != rSpanPos.end() && *pSpan == nCurr )
1197             {
1198                 aNewChanges.push_back( *pCurr );
1199                 ++nRowSpanCount;
1200                 bNew = false;
1201             }
1202         }
1203         if( bNew )
1204         {
1205             ColChange aTmp( nPos, nPos );
1206             aNewChanges.push_back( aTmp );
1207             ++nRowSpanCount;
1208         }
1209     }
1210 
1211     pCurr = aNewChanges.begin();
1212     ChangeList::iterator pLast = pCurr;
1213     ChangeList::iterator pLeftMove = pCurr;
1214     while( pCurr != aNewChanges.end() )
1215     {
1216         if( pLeftMove == pCurr )
1217         {
1218             while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second )
1219                 ;
1220         }
1221         if( pCurr->second == pCurr->first )
1222         {
1223             if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second )
1224             {
1225                 if( pLeftMove->first == pLast->first )
1226                     pCurr->second = pLeftMove->second;
1227                 else
1228                 {
1229                     sal_uInt64 nTmp = pCurr->first - pLast->first;
1230                     nTmp *= pLeftMove->second - pLast->second;
1231                     nTmp /= pLeftMove->first - pLast->first;
1232                     nTmp += pLast->second;
1233                     pCurr->second = (sal_uInt16)nTmp;
1234                 }
1235             }
1236             pLast = pCurr;
1237             ++pCurr;
1238         }
1239         else if( pCurr->second > pCurr->first )
1240         {
1241             pLast = pCurr;
1242             ++pCurr;
1243             ChangeList::iterator pNext = pCurr;
1244             while( pNext != pLeftMove && pNext->second == pNext->first &&
1245                 pNext->second < pLast->second )
1246                 ++pNext;
1247             while( pCurr != pNext )
1248             {
1249                 if( pNext == aNewChanges.end() || pNext->first == pLast->first )
1250                     pCurr->second = pLast->second;
1251                 else
1252                 {
1253                     sal_uInt64 nTmp = pCurr->first - pLast->first;
1254                     nTmp *= pNext->second - pLast->second;
1255                     nTmp /= pNext->first - pLast->first;
1256                     nTmp += pLast->second;
1257                     pCurr->second = (sal_uInt16)nTmp;
1258                 }
1259                 ++pCurr;
1260             }
1261             pLast = pCurr;
1262         }
1263         else
1264         {
1265             pLast = pCurr;
1266             ++pCurr;
1267         }
1268     }
1269 
1270     rChanges.clear();
1271     ChangeList::iterator pCopy = aNewChanges.begin();
1272     while( pCopy != aNewChanges.end() )
1273         rChanges.push_back( *pCopy++ );
1274     rSpanPos.clear();
1275     std::list<sal_uInt16>::iterator pSpCopy = aNewSpanPos.begin();
1276     while( pSpCopy != aNewSpanPos.end() )
1277         rSpanPos.push_back( *pSpCopy++ );
1278 }
1279 
1280 void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew,
1281     const SwTabCols &rOld, const SwTableBox *pStart, sal_Bool bCurRowOnly )
1282 {
1283 #ifdef DBG_UTIL
1284     static int nCallCount = 0;
1285     ++nCallCount;
1286 #endif
1287     // First step: evaluate which lines have been moved/which widths changed
1288     ChangeList aOldNew;
1289     const long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1290     const long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1291     if( nNewWidth < 1 || nOldWidth < 1 )
1292         return;
1293     for( sal_uInt16 i = 0; i <= rOld.Count(); ++i )
1294     {
1295         sal_uInt64 nNewPos;
1296         sal_uInt64 nOldPos;
1297         if( i == rOld.Count() )
1298         {
1299             nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1300             nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1301         }
1302         else
1303         {
1304             nOldPos = rOld[i] - rParm.rOld.GetLeft();
1305             nNewPos = rNew[i] - rParm.rNew.GetLeft();
1306         }
1307         nNewPos *= rParm.nNewWish;
1308         nNewPos /= nNewWidth;
1309         nOldPos *= rParm.nOldWish;
1310         nOldPos /= nOldWidth;
1311         if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 )
1312         {
1313             ColChange aChg( (sal_uInt16)nOldPos, (sal_uInt16)nNewPos );
1314             aOldNew.push_back( aChg );
1315         }
1316     }
1317     // Finished first step
1318     int nCount = aOldNew.size();
1319     if( !nCount )
1320         return; // no change, nothing to do
1321     SwTableLines &rLines = GetTabLines();
1322     if( bCurRowOnly )
1323     {
1324         const SwTableLine* pCurrLine = pStart->GetUpper();
1325         sal_uInt16 nCurr = rLines.C40_GETPOS( SwTableLine, pCurrLine );
1326         if( nCurr >= USHRT_MAX )
1327             return;
1328 
1329         ColChange aChg( 0, 0 );
1330         aOldNew.push_front( aChg );
1331         std::list<sal_uInt16> aRowSpanPos;
1332         if( nCurr )
1333         {
1334             ChangeList aCopy;
1335             ChangeList::iterator pCop = aOldNew.begin();
1336             sal_uInt16 nPos = 0;
1337             while( pCop != aOldNew.end() )
1338             {
1339                 aCopy.push_back( *pCop );
1340                 ++pCop;
1341                 aRowSpanPos.push_back( nPos++ );
1342             }
1343             lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1344                 rParm.nOldWish, nOldWidth, true );
1345             bool bGoOn = aRowSpanPos.size() > 0;
1346             sal_uInt16 j = nCurr;
1347             while( bGoOn )
1348             {
1349                 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j],
1350                     rParm.nOldWish, nOldWidth, true );
1351                 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1352                 bGoOn = aRowSpanPos.size() > 0 && j > 0;
1353             };
1354             aRowSpanPos.clear();
1355         }
1356         if( nCurr+1 < rLines.Count() )
1357         {
1358             ChangeList aCopy;
1359             ChangeList::iterator pCop = aOldNew.begin();
1360             sal_uInt16 nPos = 0;
1361             while( pCop != aOldNew.end() )
1362             {
1363                 aCopy.push_back( *pCop );
1364                 ++pCop;
1365                 aRowSpanPos.push_back( nPos++ );
1366             }
1367             lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1368                 rParm.nOldWish, nOldWidth, false );
1369             bool bGoOn = aRowSpanPos.size() > 0;
1370             sal_uInt16 j = nCurr;
1371             while( bGoOn )
1372             {
1373                 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j],
1374                     rParm.nOldWish, nOldWidth, false );
1375                 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1376                 bGoOn = aRowSpanPos.size() > 0 && j+1 < rLines.Count();
1377             };
1378         }
1379         ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, 1 );
1380     }
1381     else for( sal_uInt16 i = 0; i < rLines.Count(); ++i )
1382         ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY );
1383     CHECK_TABLE( *this )
1384 }
1385 
1386 
1387 /*************************************************************************
1388 |*
1389 |*	const SwTableBox* SwTable::GetTblBox( const Strn?ng& rName ) const
1390 |*		gebe den Pointer auf die benannte Box zurueck.
1391 |*
1392 |*************************************************************************/
1393 
1394 sal_Bool IsValidRowName( const String& rStr )
1395 {
1396 	sal_Bool bIsValid = sal_True;
1397 	xub_StrLen nLen = rStr.Len();
1398 	for (xub_StrLen i = 0;  i < nLen && bIsValid;  ++i)
1399 	{
1400 		const sal_Unicode cChar = rStr.GetChar(i);
1401 		if (cChar < '0' || cChar > '9')
1402 			bIsValid = sal_False;
1403 	}
1404 	return bIsValid;
1405 }
1406 
1407 // --> OD 2007-08-03 #i80314#
1408 // add 3rd parameter and its handling
1409 sal_uInt16 SwTable::_GetBoxNum( String& rStr, sal_Bool bFirstPart,
1410                             const bool bPerformValidCheck )
1411 {
1412 	sal_uInt16 nRet = 0;
1413 	xub_StrLen nPos = 0;
1414     if( bFirstPart )   // sal_True == column; sal_False == row
1415 	{
1416 		// die 1. ist mit Buchstaben addressiert!
1417 		sal_Unicode cChar;
1418 		sal_Bool bFirst = sal_True;
1419 		while( 0 != ( cChar = rStr.GetChar( nPos )) &&
1420 			   ( (cChar >= 'A' && cChar <= 'Z') ||
1421 			     (cChar >= 'a' && cChar <= 'z') ) )
1422 		{
1423 			if( (cChar -= 'A') >= 26 )
1424 				cChar -= 'a' - '[';
1425 			if( bFirst )
1426 				bFirst = sal_False;
1427 			else
1428 				++nRet;
1429 			nRet = nRet * 52 + cChar;
1430 			++nPos;
1431 		}
1432 		rStr.Erase( 0, nPos );		// Zeichen aus dem String loeschen
1433 	}
1434 	else if( STRING_NOTFOUND == ( nPos = rStr.Search( aDotStr ) ))
1435 	{
1436         nRet = 0;
1437         if ( !bPerformValidCheck || IsValidRowName( rStr ) )
1438         {
1439 			nRet = static_cast<sal_uInt16>(rStr.ToInt32());
1440         }
1441 		rStr.Erase();
1442 	}
1443 	else
1444 	{
1445         nRet = 0;
1446 		String aTxt( rStr.Copy( 0, nPos ) );
1447         if ( !bPerformValidCheck || IsValidRowName( aTxt ) )
1448         {
1449 			nRet = static_cast<sal_uInt16>(aTxt.ToInt32());
1450         }
1451 		rStr.Erase( 0, nPos+1 );
1452 	}
1453 	return nRet;
1454 }
1455 // <--
1456 
1457 // --> OD 2007-08-03 #i80314#
1458 // add 2nd parameter and its handling
1459 const SwTableBox* SwTable::GetTblBox( const String& rName,
1460                                       const bool bPerformValidCheck ) const
1461 {
1462 	const SwTableBox* pBox = 0;
1463 	const SwTableLine* pLine;
1464 	const SwTableLines* pLines;
1465 	const SwTableBoxes* pBoxes;
1466 
1467 	sal_uInt16 nLine, nBox;
1468 	String aNm( rName );
1469 	while( aNm.Len() )
1470 	{
1471         nBox = SwTable::_GetBoxNum( aNm, 0 == pBox, bPerformValidCheck );
1472 		// erste Box ?
1473 		if( !pBox )
1474 			pLines = &GetTabLines();
1475 		else
1476 		{
1477 			pLines = &pBox->GetTabLines();
1478 			if( nBox )
1479 				--nBox;
1480 		}
1481 
1482         nLine = SwTable::_GetBoxNum( aNm, sal_False, bPerformValidCheck );
1483 
1484 		// bestimme die Line
1485 		if( !nLine || nLine > pLines->Count() )
1486 			return 0;
1487 		pLine = (*pLines)[ nLine-1 ];
1488 
1489 		// bestimme die Box
1490 		pBoxes = &pLine->GetTabBoxes();
1491 		if( nBox >= pBoxes->Count() )
1492 			return 0;
1493 		pBox = (*pBoxes)[ nBox ];
1494 	}
1495 
1496 	// abpruefen, ob die gefundene Box auch wirklich eine Inhaltstragende
1497 	// Box ist ??
1498 	if( pBox && !pBox->GetSttNd() )
1499 	{
1500 		ASSERT( sal_False, "Box ohne Inhalt, suche die naechste !!" );
1501 		// "herunterfallen lassen" bis zur ersten Box
1502 		while( pBox->GetTabLines().Count() )
1503 			pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
1504 	}
1505 	return pBox;
1506 }
1507 
1508 SwTableBox* SwTable::GetTblBox( sal_uLong nSttIdx )
1509 {
1510 	//MA: Zur Optimierung nicht immer umstaendlich das ganze SortArray abhuenern.
1511     //OS: #102675# converting text to table tries und certain conditions
1512     // to ask for a table box of a table that is not yet having a format
1513     if(!GetFrmFmt())
1514         return 0;
1515     SwTableBox* pRet = 0;
1516     SwNodes& rNds = GetFrmFmt()->GetDoc()->GetNodes();
1517 	sal_uLong nIndex = nSttIdx + 1;
1518 	SwCntntNode* pCNd = 0;
1519     SwTableNode* pTblNd = 0;
1520 
1521     while ( nIndex < rNds.Count() )
1522     {
1523         pTblNd = rNds[ nIndex ]->GetTableNode();
1524         if ( pTblNd )
1525             break;
1526 
1527         pCNd = rNds[ nIndex ]->GetCntntNode();
1528         if ( pCNd )
1529             break;
1530 
1531         ++nIndex;
1532     }
1533 
1534 	if ( pCNd || pTblNd )
1535 	{
1536         SwModify* pModify = pCNd;
1537         // --> FME 2007-3-26 #144862# Better handling of table in table:
1538         if ( pTblNd && pTblNd->GetTable().GetFrmFmt() )
1539             pModify = pTblNd->GetTable().GetFrmFmt();
1540         // <--
1541 
1542         SwFrm* pFrm = SwIterator<SwFrm,SwModify>::FirstElement( *pModify );
1543 		while ( pFrm && !pFrm->IsCellFrm() )
1544 			pFrm = pFrm->GetUpper();
1545 		if ( pFrm )
1546 			pRet = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1547 	}
1548 
1549 	//Falls es das Layout noch nicht gibt oder sonstwie etwas schieft geht.
1550 	if ( !pRet )
1551 	{
1552 		for( sal_uInt16 n = aSortCntBoxes.Count(); n; )
1553 			if( aSortCntBoxes[ --n ]->GetSttIdx() == nSttIdx )
1554 				return aSortCntBoxes[ n ];
1555 	}
1556 	return pRet;
1557 }
1558 
1559 sal_Bool SwTable::IsTblComplex() const
1560 {
1561 	// returnt sal_True wenn sich in der Tabelle Verschachtelungen befinden
1562 	// steht eine Box nicht in der obersten Line, da wurde gesplittet/
1563 	// gemergt und die Struktur ist komplexer.
1564 	for( sal_uInt16 n = 0; n < aSortCntBoxes.Count(); ++n )
1565 		if( aSortCntBoxes[ n ]->GetUpper()->GetUpper() )
1566 			return sal_True;
1567 	return sal_False;
1568 }
1569 
1570 
1571 
1572 /*************************************************************************
1573 |*
1574 |*	SwTableLine::SwTableLine()
1575 |*
1576 |*************************************************************************/
1577 SwTableLine::SwTableLine( SwTableLineFmt *pFmt, sal_uInt16 nBoxes,
1578 							SwTableBox *pUp )
1579 	: SwClient( pFmt ),
1580 	aBoxes( (sal_uInt8)nBoxes, 1 ),
1581 	pUpper( pUp )
1582 {
1583 }
1584 
1585 SwTableLine::~SwTableLine()
1586 {
1587 	// ist die TabelleLine der letzte Client im FrameFormat, kann dieses
1588 	// geloescht werden
1589 	SwModify* pMod = GetFrmFmt();
1590 	pMod->Remove( this );				// austragen,
1591 	if( !pMod->GetDepends() )
1592 		delete pMod;	// und loeschen
1593 }
1594 
1595 /*************************************************************************
1596 |*
1597 |*	SwTableLine::ClaimFrmFmt(), ChgFrmFmt()
1598 |*
1599 |*************************************************************************/
1600 SwFrmFmt* SwTableLine::ClaimFrmFmt()
1601 {
1602     // This method makes sure that this object is an exclusive SwTableLine client
1603     // of an SwTableLineFmt object
1604     // If other SwTableLine objects currently listen to the same SwTableLineFmt as
1605     // this one, something needs to be done
1606 	SwTableLineFmt *pRet = (SwTableLineFmt*)GetFrmFmt();
1607 	SwIterator<SwTableLine,SwFmt> aIter( *pRet );
1608 	for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1609     {
1610 	    if ( pLast != this )
1611 	    {
1612             // found another SwTableLine that is a client of the current Fmt
1613             // create a new Fmt as a copy and use it for this object
1614 		    SwTableLineFmt *pNewFmt = pRet->GetDoc()->MakeTableLineFmt();
1615 		    *pNewFmt = *pRet;
1616 
1617 		    // register SwRowFrms that know me as clients at the new Fmt
1618             SwIterator<SwRowFrm,SwFmt> aFrmIter( *pRet );
1619 	        for( SwRowFrm* pFrm = aFrmIter.First(); pFrm; pFrm = aFrmIter.Next() )
1620 		        if( pFrm->GetTabLine() == this )
1621                     pFrm->RegisterToFormat( *pNewFmt );
1622 
1623 		    // register myself
1624 		    pNewFmt->Add( this );
1625 		    pRet = pNewFmt;
1626             break;
1627         }
1628 	}
1629 
1630 	return pRet;
1631 }
1632 
1633 void SwTableLine::ChgFrmFmt( SwTableLineFmt *pNewFmt )
1634 {
1635 	SwFrmFmt *pOld = GetFrmFmt();
1636 	SwIterator<SwRowFrm,SwFmt> aIter( *pOld );
1637 
1638 	//Erstmal die Frms ummelden.
1639 	for( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() )
1640 	{
1641 		if( pRow->GetTabLine() == this )
1642 		{
1643             pRow->RegisterToFormat( *pNewFmt );
1644 
1645             pRow->InvalidateSize();
1646 			pRow->_InvalidatePrt();
1647 			pRow->SetCompletePaint();
1648 			pRow->ReinitializeFrmSizeAttrFlags();
1649 
1650             // --> FME 2004-10-27 #i35063#
1651             // consider 'split row allowed' attribute
1652             SwTabFrm* pTab = pRow->FindTabFrm();
1653             bool bInFollowFlowRow = false;
1654             const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
1655                                                 pRow == pTab->GetFirstNonHeadlineRow();
1656             if ( bInFirstNonHeadlineRow ||
1657                  !pRow->GetNext() ||
1658                  0 != ( bInFollowFlowRow = pRow->IsInFollowFlowRow() ) ||
1659                  0 != pRow->IsInSplitTableRow() )
1660             {
1661                 if ( bInFirstNonHeadlineRow || bInFollowFlowRow )
1662                     pTab = pTab->FindMaster();
1663 
1664                 pTab->SetRemoveFollowFlowLinePending( sal_True );
1665                 pTab->InvalidatePos();
1666             }
1667             // <--
1668         }
1669 	}
1670 
1671 	//Jetzt noch mich selbst ummelden.
1672 	pNewFmt->Add( this );
1673 
1674 	if ( !pOld->GetDepends() )
1675 		delete pOld;
1676 }
1677 
1678 SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
1679 {
1680     SwTwips nRet = 0;
1681     bLayoutAvailable = false;
1682 	SwIterator<SwRowFrm,SwFmt> aIter( *GetFrmFmt() );
1683     // A row could appear several times in headers/footers so only one chain of master/follow tables
1684     // will be accepted...
1685     const SwTabFrm* pChain = NULL; // My chain
1686 	for( SwRowFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1687     {
1688 		if( pLast->GetTabLine() == this )
1689 		{
1690             const SwTabFrm* pTab = pLast->FindTabFrm();
1691             bLayoutAvailable = ( pTab && pTab->IsVertical() ) ?
1692                                ( 0 < pTab->Frm().Height() ) :
1693                                ( 0 < pTab->Frm().Width() );
1694 
1695             // The first one defines the chain, if a chain is defined, only members of the chain
1696             // will be added.
1697             if( !pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow( pChain ) )
1698             {
1699                 pChain = pTab; // defines my chain (even it is already)
1700                 if( pTab->IsVertical() )
1701                     nRet += pLast->Frm().Width();
1702                 else
1703                     nRet += pLast->Frm().Height();
1704                 // Optimization, if there are no master/follows in my chain, nothing more to add
1705                 if( !pTab->HasFollow() && !pTab->IsFollow() )
1706                     break;
1707                 // This is not an optimization, this is necessary to avoid double additions of
1708                 // repeating rows
1709                 if( pTab->IsInHeadline(*pLast) )
1710                     break;
1711             }
1712         }
1713     }
1714     return nRet;
1715 }
1716 
1717 /*************************************************************************
1718 |*
1719 |*	SwTableBox::SwTableBox()
1720 |*
1721 |*************************************************************************/
1722 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, sal_uInt16 nLines, SwTableLine *pUp )
1723 	: SwClient( 0 ),
1724 	aLines( (sal_uInt8)nLines, 1 ),
1725 	pSttNd( 0 ),
1726 	pUpper( pUp ),
1727 	pImpl( 0 )
1728 {
1729 	CheckBoxFmt( pFmt )->Add( this );
1730 }
1731 
1732 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwNodeIndex &rIdx,
1733 						SwTableLine *pUp )
1734 	: SwClient( 0 ),
1735 	aLines( 0, 0 ),
1736 	pUpper( pUp ),
1737 	pImpl( 0 )
1738 {
1739 	CheckBoxFmt( pFmt )->Add( this );
1740 
1741     pSttNd = rIdx.GetNode().GetStartNode();
1742 
1743 	// an der Table eintragen
1744 	const SwTableNode* pTblNd = pSttNd->FindTableNode();
1745 	ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1746 	SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1747 								GetTabSortBoxes();
1748 	SwTableBox* p = this;	// error: &this
1749 	rSrtArr.Insert( p );		// eintragen
1750 }
1751 
1752 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwStartNode& rSttNd, SwTableLine *pUp ) :
1753 	SwClient( 0 ),
1754 	aLines( 0, 0 ),
1755     pSttNd( &rSttNd ),
1756 	pUpper( pUp ),
1757     pImpl( 0 )
1758 {
1759     CheckBoxFmt( pFmt )->Add( this );
1760 
1761 	// an der Table eintragen
1762 	const SwTableNode* pTblNd = pSttNd->FindTableNode();
1763 	ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1764 	SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1765 								GetTabSortBoxes();
1766 	SwTableBox* p = this;	// error: &this
1767 	rSrtArr.Insert( p );		// eintragen
1768 }
1769 
1770 SwTableBox::~SwTableBox()
1771 {
1772 	// Inhaltstragende Box ?
1773 	if( !GetFrmFmt()->GetDoc()->IsInDtor() && pSttNd )
1774 	{
1775 		// an der Table austragen
1776 		const SwTableNode* pTblNd = pSttNd->FindTableNode();
1777 		ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1778 		SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1779 									GetTabSortBoxes();
1780 		SwTableBox *p = this;	// error: &this
1781 		rSrtArr.Remove( p );		// austragen
1782 	}
1783 
1784 	// ist die TabelleBox der letzte Client im FrameFormat, kann dieses
1785 	// geloescht werden
1786 	SwModify* pMod = GetFrmFmt();
1787 	pMod->Remove( this );				// austragen,
1788 	if( !pMod->GetDepends() )
1789 		delete pMod;	// und loeschen
1790 
1791 	delete pImpl;
1792 }
1793 
1794 SwTableBoxFmt* SwTableBox::CheckBoxFmt( SwTableBoxFmt* pFmt )
1795 {
1796 	// sollte das Format eine Formel oder einen Value tragen, dann muss die
1797 	// Box alleine am Format haengen. Ggfs. muss ein neues angelegt werden.
1798 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) ||
1799 		SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ) )
1800 	{
1801 		SwTableBox* pOther = SwIterator<SwTableBox,SwFmt>::FirstElement( *pFmt );
1802 		if( pOther )
1803 		{
1804 			SwTableBoxFmt* pNewFmt = pFmt->GetDoc()->MakeTableBoxFmt();
1805 			pNewFmt->LockModify();
1806 			*pNewFmt = *pFmt;
1807 
1808 			// Values und Formeln entfernen
1809             pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1810 			pNewFmt->UnlockModify();
1811 
1812 			pFmt = pNewFmt;
1813 		}
1814 	}
1815 	return pFmt;
1816 }
1817 
1818 /*************************************************************************
1819 |*
1820 |*	SwTableBox::ClaimFrmFmt(), ChgFrmFmt()
1821 |*
1822 |*************************************************************************/
1823 SwFrmFmt* SwTableBox::ClaimFrmFmt()
1824 {
1825     // This method makes sure that this object is an exclusive SwTableBox client
1826     // of an SwTableBoxFmt object
1827     // If other SwTableBox objects currently listen to the same SwTableBoxFmt as
1828     // this one, something needs to be done
1829 	SwTableBoxFmt *pRet = (SwTableBoxFmt*)GetFrmFmt();
1830 	SwIterator<SwTableBox,SwFmt> aIter( *pRet );
1831 	for( SwTableBox* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1832     {
1833 	    if ( pLast != this )
1834         {
1835             // Found another SwTableBox object
1836             // create a new Fmt as a copy and assign me to it
1837 		    // don't copy values and formulas
1838 		    SwTableBoxFmt* pNewFmt = pRet->GetDoc()->MakeTableBoxFmt();
1839 		    pNewFmt->LockModify();
1840 		    *pNewFmt = *pRet;
1841             pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1842 		    pNewFmt->UnlockModify();
1843 
1844 		    // re-register SwCellFrm objects that know me
1845             SwIterator<SwCellFrm,SwFmt> aFrmIter( *pRet );
1846 	        for( SwCellFrm* pCell = aFrmIter.First(); pCell; pCell = aFrmIter.Next() )
1847 		        if( pCell->GetTabBox() == this )
1848                     pCell->RegisterToFormat( *pNewFmt );
1849 
1850 		    // re-register myself
1851 		    pNewFmt->Add( this );
1852 		    pRet = pNewFmt;
1853             break;
1854         }
1855     }
1856 	return pRet;
1857 }
1858 
1859 void SwTableBox::ChgFrmFmt( SwTableBoxFmt* pNewFmt )
1860 {
1861 	SwFrmFmt *pOld = GetFrmFmt();
1862 	SwIterator<SwCellFrm,SwFmt> aIter( *pOld );
1863 
1864 	//Erstmal die Frms ummelden.
1865 	for( SwCellFrm* pCell = aIter.First(); pCell; pCell = aIter.Next() )
1866 	{
1867 		if( pCell->GetTabBox() == this )
1868 		{
1869             pCell->RegisterToFormat( *pNewFmt );
1870 			pCell->InvalidateSize();
1871 			pCell->_InvalidatePrt();
1872 			pCell->SetCompletePaint();
1873             pCell->SetDerivedVert( sal_False );
1874             pCell->CheckDirChange();
1875 
1876             // --> FME 2005-04-15 #i47489#
1877             // make sure that the row will be formatted, in order
1878             // to have the correct Get(Top|Bottom)MarginForLowers values
1879             // set at the row.
1880             const SwTabFrm* pTab = pCell->FindTabFrm();
1881             if ( pTab && pTab->IsCollapsingBorders() )
1882             {
1883                 SwFrm* pRow = pCell->GetUpper();
1884                 pRow->_InvalidateSize();
1885                 pRow->_InvalidatePrt();
1886             }
1887             // <--
1888         }
1889 	}
1890 
1891 	//Jetzt noch mich selbst ummelden.
1892 	pNewFmt->Add( this );
1893 
1894 	if( !pOld->GetDepends() )
1895 		delete pOld;
1896 }
1897 
1898 /*************************************************************************
1899 |*
1900 |*	String SwTableBox::GetName() const
1901 |*		gebe den Namen dieser Box zurueck. Dieser wird dynamisch bestimmt
1902 |*		und ergibt sich aus der Position in den Lines/Boxen/Tabelle
1903 |*
1904 |*************************************************************************/
1905 void lcl_GetTblBoxColStr( sal_uInt16 nCol, String& rNm )
1906 {
1907 	const sal_uInt16 coDiff = 52; 	// 'A'-'Z' 'a' - 'z'
1908     sal_uInt16 nCalc;
1909 
1910 	do {
1911 		nCalc = nCol % coDiff;
1912 		if( nCalc >= 26 )
1913 			rNm.Insert( sal_Unicode('a' - 26 + nCalc ), 0 );
1914 		else
1915 			rNm.Insert( sal_Unicode('A' + nCalc ), 0 );
1916 
1917         if( 0 == (nCol = nCol - nCalc) )
1918 			break;
1919 		nCol /= coDiff;
1920 		--nCol;
1921 	} while( 1 );
1922 }
1923 
1924 String SwTableBox::GetName() const
1925 {
1926 	if( !pSttNd )		// keine Content Box ??
1927 	{
1928 		// die naechste erste Box suchen ??
1929 		return aEmptyStr;
1930 	}
1931 
1932 	const SwTable& rTbl = pSttNd->FindTableNode()->GetTable();
1933     sal_uInt16 nPos;
1934 	String sNm, sTmp;
1935 	const SwTableBox* pBox = this;
1936 	do {
1937 		const SwTableBoxes* pBoxes = &pBox->GetUpper()->GetTabBoxes();
1938 		const SwTableLine* pLine = pBox->GetUpper();
1939 		// auf oberstere Ebene ?
1940 		const SwTableLines* pLines = pLine->GetUpper()
1941 				? &pLine->GetUpper()->GetTabLines() : &rTbl.GetTabLines();
1942 
1943 		sTmp = String::CreateFromInt32( nPos = pLines->GetPos( pLine ) + 1 );
1944 		if( sNm.Len() )
1945 			sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
1946 		else
1947 			sNm = sTmp;
1948 
1949 		sTmp = String::CreateFromInt32(( nPos = pBoxes->GetPos( pBox )) + 1 );
1950 		if( 0 != ( pBox = pLine->GetUpper()) )
1951 			sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
1952 		else
1953 			::lcl_GetTblBoxColStr( nPos, sNm );
1954 
1955 	} while( pBox );
1956 	return sNm;
1957 }
1958 
1959 sal_Bool SwTableBox::IsInHeadline( const SwTable* pTbl ) const
1960 {
1961 	if( !GetUpper() )			// sollte nur beim Merge vorkommen.
1962 		return sal_False;
1963 
1964 	if( !pTbl )
1965 		pTbl = &pSttNd->FindTableNode()->GetTable();
1966 
1967 	const SwTableLine* pLine = GetUpper();
1968 	while( pLine->GetUpper() )
1969 		pLine = pLine->GetUpper()->GetUpper();
1970 
1971 	// Headerline?
1972 	return pTbl->GetTabLines()[ 0 ] == pLine;
1973 }
1974 
1975 #ifdef DBG_UTIL
1976 
1977 sal_uLong SwTableBox::GetSttIdx() const
1978 {
1979 	return pSttNd ? pSttNd->GetIndex() : 0;
1980 }
1981 #endif
1982 
1983 	// erfrage vom Client Informationen
1984 sal_Bool SwTable::GetInfo( SfxPoolItem& rInfo ) const
1985 {
1986 	switch( rInfo.Which() )
1987 	{
1988 	case RES_AUTOFMT_DOCNODE:
1989     {
1990         const SwTableNode* pTblNode = GetTableNode();
1991         if( pTblNode && &pTblNode->GetNodes() == ((SwAutoFmtGetDocNode&)rInfo).pNodes )
1992         {
1993             if ( aSortCntBoxes.Count() )
1994             {
1995   			    SwNodeIndex aIdx( *aSortCntBoxes[ 0 ]->GetSttNd() );
1996     		    ((SwAutoFmtGetDocNode&)rInfo).pCntntNode =
1997 	    		    			GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx );
1998             }
1999 			return sal_False;
2000 		}
2001 		break;
2002     }
2003 	case RES_FINDNEARESTNODE:
2004         if( GetFrmFmt() && ((SwFmtPageDesc&)GetFrmFmt()->GetFmtAttr(
2005 			RES_PAGEDESC )).GetPageDesc() &&
2006 			aSortCntBoxes.Count() &&
2007 			aSortCntBoxes[ 0 ]->GetSttNd()->GetNodes().IsDocNodes() )
2008 			((SwFindNearestNode&)rInfo).CheckNode( *
2009 				aSortCntBoxes[ 0 ]->GetSttNd()->FindTableNode() );
2010 		break;
2011 
2012 	case RES_CONTENT_VISIBLE:
2013 		{
2014 			((SwPtrMsgPoolItem&)rInfo).pObject = SwIterator<SwFrm,SwFmt>::FirstElement( *GetFrmFmt() );
2015 		}
2016 		return sal_False;
2017 	}
2018 	return sal_True;
2019 }
2020 
2021 SwTable * SwTable::FindTable( SwFrmFmt const*const pFmt )
2022 {
2023     return (pFmt)
2024         ? SwIterator<SwTable,SwFmt>::FirstElement(*pFmt)
2025         : 0;
2026 }
2027 
2028 SwTableNode* SwTable::GetTableNode() const
2029 {
2030     return GetTabSortBoxes().Count() ?
2031            (SwTableNode*)GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode() :
2032            pTableNode;
2033 }
2034 
2035 void SwTable::SetRefObject( SwServerObject* pObj )
2036 {
2037 	if( refObj.Is() )
2038 		refObj->Closed();
2039 
2040 	refObj = pObj;
2041 }
2042 
2043 
2044 void SwTable::SetHTMLTableLayout( SwHTMLTableLayout *p )
2045 {
2046 	delete pHTMLLayout;
2047 	pHTMLLayout = p;
2048 }
2049 
2050 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
2051 					sal_Bool bChgAlign )
2052 {
2053     sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_True );
2054     ChgTextToNum( rBox,rTxt,pCol,bChgAlign,nNdPos);
2055 }
2056 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
2057 					sal_Bool bChgAlign,sal_uLong nNdPos )
2058 {
2059 
2060 	if( ULONG_MAX != nNdPos )
2061 	{
2062 		SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2063 		SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2064 		const SfxPoolItem* pItem;
2065 
2066 		// Ausrichtung umsetzen
2067 		if( bChgAlign )
2068 		{
2069 			pItem = &pTNd->SwCntntNode::GetAttr( RES_PARATR_ADJUST );
2070 			SvxAdjust eAdjust = ((SvxAdjustItem*)pItem)->GetAdjust();
2071 			if( SVX_ADJUST_LEFT == eAdjust || SVX_ADJUST_BLOCK == eAdjust )
2072 			{
2073 				SvxAdjustItem aAdjust( *(SvxAdjustItem*)pItem );
2074 				aAdjust.SetAdjust( SVX_ADJUST_RIGHT );
2075                 pTNd->SetAttr( aAdjust );
2076 			}
2077 		}
2078 
2079 		// Farbe umsetzen oder "Benutzer Farbe" sichern
2080 		if( !pTNd->GetpSwAttrSet() || SFX_ITEM_SET != pTNd->GetpSwAttrSet()->
2081 			GetItemState( RES_CHRATR_COLOR, sal_False, &pItem ))
2082 			pItem = 0;
2083 
2084 		const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2085 		const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2086 
2087 		if( ( pNewUserColor && pOldNumFmtColor &&
2088 				*pNewUserColor == *pOldNumFmtColor ) ||
2089 			( !pNewUserColor && !pOldNumFmtColor ))
2090 		{
2091 			// User Color nicht veraendern aktuellen Werte setzen
2092 			// ggfs. die alte NumFmtColor loeschen
2093 			if( pCol )
2094 				// ggfs. die Farbe setzen
2095                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2096 			else if( pItem )
2097 			{
2098 				pNewUserColor = rBox.GetSaveUserColor();
2099 				if( pNewUserColor )
2100                     pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2101 				else
2102                     pTNd->ResetAttr( RES_CHRATR_COLOR );
2103 			}
2104 		}
2105 		else
2106 		{
2107 			// User Color merken, ggfs. die NumFormat Color setzen, aber
2108 			// nie die Farbe zurueck setzen
2109 			rBox.SetSaveUserColor( pNewUserColor );
2110 
2111 			if( pCol )
2112 				// ggfs. die Farbe setzen
2113                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2114 
2115 		}
2116 		rBox.SetSaveNumFmtColor( pCol );
2117 
2118 		if( pTNd->GetTxt() != rTxt )
2119 		{
2120 			// Text austauschen
2121 			//JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten!)
2122 			const String& rOrig = pTNd->GetTxt();
2123 			xub_StrLen n;
2124 
2125 			for( n = 0; n < rOrig.Len() && '\x9' == rOrig.GetChar( n ); ++n )
2126 				;
2127             for( ; n < rOrig.Len() && '\x01' == rOrig.GetChar( n ); ++n )
2128 				;
2129 			SwIndex aIdx( pTNd, n );
2130 			for( n = rOrig.Len(); n && '\x9' == rOrig.GetChar( --n ); )
2131 				;
2132 			n -= aIdx.GetIndex() - 1;
2133 
2134 			//JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2135 			//             zuruecksetzen, damit sie wieder aufgespannt werden
2136 			{
2137 				SwIndex aResetIdx( aIdx, n );
2138 				pTNd->DontExpandFmt( aResetIdx, sal_False, sal_False );
2139 			}
2140 
2141             if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
2142             {
2143                 SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.Len());
2144                 pDoc->DeleteRedline(aTemp, true, USHRT_MAX);
2145             }
2146 
2147             pTNd->EraseText( aIdx, n,
2148                     IDocumentContentOperations::INS_EMPTYEXPAND );
2149             pTNd->InsertText( rTxt, aIdx,
2150                     IDocumentContentOperations::INS_EMPTYEXPAND );
2151 
2152             if( pDoc->IsRedlineOn() )
2153             {
2154                 SwPaM aTemp(*pTNd, 0, *pTNd, rTxt.Len());
2155                 pDoc->AppendRedline(new SwRedline(nsRedlineType_t::REDLINE_INSERT, aTemp), true);
2156             }
2157 		}
2158 
2159 		// vertikale Ausrichtung umsetzen
2160 		if( bChgAlign &&
2161 			( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(
2162 				RES_VERT_ORIENT, sal_True, &pItem ) ||
2163 				text::VertOrientation::TOP == ((SwFmtVertOrient*)pItem)->GetVertOrient() ))
2164 		{
2165             rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::BOTTOM ));
2166 		}
2167 	}
2168 }
2169 
2170 void ChgNumToText( SwTableBox& rBox, sal_uLong nFmt )
2171 {
2172 	sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_False );
2173 	if( ULONG_MAX != nNdPos )
2174 	{
2175 		SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2176 		SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2177 		sal_Bool bChgAlign = pDoc->IsInsTblAlignNum();
2178 		const SfxPoolItem* pItem;
2179 
2180 		Color* pCol = 0;
2181 		if( NUMBERFORMAT_TEXT != nFmt )
2182 		{
2183 			// speziellen Textformat:
2184 			String sTmp, sTxt( pTNd->GetTxt() );
2185 			pDoc->GetNumberFormatter()->GetOutputString( sTxt, nFmt, sTmp, &pCol );
2186 			if( sTxt != sTmp )
2187 			{
2188 				// Text austauschen
2189 				SwIndex aIdx( pTNd, sTxt.Len() );
2190 				//JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2191 				//             zuruecksetzen, damit sie wieder aufgespannt werden
2192 				pTNd->DontExpandFmt( aIdx, sal_False, sal_False );
2193 				aIdx = 0;
2194                 pTNd->EraseText( aIdx, STRING_LEN,
2195                         IDocumentContentOperations::INS_EMPTYEXPAND );
2196                 pTNd->InsertText( sTmp, aIdx,
2197                         IDocumentContentOperations::INS_EMPTYEXPAND );
2198             }
2199         }
2200 
2201         const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
2202 
2203 		// Ausrichtung umsetzen
2204 		if( bChgAlign && pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState(
2205 			RES_PARATR_ADJUST, sal_False, &pItem ) &&
2206 				SVX_ADJUST_RIGHT == ((SvxAdjustItem*)pItem)->GetAdjust() )
2207 		{
2208             pTNd->SetAttr( SvxAdjustItem( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ) );
2209 		}
2210 
2211 		// Farbe umsetzen oder "Benutzer Farbe" sichern
2212 		if( !pAttrSet || SFX_ITEM_SET != pAttrSet->
2213 			GetItemState( RES_CHRATR_COLOR, sal_False, &pItem ))
2214 			pItem = 0;
2215 
2216 		const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2217 		const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2218 
2219 		if( ( pNewUserColor && pOldNumFmtColor &&
2220 				*pNewUserColor == *pOldNumFmtColor ) ||
2221 			( !pNewUserColor && !pOldNumFmtColor ))
2222 		{
2223 			// User Color nicht veraendern aktuellen Werte setzen
2224 			// ggfs. die alte NumFmtColor loeschen
2225 			if( pCol )
2226 				// ggfs. die Farbe setzen
2227                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2228 			else if( pItem )
2229 			{
2230 				pNewUserColor = rBox.GetSaveUserColor();
2231 				if( pNewUserColor )
2232                     pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2233 				else
2234                     pTNd->ResetAttr( RES_CHRATR_COLOR );
2235 			}
2236 		}
2237 		else
2238 		{
2239 			// User Color merken, ggfs. die NumFormat Color setzen, aber
2240 			// nie die Farbe zurueck setzen
2241 			rBox.SetSaveUserColor( pNewUserColor );
2242 
2243 			if( pCol )
2244 				// ggfs. die Farbe setzen
2245                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2246 
2247 		}
2248 		rBox.SetSaveNumFmtColor( pCol );
2249 
2250 
2251 		// vertikale Ausrichtung umsetzen
2252 		if( bChgAlign &&
2253 			SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState(
2254 			RES_VERT_ORIENT, sal_False, &pItem ) &&
2255 			text::VertOrientation::BOTTOM == ((SwFmtVertOrient*)pItem)->GetVertOrient() )
2256 		{
2257             rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::TOP ));
2258 		}
2259 	}
2260 }
2261 
2262 // zum Erkennen von Veraenderungen (haupts. TableBoxAttribute)
2263 void SwTableBoxFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2264 {
2265 	if( !IsModifyLocked() && !IsInDocDTOR() )
2266 	{
2267         const SwTblBoxNumFormat *pNewFmt = 0;
2268         const SwTblBoxFormula *pNewFml = 0;
2269         const SwTblBoxValue *pNewVal = 0;
2270 		double aOldValue = 0;
2271 		sal_uLong nOldFmt = NUMBERFORMAT_TEXT;
2272 
2273         switch( pNew ? pNew->Which() : 0 )
2274 		{
2275 		case RES_ATTRSET_CHG:
2276 			{
2277 				const SfxItemSet& rSet = *((SwAttrSetChg*)pNew)->GetChgSet();
2278 				if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT,
2279 									sal_False, (const SfxPoolItem**)&pNewFmt ) )
2280 					nOldFmt = ((SwTblBoxNumFormat&)((SwAttrSetChg*)pOld)->
2281 							GetChgSet()->Get( RES_BOXATR_FORMAT )).GetValue();
2282 				rSet.GetItemState( RES_BOXATR_FORMULA, sal_False,
2283 									(const SfxPoolItem**)&pNewFml );
2284 				if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE,
2285 									sal_False, (const SfxPoolItem**)&pNewVal ) )
2286 					aOldValue = ((SwTblBoxValue&)((SwAttrSetChg*)pOld)->
2287 							GetChgSet()->Get( RES_BOXATR_VALUE )).GetValue();
2288 			}
2289 			break;
2290 
2291 		case RES_BOXATR_FORMAT:
2292 			pNewFmt = (SwTblBoxNumFormat*)pNew;
2293 			nOldFmt = ((SwTblBoxNumFormat*)pOld)->GetValue();
2294 			break;
2295 		case RES_BOXATR_FORMULA:
2296 			pNewFml = (SwTblBoxFormula*)pNew;
2297 			break;
2298 		case RES_BOXATR_VALUE:
2299 			pNewVal = (SwTblBoxValue*)pNew;
2300 			aOldValue = ((SwTblBoxValue*)pOld)->GetValue();
2301 			break;
2302 		}
2303 
2304 		// es hat sich etwas getan und im Set ist noch irgendein BoxAttribut
2305 		// vorhanden!
2306 		if( pNewFmt || pNewFml || pNewVal )
2307 		{
2308 			GetDoc()->SetFieldsDirty(true, NULL, 0);
2309 
2310 			if( SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMAT, sal_False ) ||
2311 				SFX_ITEM_SET == GetItemState( RES_BOXATR_VALUE, sal_False ) ||
2312 				SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMULA, sal_False ) )
2313 			{
2314 				// die Box holen
2315 				SwIterator<SwTableBox,SwFmt> aIter( *this );
2316 				SwTableBox* pBox = aIter.First();
2317 				if( pBox )
2318 				{
2319 					ASSERT( !aIter.Next(), "keine Box oder mehrere am Format" );
2320 
2321 					sal_uLong nNewFmt;
2322 					if( pNewFmt )
2323 					{
2324 						nNewFmt = pNewFmt->GetValue();
2325 						// neu Formatieren
2326 						// ist es neuer oder wurde der akt. entfernt?
2327 						if( SFX_ITEM_SET != GetItemState( RES_BOXATR_VALUE, sal_False ))
2328 							pNewFmt = 0;
2329 					}
2330 					else
2331 					{
2332 						// das akt. Item besorgen
2333 						GetItemState( RES_BOXATR_FORMAT, sal_False,
2334 											(const SfxPoolItem**)&pNewFmt );
2335 						nOldFmt = GetTblBoxNumFmt().GetValue();
2336 						nNewFmt = pNewFmt ? pNewFmt->GetValue() : nOldFmt;
2337 					}
2338 
2339 					// ist es neuer oder wurde der akt. entfernt?
2340 					if( pNewVal )
2341 					{
2342 						if( NUMBERFORMAT_TEXT != nNewFmt )
2343 						{
2344 							if( SFX_ITEM_SET == GetItemState(
2345 												RES_BOXATR_VALUE, sal_False ))
2346 								nOldFmt = NUMBERFORMAT_TEXT;
2347 							else
2348 								nNewFmt = NUMBERFORMAT_TEXT;
2349 						}
2350 						else if( NUMBERFORMAT_TEXT == nNewFmt )
2351 							nOldFmt = 0;
2352 					}
2353 
2354 					// Logik:
2355 					// ValueAenderung:	-> "simuliere" eine FormatAenderung!
2356 					// FormatAenderung:
2357 					// Text -> !Text oder FormatAenderung:
2358 					//			- Ausrichtung auf RECHTS, wenn LINKS oder Blocksatz
2359 					//			- vertikale Ausrichtung auf UNTEN wenn OBEN oder nicht
2360 					//				gesetzt ist.
2361 					//			- Text ersetzen (Farbe?? neg. Zahlen ROT??)
2362 					// !Text -> Text:
2363 					//			- Ausrichtung auf LINKS, wenn RECHTS
2364 					//			- vertikale Ausrichtung auf OEBN, wenn UNTEN gesetzt ist
2365 
2366 					SvNumberFormatter* pNumFmtr = GetDoc()->GetNumberFormatter();
2367 					sal_Bool bNewIsTxtFmt = pNumFmtr->IsTextFormat( nNewFmt ) ||
2368 										NUMBERFORMAT_TEXT == nNewFmt;
2369 
2370 					if( (!bNewIsTxtFmt && nOldFmt != nNewFmt) || pNewFml )
2371 					{
2372 						sal_Bool bChgTxt = sal_True;
2373 						double fVal = 0;
2374 						if( !pNewVal && SFX_ITEM_SET != GetItemState(
2375 							RES_BOXATR_VALUE, sal_False, (const SfxPoolItem**)&pNewVal ))
2376 						{
2377 							// es wurde noch nie ein Wert gesetzt, dann versuche
2378 							// doch mal den Inhalt auszuwerten
2379 							sal_uLong nNdPos = pBox->IsValidNumTxtNd( sal_True );
2380 							if( ULONG_MAX != nNdPos )
2381 							{
2382 								sal_uInt32 nTmpFmtIdx = nNewFmt;
2383 								String aTxt( GetDoc()->GetNodes()[ nNdPos ]
2384 												->GetTxtNode()->GetRedlineTxt());
2385 								if( !aTxt.Len() )
2386 									bChgTxt = sal_False;
2387 								else
2388 								{
2389 									//JP 15.09.98: Bug 55741 - Tabs beibehalten
2390 									lcl_TabToBlankAtSttEnd( aTxt );
2391 
2392 									// JP 22.04.98: Bug 49659 -
2393 									//			Sonderbehandlung fuer Prozent
2394 									sal_Bool bIsNumFmt = sal_False;
2395 									if( NUMBERFORMAT_PERCENT ==
2396 										pNumFmtr->GetType( nNewFmt ))
2397 									{
2398 										sal_uInt32 nTmpFmt = 0;
2399 										if( pNumFmtr->IsNumberFormat(
2400 													aTxt, nTmpFmt, fVal ))
2401 										{
2402 											if( NUMBERFORMAT_NUMBER ==
2403 												pNumFmtr->GetType( nTmpFmt ))
2404 												aTxt += '%';
2405 
2406 											bIsNumFmt = pNumFmtr->IsNumberFormat(
2407 														aTxt, nTmpFmtIdx, fVal );
2408 										}
2409 									}
2410 									else
2411 										bIsNumFmt = pNumFmtr->IsNumberFormat(
2412 														aTxt, nTmpFmtIdx, fVal );
2413 
2414 									if( bIsNumFmt )
2415 									{
2416 										// dann setze den Value direkt in den Set -
2417 										// ohne Modify
2418 										int bIsLockMod = IsModifyLocked();
2419 										LockModify();
2420                                         SetFmtAttr( SwTblBoxValue( fVal ));
2421 										if( !bIsLockMod )
2422 											UnlockModify();
2423 									}
2424 								}
2425 							}
2426 						}
2427 						else
2428 							fVal = pNewVal->GetValue();
2429 
2430 						// den Inhalt mit dem neuen Wert Formtieren und in den Absatz
2431 						// schbreiben
2432 						Color* pCol = 0;
2433 						String sNewTxt;
2434 						if( DBL_MAX == fVal )
2435 							sNewTxt = ViewShell::GetShellRes()->aCalc_Error;
2436 						else
2437 						{
2438 							pNumFmtr->GetOutputString( fVal, nNewFmt, sNewTxt, &pCol );
2439 
2440 							if( !bChgTxt )
2441 								sNewTxt.Erase();
2442 						}
2443 
2444 						// ueber alle Boxen
2445 						ChgTextToNum( *pBox, sNewTxt, pCol,
2446 										GetDoc()->IsInsTblAlignNum() );
2447 
2448 					}
2449 					else if( bNewIsTxtFmt && nOldFmt != nNewFmt )
2450 					{
2451 						// auf jedenfall muessen jetzt die Formeln/Values
2452 						// geloescht werden!
2453 	//					LockModify();
2454 	//					ResetAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
2455 	//					UnlockModify();
2456 
2457 
2458 						ChgNumToText( *pBox, nNewFmt );
2459 					}
2460 				}
2461 			}
2462 		}
2463 	}
2464 	// Und die Basis-Klasse rufen
2465 	SwFrmFmt::Modify( pOld, pNew );
2466 }
2467 
2468 sal_Bool SwTableBox::HasNumCntnt( double& rNum, sal_uInt32& rFmtIndex,
2469 							sal_Bool& rIsEmptyTxtNd ) const
2470 {
2471 	sal_Bool bRet = sal_False;
2472 	sal_uLong nNdPos = IsValidNumTxtNd( sal_True );
2473 	if( ULONG_MAX != nNdPos )
2474 	{
2475 		String aTxt( pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->
2476 							GetRedlineTxt() );
2477 		//JP 15.09.98: Bug 55741 - Tabs beibehalten
2478 		lcl_TabToBlankAtSttEnd( aTxt );
2479 		rIsEmptyTxtNd = 0 == aTxt.Len();
2480 		SvNumberFormatter* pNumFmtr = GetFrmFmt()->GetDoc()->GetNumberFormatter();
2481 
2482 		const SfxPoolItem* pItem;
2483 		if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
2484 				sal_False, &pItem ))
2485 		{
2486 			rFmtIndex = ((SwTblBoxNumFormat*)pItem)->GetValue();
2487 			// JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
2488 			if( !rIsEmptyTxtNd &&
2489 				NUMBERFORMAT_PERCENT == pNumFmtr->GetType( rFmtIndex ))
2490 			{
2491 				sal_uInt32 nTmpFmt = 0;
2492 				if( pNumFmtr->IsNumberFormat( aTxt, nTmpFmt, rNum ) &&
2493 					NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt ))
2494 					aTxt += '%';
2495 			}
2496 		}
2497 		else
2498 			rFmtIndex = 0;
2499 
2500 		bRet = pNumFmtr->IsNumberFormat( aTxt, rFmtIndex, rNum );
2501 	}
2502 	else
2503 		rIsEmptyTxtNd = sal_False;
2504 	return bRet;
2505 }
2506 
2507 sal_Bool SwTableBox::IsNumberChanged() const
2508 {
2509 	sal_Bool bRet = sal_True;
2510 
2511 	if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA, sal_False ))
2512 	{
2513 		const SwTblBoxNumFormat *pNumFmt;
2514 		const SwTblBoxValue *pValue;
2515 
2516 		if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_VALUE, sal_False,
2517 			(const SfxPoolItem**)&pValue ))
2518 			pValue = 0;
2519 		if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, sal_False,
2520 			(const SfxPoolItem**)&pNumFmt ))
2521 			pNumFmt = 0;
2522 
2523 		sal_uLong nNdPos;
2524 		if( pNumFmt && pValue &&
2525 			ULONG_MAX != ( nNdPos = IsValidNumTxtNd( sal_True ) ) )
2526 		{
2527 			String sNewTxt, sOldTxt( pSttNd->GetNodes()[ nNdPos ]->
2528 									GetTxtNode()->GetRedlineTxt() );
2529 			lcl_DelTabsAtSttEnd( sOldTxt );
2530 
2531 			Color* pCol = 0;
2532 			GetFrmFmt()->GetDoc()->GetNumberFormatter()->GetOutputString(
2533 				pValue->GetValue(), pNumFmt->GetValue(), sNewTxt, &pCol );
2534 
2535 			bRet = sNewTxt != sOldTxt ||
2536 					!( ( !pCol && !GetSaveNumFmtColor() ) ||
2537 					   ( pCol && GetSaveNumFmtColor() &&
2538 						*pCol == *GetSaveNumFmtColor() ));
2539 		}
2540 	}
2541 	return bRet;
2542 }
2543 
2544 sal_uLong SwTableBox::IsValidNumTxtNd( sal_Bool bCheckAttr ) const
2545 {
2546 	sal_uLong nPos = ULONG_MAX;
2547 	if( pSttNd )
2548 	{
2549 		SwNodeIndex aIdx( *pSttNd );
2550 		sal_uLong nIndex = aIdx.GetIndex();
2551 		const sal_uLong nIndexEnd = pSttNd->GetNodes()[ nIndex ]->EndOfSectionIndex();
2552 		const SwTxtNode *pTextNode = 0;
2553 		while( ++nIndex < nIndexEnd )
2554 		{
2555             const SwNode* pNode = pSttNd->GetNodes()[nIndex];
2556 			if( pNode->IsTableNode() )
2557 			{    /*return ULONG_MAX if the cell contains a table(in table)*/
2558 				pTextNode = 0;
2559 				break;
2560 			}
2561 			if( pNode->IsTxtNode() )
2562 			{
2563 				if( pTextNode )
2564 				{    /*return ULONG_MAX if the cell contains complex paragraphs*/
2565 					pTextNode = 0;
2566 					break;
2567 				}
2568                 else
2569                 {
2570                     pTextNode = pNode->GetTxtNode();
2571                     nPos = nIndex;
2572                 }
2573 			}
2574 		}
2575 		if( pTextNode )
2576 		{
2577 			if( bCheckAttr )
2578 			{
2579 				const SwpHints* pHts = pTextNode->GetpSwpHints();
2580 				const String& rTxt = pTextNode->GetTxt();
2581                 // dann teste doch mal, ob das wirklich nur Text im Node steht!
2582                 // Flys/Felder/..
2583                 if( pHts )
2584                 {
2585                     for( sal_uInt16 n = 0; n < pHts->Count(); ++n )
2586                     {
2587                         const SwTxtAttr* pAttr = (*pHts)[ n ];
2588                         if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() ||
2589                             *pAttr->GetStart() ||
2590                             *pAttr->GetAnyEnd() < rTxt.Len() )
2591                         {
2592                             if ( pAttr->Which() == RES_TXTATR_FIELD )
2593                             {
2594                                 const SwField* pField = pAttr->GetFld().GetFld();
2595                                 if ( pField && pField->GetTypeId() == TYP_SETFLD )
2596                                 {
2597                                     continue;
2598                                 }
2599                             }
2600                             nPos = ULONG_MAX;
2601                             break;
2602                         }
2603                     }
2604                 }
2605 			}
2606 		}
2607         else
2608             nPos = ULONG_MAX;
2609 	}
2610 	return nPos;
2611 }
2612 
2613 // ist das eine FormelBox oder eine Box mit numerischen Inhalt (AutoSum)
2614 sal_uInt16 SwTableBox::IsFormulaOrValueBox() const
2615 {
2616 	sal_uInt16 nWhich = 0;
2617 	const SwTxtNode* pTNd;
2618 	SwFrmFmt* pFmt = GetFrmFmt();
2619 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ))
2620 		nWhich = RES_BOXATR_FORMULA;
2621 	else if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) &&
2622 			!pFmt->GetDoc()->GetNumberFormatter()->IsTextFormat(
2623 				pFmt->GetTblBoxNumFmt().GetValue() ))
2624 		nWhich = RES_BOXATR_VALUE;
2625 	else if( pSttNd && pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex()
2626 			&& 0 != ( pTNd = pSttNd->GetNodes()[ pSttNd->GetIndex() + 1 ]
2627 			->GetTxtNode() ) && !pTNd->GetTxt().Len() )
2628 		nWhich = USHRT_MAX;
2629 
2630 	return nWhich;
2631 }
2632 
2633 void SwTableBox::ActualiseValueBox()
2634 {
2635 	const SfxPoolItem *pFmtItem, *pValItem;
2636 	SwFrmFmt* pFmt = GetFrmFmt();
2637 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT, sal_True, &pFmtItem )
2638 		&& SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_True, &pValItem ))
2639 	{
2640         const sal_uLong nFmtId = ((SwTblBoxNumFormat*)pFmtItem)->GetValue();
2641 		sal_uLong nNdPos = ULONG_MAX;
2642 		SvNumberFormatter* pNumFmtr = pFmt->GetDoc()->GetNumberFormatter();
2643 
2644 		if( !pNumFmtr->IsTextFormat( nFmtId ) &&
2645 			ULONG_MAX != (nNdPos = IsValidNumTxtNd( sal_True )) )
2646 		{
2647 			double fVal = ((SwTblBoxValue*)pValItem)->GetValue();
2648 			Color* pCol = 0;
2649 			String sNewTxt;
2650 			pNumFmtr->GetOutputString( fVal, nFmtId, sNewTxt, &pCol );
2651 
2652 			const String& rTxt = pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->GetTxt();
2653 			if( rTxt != sNewTxt )
2654 				ChgTextToNum( *this, sNewTxt, pCol, sal_False ,nNdPos);
2655 		}
2656 	}
2657 }
2658 
2659 void SwTableBox_Impl::SetNewCol( Color** ppCol, const Color* pNewCol )
2660 {
2661 	if( *ppCol != pNewCol )
2662 	{
2663 		delete *ppCol;
2664 		if( pNewCol )
2665 			*ppCol = new Color( *pNewCol );
2666 		else
2667 			*ppCol = 0;
2668 	}
2669 }
2670 
2671 struct SwTableCellInfo::Impl
2672 {
2673     const SwTable * m_pTable;
2674     const SwCellFrm * m_pCellFrm;
2675     const SwTabFrm * m_pTabFrm;
2676     typedef ::std::set<const SwTableBox *> TableBoxes_t;
2677     TableBoxes_t m_HandledTableBoxes;
2678 
2679 public:
2680     Impl()
2681         : m_pTable(NULL), m_pCellFrm(NULL), m_pTabFrm(NULL)
2682     {
2683     }
2684 
2685     ~Impl() {}
2686 
2687     void setTable(const SwTable * pTable) {
2688         m_pTable = pTable;
2689         SwFrmFmt * pFrmFmt = m_pTable->GetFrmFmt();
2690         m_pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement(*pFrmFmt);
2691         if (m_pTabFrm->IsFollow())
2692             m_pTabFrm = m_pTabFrm->FindMaster(true);
2693     }
2694     const SwTable * getTable() const { return m_pTable; }
2695 
2696     const SwCellFrm * getCellFrm() const { return m_pCellFrm; }
2697 
2698     const SwFrm * getNextFrmInTable(const SwFrm * pFrm);
2699     const SwCellFrm * getNextCellFrm(const SwFrm * pFrm);
2700     const SwCellFrm * getNextTableBoxsCellFrm(const SwFrm * pFrm);
2701     bool getNext();
2702 };
2703 
2704 const SwFrm * SwTableCellInfo::Impl::getNextFrmInTable(const SwFrm * pFrm)
2705 {
2706     const SwFrm * pResult = NULL;
2707 
2708     if (((! pFrm->IsTabFrm()) || pFrm == m_pTabFrm) && pFrm->GetLower())
2709         pResult = pFrm->GetLower();
2710     else if (pFrm->GetNext())
2711         pResult = pFrm->GetNext();
2712     else
2713     {
2714         while (pFrm->GetUpper() != NULL)
2715         {
2716             pFrm = pFrm->GetUpper();
2717 
2718             if (pFrm->IsTabFrm())
2719             {
2720                 m_pTabFrm = static_cast<const SwTabFrm *>(pFrm)->GetFollow();
2721                 pResult = m_pTabFrm;
2722                 break;
2723             }
2724             else if (pFrm->GetNext())
2725             {
2726                 pResult = pFrm->GetNext();
2727                 break;
2728             }
2729         }
2730     }
2731 
2732     return pResult;
2733 }
2734 
2735 const SwCellFrm * SwTableCellInfo::Impl::getNextCellFrm(const SwFrm * pFrm)
2736 {
2737     const SwCellFrm * pResult = NULL;
2738 
2739     while ((pFrm = getNextFrmInTable(pFrm)) != NULL)
2740     {
2741         if (pFrm->IsCellFrm())
2742         {
2743             pResult = static_cast<const SwCellFrm *>(pFrm);
2744             break;
2745         }
2746     }
2747 
2748     return pResult;
2749 }
2750 
2751 const SwCellFrm * SwTableCellInfo::Impl::getNextTableBoxsCellFrm(const SwFrm * pFrm)
2752 {
2753     const SwCellFrm * pResult = NULL;
2754 
2755     while ((pFrm = getNextCellFrm(pFrm)) != NULL)
2756     {
2757         const SwCellFrm * pCellFrm = static_cast<const SwCellFrm *>(pFrm);
2758         const SwTableBox * pTabBox = pCellFrm->GetTabBox();
2759         TableBoxes_t::const_iterator aIt = m_HandledTableBoxes.find(pTabBox);
2760 
2761         if (aIt == m_HandledTableBoxes.end())
2762         {
2763             pResult = pCellFrm;
2764             m_HandledTableBoxes.insert(pTabBox);
2765             break;
2766         }
2767     }
2768 
2769     return pResult;
2770 }
2771 
2772 const SwCellFrm * SwTableCellInfo::getCellFrm() const
2773 {
2774     return m_pImpl->getCellFrm();
2775 }
2776 
2777 bool SwTableCellInfo::Impl::getNext()
2778 {
2779     if (m_pCellFrm == NULL)
2780     {
2781         if (m_pTabFrm != NULL)
2782             m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pTabFrm);
2783     }
2784     else
2785         m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pCellFrm);
2786 
2787     return m_pCellFrm != NULL;
2788 }
2789 
2790 SwTableCellInfo::SwTableCellInfo(const SwTable * pTable)
2791 {
2792     m_pImpl.reset(new Impl());
2793     m_pImpl->setTable(pTable);
2794 }
2795 
2796 SwTableCellInfo::~SwTableCellInfo()
2797 {
2798 }
2799 
2800 bool SwTableCellInfo::getNext()
2801 {
2802     return m_pImpl->getNext();
2803 }
2804 
2805 SwRect SwTableCellInfo::getRect() const
2806 {
2807     SwRect aRet;
2808 
2809     if (getCellFrm() != NULL)
2810         aRet = getCellFrm()->Frm();
2811 
2812     return aRet;
2813 }
2814 
2815 const SwTableBox * SwTableCellInfo::getTableBox() const
2816 {
2817     const SwTableBox * pRet = NULL;
2818 
2819     if (getCellFrm() != NULL)
2820         pRet = getCellFrm()->GetTabBox();
2821 
2822     return pRet;
2823 }
2824 
2825 void SwTable::RegisterToFormat( SwFmt& rFmt )
2826 {
2827     rFmt.Add( this );
2828 }
2829 
2830 void SwTableLine::RegisterToFormat( SwFmt& rFmt )
2831 {
2832     rFmt.Add( this );
2833 }
2834 
2835 void SwTableBox::RegisterToFormat( SwFmt& rFmt )
2836 {
2837     rFmt.Add( this );
2838 }
2839 
2840 void SwTableBox::ForgetFrmFmt()
2841 {
2842     if ( GetRegisteredIn() )
2843         GetRegisteredInNonConst()->Remove(this);
2844 }
2845 
2846 
2847