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