xref: /trunk/main/sw/source/core/table/swtable.cxx (revision a5b190bfa3e1bed4623e2958a8877664a3b5506c)
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                     xub_StrLen nNextSetField = 0;
2586                     for( sal_uInt16 n = 0; n < pHts->Count(); ++n )
2587                     {
2588                         const SwTxtAttr* pAttr = (*pHts)[ n ];
2589                         if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() ||
2590                             *pAttr->GetStart() ||
2591                             *pAttr->GetAnyEnd() < rTxt.Len() )
2592                         {
2593                             if ((*pAttr->GetStart() == nNextSetField) &&
2594                                 (pAttr->Which() == RES_TXTATR_FIELD))
2595                             {
2596                                 // #i104949# hideous hack for report builder:
2597                                 // it inserts hidden variable-set fields at
2598                                 // the beginning of para in cell, but they
2599                                 // should not turn cell into text cell
2600                                 const SwField* pField = pAttr->GetFld().GetFld();
2601                                 if (pField &&
2602                                     (pField->GetTypeId() == TYP_SETFLD) &&
2603                                     (0 != (static_cast<SwSetExpField const*>
2604                                            (pField)->GetSubType() &
2605                                         nsSwExtendedSubType::SUB_INVISIBLE)))
2606                                 {
2607                                     nNextSetField = *pAttr->GetStart() + 1;
2608                                     continue;
2609                                 }
2610                             }
2611                             nPos = ULONG_MAX;
2612                             break;
2613                         }
2614                     }
2615                 }
2616             }
2617         }
2618         else
2619             nPos = ULONG_MAX;
2620     }
2621     return nPos;
2622 }
2623 
2624 // ist das eine FormelBox oder eine Box mit numerischen Inhalt (AutoSum)
2625 sal_uInt16 SwTableBox::IsFormulaOrValueBox() const
2626 {
2627     sal_uInt16 nWhich = 0;
2628     const SwTxtNode* pTNd;
2629     SwFrmFmt* pFmt = GetFrmFmt();
2630     if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ))
2631         nWhich = RES_BOXATR_FORMULA;
2632     else if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) &&
2633             !pFmt->GetDoc()->GetNumberFormatter()->IsTextFormat(
2634                 pFmt->GetTblBoxNumFmt().GetValue() ))
2635         nWhich = RES_BOXATR_VALUE;
2636     else if( pSttNd && pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex()
2637             && 0 != ( pTNd = pSttNd->GetNodes()[ pSttNd->GetIndex() + 1 ]
2638             ->GetTxtNode() ) && !pTNd->GetTxt().Len() )
2639         nWhich = USHRT_MAX;
2640 
2641     return nWhich;
2642 }
2643 
2644 void SwTableBox::ActualiseValueBox()
2645 {
2646     const SfxPoolItem *pFmtItem, *pValItem;
2647     SwFrmFmt* pFmt = GetFrmFmt();
2648     if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT, sal_True, &pFmtItem )
2649         && SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_True, &pValItem ))
2650     {
2651         const sal_uLong nFmtId = ((SwTblBoxNumFormat*)pFmtItem)->GetValue();
2652         sal_uLong nNdPos = ULONG_MAX;
2653         SvNumberFormatter* pNumFmtr = pFmt->GetDoc()->GetNumberFormatter();
2654 
2655         if( !pNumFmtr->IsTextFormat( nFmtId ) &&
2656             ULONG_MAX != (nNdPos = IsValidNumTxtNd( sal_True )) )
2657         {
2658             double fVal = ((SwTblBoxValue*)pValItem)->GetValue();
2659             Color* pCol = 0;
2660             String sNewTxt;
2661             pNumFmtr->GetOutputString( fVal, nFmtId, sNewTxt, &pCol );
2662 
2663             const String& rTxt = pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->GetTxt();
2664             if( rTxt != sNewTxt )
2665                 ChgTextToNum( *this, sNewTxt, pCol, sal_False ,nNdPos);
2666         }
2667     }
2668 }
2669 
2670 void SwTableBox_Impl::SetNewCol( Color** ppCol, const Color* pNewCol )
2671 {
2672     if( *ppCol != pNewCol )
2673     {
2674         delete *ppCol;
2675         if( pNewCol )
2676             *ppCol = new Color( *pNewCol );
2677         else
2678             *ppCol = 0;
2679     }
2680 }
2681 
2682 struct SwTableCellInfo::Impl
2683 {
2684     const SwTable * m_pTable;
2685     const SwCellFrm * m_pCellFrm;
2686     const SwTabFrm * m_pTabFrm;
2687     typedef ::std::set<const SwTableBox *> TableBoxes_t;
2688     TableBoxes_t m_HandledTableBoxes;
2689 
2690 public:
2691     Impl()
2692         : m_pTable(NULL), m_pCellFrm(NULL), m_pTabFrm(NULL)
2693     {
2694     }
2695 
2696     ~Impl() {}
2697 
2698     void setTable(const SwTable * pTable) {
2699         m_pTable = pTable;
2700         SwFrmFmt * pFrmFmt = m_pTable->GetFrmFmt();
2701         m_pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement(*pFrmFmt);
2702         if (m_pTabFrm->IsFollow())
2703             m_pTabFrm = m_pTabFrm->FindMaster(true);
2704     }
2705     const SwTable * getTable() const { return m_pTable; }
2706 
2707     const SwCellFrm * getCellFrm() const { return m_pCellFrm; }
2708 
2709     const SwFrm * getNextFrmInTable(const SwFrm * pFrm);
2710     const SwCellFrm * getNextCellFrm(const SwFrm * pFrm);
2711     const SwCellFrm * getNextTableBoxsCellFrm(const SwFrm * pFrm);
2712     bool getNext();
2713 };
2714 
2715 const SwFrm * SwTableCellInfo::Impl::getNextFrmInTable(const SwFrm * pFrm)
2716 {
2717     const SwFrm * pResult = NULL;
2718 
2719     if (((! pFrm->IsTabFrm()) || pFrm == m_pTabFrm) && pFrm->GetLower())
2720         pResult = pFrm->GetLower();
2721     else if (pFrm->GetNext())
2722         pResult = pFrm->GetNext();
2723     else
2724     {
2725         while (pFrm->GetUpper() != NULL)
2726         {
2727             pFrm = pFrm->GetUpper();
2728 
2729             if (pFrm->IsTabFrm())
2730             {
2731                 m_pTabFrm = static_cast<const SwTabFrm *>(pFrm)->GetFollow();
2732                 pResult = m_pTabFrm;
2733                 break;
2734             }
2735             else if (pFrm->GetNext())
2736             {
2737                 pResult = pFrm->GetNext();
2738                 break;
2739             }
2740         }
2741     }
2742 
2743     return pResult;
2744 }
2745 
2746 const SwCellFrm * SwTableCellInfo::Impl::getNextCellFrm(const SwFrm * pFrm)
2747 {
2748     const SwCellFrm * pResult = NULL;
2749 
2750     while ((pFrm = getNextFrmInTable(pFrm)) != NULL)
2751     {
2752         if (pFrm->IsCellFrm())
2753         {
2754             pResult = static_cast<const SwCellFrm *>(pFrm);
2755             break;
2756         }
2757     }
2758 
2759     return pResult;
2760 }
2761 
2762 const SwCellFrm * SwTableCellInfo::Impl::getNextTableBoxsCellFrm(const SwFrm * pFrm)
2763 {
2764     const SwCellFrm * pResult = NULL;
2765 
2766     while ((pFrm = getNextCellFrm(pFrm)) != NULL)
2767     {
2768         const SwCellFrm * pCellFrm = static_cast<const SwCellFrm *>(pFrm);
2769         const SwTableBox * pTabBox = pCellFrm->GetTabBox();
2770         TableBoxes_t::const_iterator aIt = m_HandledTableBoxes.find(pTabBox);
2771 
2772         if (aIt == m_HandledTableBoxes.end())
2773         {
2774             pResult = pCellFrm;
2775             m_HandledTableBoxes.insert(pTabBox);
2776             break;
2777         }
2778     }
2779 
2780     return pResult;
2781 }
2782 
2783 const SwCellFrm * SwTableCellInfo::getCellFrm() const
2784 {
2785     return m_pImpl->getCellFrm();
2786 }
2787 
2788 bool SwTableCellInfo::Impl::getNext()
2789 {
2790     if (m_pCellFrm == NULL)
2791     {
2792         if (m_pTabFrm != NULL)
2793             m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pTabFrm);
2794     }
2795     else
2796         m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pCellFrm);
2797 
2798     return m_pCellFrm != NULL;
2799 }
2800 
2801 SwTableCellInfo::SwTableCellInfo(const SwTable * pTable)
2802 {
2803     m_pImpl.reset(new Impl());
2804     m_pImpl->setTable(pTable);
2805 }
2806 
2807 SwTableCellInfo::~SwTableCellInfo()
2808 {
2809 }
2810 
2811 bool SwTableCellInfo::getNext()
2812 {
2813     return m_pImpl->getNext();
2814 }
2815 
2816 SwRect SwTableCellInfo::getRect() const
2817 {
2818     SwRect aRet;
2819 
2820     if (getCellFrm() != NULL)
2821         aRet = getCellFrm()->Frm();
2822 
2823     return aRet;
2824 }
2825 
2826 const SwTableBox * SwTableCellInfo::getTableBox() const
2827 {
2828     const SwTableBox * pRet = NULL;
2829 
2830     if (getCellFrm() != NULL)
2831         pRet = getCellFrm()->GetTabBox();
2832 
2833     return pRet;
2834 }
2835 
2836 void SwTable::RegisterToFormat( SwFmt& rFmt )
2837 {
2838     rFmt.Add( this );
2839 }
2840 
2841 void SwTableLine::RegisterToFormat( SwFmt& rFmt )
2842 {
2843     rFmt.Add( this );
2844 }
2845 
2846 void SwTableBox::RegisterToFormat( SwFmt& rFmt )
2847 {
2848     rFmt.Add( this );
2849 }
2850 
2851 void SwTableBox::ForgetFrmFmt()
2852 {
2853     if ( GetRegisteredIn() )
2854         GetRegisteredInNonConst()->Remove(this);
2855 }
2856 
2857 
2858