Update ooo320-m1
[ooovba.git] / sw / source / core / table / swtable.cxx
blobcaffe6edbf4672b8ba2d092c7a9eb46cc43232f5
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: swtable.cxx,v $
10 * $Revision: 1.16 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #ifdef WTC
35 #define private public
36 #endif
38 #include <ctype.h>
39 #include <float.h>
40 #include <hintids.hxx>
41 #include <hints.hxx> // fuer SwAttrSetChg
42 #include <svx/lrspitem.hxx>
43 #include <svx/shaditem.hxx>
44 #include <svx/adjitem.hxx>
45 #include <svx/colritem.hxx>
46 #include <svx/linkmgr.hxx>
47 #include <svx/boxitem.hxx>
50 #include <fmtfsize.hxx>
51 #include <fmtornt.hxx>
52 #include <fmtpdsc.hxx>
53 #include <frmatr.hxx>
54 #include <doc.hxx>
55 #include <docary.hxx> // fuer RedlineTbl()
56 #include <frame.hxx>
57 #include <swtable.hxx>
58 #include <ndtxt.hxx>
59 #include <tabcol.hxx>
60 #include <tabfrm.hxx>
61 #include <cellfrm.hxx>
62 #include <rowfrm.hxx>
63 #include <swserv.hxx>
64 #include <expfld.hxx>
65 #include <mdiexp.hxx>
66 #include <cellatr.hxx>
67 #include <txatbase.hxx>
68 #include <htmltbl.hxx>
69 #include <swtblfmt.hxx>
70 #include <ndindex.hxx>
71 #include <tblrwcl.hxx>
72 #include <shellres.hxx>
73 #include <viewsh.hxx>
74 #include <redline.hxx>
75 #include <list>
77 #ifdef PRODUCT
78 #define CHECK_TABLE(t)
79 #else
80 #ifdef DEBUG
81 #define CHECK_TABLE(t) (t).CheckConsistency();
82 #else
83 #define CHECK_TABLE(t)
84 #endif
85 #endif
87 using namespace com::sun::star;
89 TYPEINIT1( SwTable, SwClient );
90 TYPEINIT1( SwTableBox, SwClient );
91 TYPEINIT1( SwTableLine, SwClient );
92 TYPEINIT1( SwTableFmt, SwFrmFmt );
93 TYPEINIT1( SwTableBoxFmt, SwFrmFmt );
94 TYPEINIT1( SwTableLineFmt, SwFrmFmt );
96 SV_IMPL_PTRARR(SwTableLines,SwTableLine*);
97 SV_IMPL_PTRARR(SwTableBoxes,SwTableBox*);
98 SV_IMPL_PTRARR_SORT(SwTableSortBoxes,SwTableBoxPtr);
100 SV_IMPL_REF( SwServerObject )
102 #define COLFUZZY 20
104 //----------------------------------
106 class SwTableBox_Impl
108 Color *mpUserColor, *mpNumFmtColor;
109 long mnRowSpan;
110 bool mbDummyFlag;
112 void SetNewCol( Color** ppCol, const Color* pNewCol );
113 public:
114 SwTableBox_Impl() : mpUserColor(0), mpNumFmtColor(0), mnRowSpan(1),
115 mbDummyFlag( false ) {}
116 ~SwTableBox_Impl() { delete mpUserColor; delete mpNumFmtColor; }
118 const Color* GetSaveUserColor() const { return mpUserColor; }
119 const Color* GetSaveNumFmtColor() const { return mpNumFmtColor; }
120 void SetSaveUserColor(const Color* p ) { SetNewCol( &mpUserColor, p ); }
121 void SetSaveNumFmtColor( const Color* p ) { SetNewCol( &mpNumFmtColor, p ); }
122 long getRowSpan() const { return mnRowSpan; }
123 void setRowSpan( long nNewRowSpan ) { mnRowSpan = nNewRowSpan; }
124 bool getDummyFlag() const { return mbDummyFlag; }
125 void setDummyFlag( bool bDummy ) { mbDummyFlag = bDummy; }
128 // ----------- Inlines -----------------------------
130 inline const Color* SwTableBox::GetSaveUserColor() const
132 return pImpl ? pImpl->GetSaveUserColor() : 0;
135 inline const Color* SwTableBox::GetSaveNumFmtColor() const
137 return pImpl ? pImpl->GetSaveNumFmtColor() : 0;
140 inline void SwTableBox::SetSaveUserColor(const Color* p )
142 if( pImpl )
143 pImpl->SetSaveUserColor( p );
144 else if( p )
145 ( pImpl = new SwTableBox_Impl ) ->SetSaveUserColor( p );
148 inline void SwTableBox::SetSaveNumFmtColor( const Color* p )
150 if( pImpl )
151 pImpl->SetSaveNumFmtColor( p );
152 else if( p )
153 ( pImpl = new SwTableBox_Impl )->SetSaveNumFmtColor( p );
156 long SwTableBox::getRowSpan() const
158 return pImpl ? pImpl->getRowSpan() : 1;
161 void SwTableBox::setRowSpan( long nNewRowSpan )
163 if( !pImpl )
165 if( nNewRowSpan == 1 )
166 return;
167 pImpl = new SwTableBox_Impl();
169 pImpl->setRowSpan( nNewRowSpan );
172 bool SwTableBox::getDummyFlag() const
174 return pImpl ? pImpl->getDummyFlag() : false;
177 void SwTableBox::setDummyFlag( bool bDummy )
179 if( !pImpl )
181 if( !bDummy )
182 return;
183 pImpl = new SwTableBox_Impl();
185 pImpl->setDummyFlag( bDummy );
188 //JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten)
189 String& lcl_TabToBlankAtSttEnd( String& rTxt )
191 sal_Unicode c;
192 xub_StrLen n;
194 for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
195 if( '\x9' == c )
196 rTxt.SetChar( n, ' ' );
197 for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
198 if( '\x9' == c )
199 rTxt.SetChar( n, ' ' );
200 return rTxt;
203 String& lcl_DelTabsAtSttEnd( String& rTxt )
205 sal_Unicode c;
206 xub_StrLen n;
208 for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
209 if( '\x9' == c )
210 rTxt.Erase( n--, 1 );
211 for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
212 if( '\x9' == c )
213 rTxt.Erase( n, 1 );
214 return rTxt;
217 void _InsTblBox( SwDoc* pDoc, SwTableNode* pTblNd,
218 SwTableLine* pLine, SwTableBoxFmt* pBoxFrmFmt,
219 SwTableBox* pBox,
220 USHORT nInsPos, USHORT nCnt )
222 ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
223 SwNodeIndex aIdx( *pBox->GetSttNd(), +1 );
224 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
225 if( !pCNd )
226 pCNd = pDoc->GetNodes().GoNext( &aIdx );
227 ASSERT( pCNd, "Box ohne ContentNode" );
229 if( pCNd->IsTxtNode() )
231 if( pBox->GetSaveNumFmtColor() && pCNd->GetpSwAttrSet() )
233 SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() );
234 if( pBox->GetSaveUserColor() )
235 aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR ));
236 else
237 aAttrSet.ClearItem( RES_CHRATR_COLOR );
238 pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
239 ((SwTxtNode*)pCNd)->GetTxtColl(),
240 &aAttrSet, nInsPos, nCnt );
242 else
243 pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
244 ((SwTxtNode*)pCNd)->GetTxtColl(),
245 pCNd->GetpSwAttrSet(),
246 nInsPos, nCnt );
248 else
249 pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
250 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
251 nInsPos, nCnt );
253 long nRowSpan = pBox->getRowSpan();
254 if( nRowSpan != 1 )
256 SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
257 for( USHORT i = 0; i < nCnt; ++i )
259 pBox = rTblBoxes[ i + nInsPos ];
260 pBox->setRowSpan( nRowSpan );
265 /*************************************************************************
267 |* SwTable::SwTable()
269 |* Ersterstellung MA 09. Mar. 93
270 |* Letzte Aenderung MA 05. May. 93
272 |*************************************************************************/
273 SwTable::SwTable( SwTableFmt* pFmt )
274 : SwClient( pFmt ),
275 pHTMLLayout( 0 ),
276 pTableNode( 0 ),
277 nGrfsThatResize( 0 ),
278 nRowsToRepeat( 1 ),
279 bModifyLocked( FALSE ),
280 bNewModel( TRUE )
282 // default Wert aus den Optionen setzen
283 eTblChgMode = (TblChgMode)GetTblChgDefaultMode();
286 SwTable::SwTable( const SwTable& rTable )
287 : SwClient( rTable.GetFrmFmt() ),
288 pHTMLLayout( 0 ),
289 pTableNode( 0 ),
290 eTblChgMode( rTable.eTblChgMode ),
291 nGrfsThatResize( 0 ),
292 nRowsToRepeat( rTable.GetRowsToRepeat() ),
293 bModifyLocked( FALSE ),
294 bNewModel( rTable.bNewModel )
298 void DelBoxNode( SwTableSortBoxes& rSortCntBoxes )
300 for( USHORT n = 0; n < rSortCntBoxes.Count(); ++n )
301 rSortCntBoxes[ n ]->pSttNd = 0;
304 SwTable::~SwTable()
306 if( refObj.Is() )
308 SwDoc* pDoc = GetFrmFmt()->GetDoc();
309 if( !pDoc->IsInDtor() ) // dann aus der Liste entfernen
310 pDoc->GetLinkManager().RemoveServer( &refObj );
312 refObj->Closed();
315 // ist die Tabelle der letzte Client im FrameFormat, kann dieses
316 // geloescht werden
317 SwTableFmt* pFmt = (SwTableFmt*)GetFrmFmt();
318 pFmt->Remove( this ); // austragen,
320 if( !pFmt->GetDepends() )
321 pFmt->GetDoc()->DelTblFrmFmt( pFmt ); // und loeschen
323 // Loesche die Pointer aus dem SortArray der Boxen, die
324 // Objecte bleiben erhalten und werden vom DTOR der Lines/Boxes
325 // Arrays geloescht.
326 //JP: reicht leider nicht, es muessen die Pointer auf den StartNode
327 // der Section geloescht werden
328 DelBoxNode( aSortCntBoxes );
329 aSortCntBoxes.Remove( (USHORT)0, aSortCntBoxes.Count() );
330 delete pHTMLLayout;
334 /*************************************************************************
336 |* SwTable::Modify()
338 |* Ersterstellung JP ??
339 |* Letzte Aenderung MA 06. May. 93
341 |*************************************************************************/
342 inline void FmtInArr( SvPtrarr& rFmtArr, SwFmt* pBoxFmt )
344 BOOL bRet = USHRT_MAX != rFmtArr.GetPos( (VoidPtr)pBoxFmt );
345 if( !bRet )
346 rFmtArr.Insert( (VoidPtr)pBoxFmt, rFmtArr.Count() );
349 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
350 const long nNew, SvPtrarr& rFmtArr );
352 void lcl_ModifyLines( SwTableLines &rLines, const long nOld,
353 const long nNew, SvPtrarr& rFmtArr, const bool bCheckSum )
355 for ( USHORT i = 0; i < rLines.Count(); ++i )
356 ::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFmtArr );
357 if( bCheckSum )
359 for( USHORT i = 0; i < rFmtArr.Count(); ++i )
361 SwFmt* pFmt = (SwFmt*)rFmtArr[i];
362 sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
363 nBox *= nNew;
364 nBox /= nOld;
365 SwFmtFrmSize aNewBox( ATT_VAR_SIZE, SwTwips(nBox), 0 );
366 pFmt->LockModify();
367 pFmt->SetFmtAttr( aNewBox );
368 pFmt->UnlockModify();
373 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
374 const long nNew, SvPtrarr& rFmtArr )
376 sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths
377 sal_uInt64 nOriginalSum = 0; // Sum of original widths
378 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
380 SwTableBox &rBox = *rBoxes[i];
381 if ( rBox.GetTabLines().Count() )
383 // For SubTables the rounding problem will not be solved :-(
384 ::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFmtArr, false );
386 //Die Box anpassen
387 SwFrmFmt *pFmt = rBox.GetFrmFmt();
388 sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
389 nOriginalSum += nBox;
390 nBox *= nNew;
391 nBox /= nOld;
392 sal_uInt64 nWishedSum = nOriginalSum;
393 nWishedSum *= nNew;
394 nWishedSum /= nOld;
395 nWishedSum -= nSum;
396 if( nWishedSum > 0 )
398 if( nBox == nWishedSum )
399 FmtInArr( rFmtArr, pFmt );
400 else
402 nBox = nWishedSum;
403 pFmt = rBox.ClaimFrmFmt();
404 SwFmtFrmSize aNewBox( ATT_VAR_SIZE, static_cast< SwTwips >(nBox), 0 );
405 pFmt->LockModify();
406 pFmt->SetFmtAttr( aNewBox );
407 pFmt->UnlockModify();
410 else {
411 ASSERT( false, "Rounding error" );
413 nSum += nBox;
417 void SwTable::Modify( SfxPoolItem *pOld, SfxPoolItem *pNew )
419 // fange SSize Aenderungen ab, um die Lines/Boxen anzupassen
420 USHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
421 const SwFmtFrmSize* pNewSize = 0, *pOldSize = 0;
423 if( RES_ATTRSET_CHG == nWhich )
425 if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState(
426 RES_FRM_SIZE, FALSE, (const SfxPoolItem**)&pNewSize ))
427 pOldSize = &((SwAttrSetChg*)pOld)->GetChgSet()->GetFrmSize();
429 else if( RES_FRM_SIZE == nWhich )
431 pOldSize = (const SwFmtFrmSize*)pOld;
432 pNewSize = (const SwFmtFrmSize*)pNew;
435 if( pOldSize || pNewSize )
437 if ( !IsModifyLocked() )
439 ASSERT( pOldSize && pOldSize->Which() == RES_FRM_SIZE &&
440 pNewSize && pNewSize->Which() == RES_FRM_SIZE,
441 "Kein Old oder New fuer FmtFrmSize-Modify der SwTable." );
442 AdjustWidths( pOldSize->GetWidth(), pNewSize->GetWidth() );
445 else
446 SwClient::Modify( pOld, pNew ); // fuers ObjectDying
449 void SwTable::AdjustWidths( const long nOld, const long nNew )
451 SvPtrarr aFmtArr( (BYTE)aLines[0]->GetTabBoxes().Count(), 1 );
452 ::lcl_ModifyLines( aLines, nOld, nNew, aFmtArr, true );
455 /*************************************************************************
457 |* SwTable::GetTabCols()
459 |* Ersterstellung MA 04. May. 93
460 |* Letzte Aenderung MA 30. Nov. 95
462 |*************************************************************************/
463 void lcl_RefreshHidden( SwTabCols &rToFill, USHORT nPos )
465 for ( USHORT i = 0; i < rToFill.Count(); ++i )
467 if ( Abs((long)(nPos - rToFill[i])) <= COLFUZZY )
469 rToFill.SetHidden( i, FALSE );
470 break;
475 void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox,
476 const SwFrmFmt *pTabFmt, const BOOL bHidden,
477 const FASTBOOL bRefreshHidden )
479 const long nWish = pTabFmt->GetFrmSize().GetWidth();
480 const long nAct = rToFill.GetRight() - rToFill.GetLeft(); // +1 why?
482 //Der Wert fuer die linke Kante der Box errechnet sich aus den
483 //Breiten der vorhergehenden Boxen.
484 USHORT nPos = 0;
485 USHORT nSum = 0;
486 USHORT nLeftMin = 0;
487 USHORT nRightMax = 0;
488 const SwTableBox *pCur = pBox;
489 const SwTableLine *pLine = pBox->GetUpper();
490 while ( pLine )
491 { const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
492 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
494 SwTwips nWidth = rBoxes[i]->GetFrmFmt()->GetFrmSize().GetWidth();
495 nSum = (USHORT)(nSum + nWidth);
496 sal_uInt64 nTmp = nSum;
497 nTmp *= nAct;
498 nTmp /= nWish;
499 if (rBoxes[i] != pCur)
501 if ( pLine == pBox->GetUpper() || 0 == nLeftMin )
502 nLeftMin = (USHORT)(nTmp - nPos);
503 nPos = (USHORT)nTmp;
505 else
507 nSum = (USHORT)(nSum - nWidth);
508 if ( 0 == nRightMax )
509 nRightMax = (USHORT)(nTmp - nPos);
510 break;
513 pCur = pLine->GetUpper();
514 pLine = pCur ? pCur->GetUpper() : 0;
517 BOOL bInsert = !bRefreshHidden;
518 for ( USHORT j = 0; bInsert && (j < rToFill.Count()); ++j )
520 long nCmp = rToFill[j];
521 if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
522 (nPos <= (nCmp + COLFUZZY)) )
524 bInsert = FALSE; //Hat ihn schon.
526 else if ( nPos < nCmp )
528 bInsert = FALSE;
529 rToFill.Insert( nPos, bHidden, j );
532 if ( bInsert )
533 rToFill.Insert( nPos, bHidden, rToFill.Count() );
534 else if ( bRefreshHidden )
535 ::lcl_RefreshHidden( rToFill, nPos );
537 if ( bHidden && !bRefreshHidden )
539 // calculate minimum/maximum values for the existing entries:
540 nLeftMin = nPos - nLeftMin;
541 nRightMax = nPos + nRightMax;
543 // check if nPos is entry:
544 bool bFoundPos = false;
545 bool bFoundMax = false;
546 for ( USHORT j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j )
548 SwTabColsEntry& rEntry = rToFill.GetEntry( j );
549 long nCmp = rToFill[j];
551 if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
552 (nPos <= (nCmp + COLFUZZY)) )
554 // check if nLeftMin is > old minimum for entry nPos:
555 const long nOldMin = rEntry.nMin;
556 if ( nLeftMin > nOldMin )
557 rEntry.nMin = nLeftMin;
558 // check if nRightMin is < old maximum for entry nPos:
559 const long nOldMax = rEntry.nMax;
560 if ( nRightMax < nOldMax )
561 rEntry.nMax = nRightMax;
563 bFoundPos = true;
565 else if ( (nRightMax >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
566 (nRightMax <= (nCmp + COLFUZZY)) )
568 // check if nPos is > old minimum for entry nRightMax:
569 const long nOldMin = rEntry.nMin;
570 if ( nPos > nOldMin )
571 rEntry.nMin = nPos;
573 bFoundMax = true;
579 void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill,
580 const SwFrmFmt *pTabFmt, FASTBOOL bRefreshHidden )
582 if ( pBox->GetTabLines().Count() )
584 const SwTableLines &rLines = pBox->GetTabLines();
585 for ( USHORT i = 0; i < rLines.Count(); ++i )
586 { const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
587 for ( USHORT j = 0; j < rBoxes.Count(); ++j )
588 ::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFmt, bRefreshHidden);
591 else
592 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, FALSE, bRefreshHidden );
595 void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill,
596 const SwFrmFmt *pTabFmt )
598 for ( USHORT i = 0; i < pLine->GetTabBoxes().Count(); ++i )
600 const SwTableBox *pBox = pLine->GetTabBoxes()[i];
601 if ( pBox->GetSttNd() )
602 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, TRUE, FALSE );
603 else
604 for ( USHORT j = 0; j < pBox->GetTabLines().Count(); ++j )
605 ::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFmt );
609 // MS: Sonst Absturz auf der DEC-Kiste
611 #if defined(ALPHA) && defined(WNT)
612 #pragma optimize("", off)
613 #endif
615 void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart,
616 BOOL bRefreshHidden, BOOL bCurRowOnly ) const
618 //MA 30. Nov. 95: Opt: wenn bHidden gesetzt ist, wird nur das Hidden
619 //Array aktualisiert.
620 if ( bRefreshHidden )
622 //Korrekturen entfernen
623 USHORT i;
624 for ( i = 0; i < rToFill.Count(); ++i )
626 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
627 rEntry.nPos -= rToFill.GetLeft();
628 rEntry.nMin -= rToFill.GetLeft();
629 rEntry.nMax -= rToFill.GetLeft();
632 //Alle sind hidden, dann die sichtbaren eintragen.
633 for ( i = 0; i < rToFill.Count(); ++i )
634 rToFill.SetHidden( i, TRUE );
636 else
638 rToFill.Remove( 0, rToFill.Count() );
641 //Eingetragen werden:
642 //1. Alle Boxen unterhalb der dem Start uebergeordneten Line sowie
643 // deren untergeordnete Boxen falls vorhanden.
644 //2. Ausgehend von der Line die uebergeordnete Box sowie deren Nachbarn;
645 // nicht aber deren untergeordnete.
646 //3. Mit der der Boxenkette uebergeordneten Line wieder wie 2. bis einer
647 // Line keine Box (sondern die Table) uebergeordnet ist.
648 //Es werden nur diejenigen Boxen eingetragen, die keine weiteren Zeilen
649 //enhalten. Die eintragende Funktion sorgt dafuer, dass keine doppelten
650 //eingetragen werden. Um dies zu gewaehrleisten wird mit einer gewissen
651 //Unschaerfe gearbeitet (um Rundungsfehler auszuschalten).
652 //Es werden nur die linken Kanten der Boxen eingetragen.
653 //Am Schluss wird der Erste wieder ausgetragen denn er ist bereits vom
654 //Rand abgedeckt.
656 //4. Nochmalige abscannen der Tabelle und eintragen _aller_ Boxen,
657 // jetzt aber als Hidden.
659 const SwFrmFmt *pTabFmt = GetFrmFmt();
661 //1.
662 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
664 USHORT i;
665 for ( i = 0; i < rBoxes.Count(); ++i )
666 ::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFmt, bRefreshHidden );
668 //2. und 3.
669 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
670 pStart->GetUpper()->GetUpper()->GetUpper() : 0;
671 while ( pLine )
673 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
674 for ( USHORT k = 0; k < rBoxes2.Count(); ++k )
675 ::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
676 pTabFmt, FALSE, bRefreshHidden );
677 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
680 if ( !bRefreshHidden )
682 //4.
683 if ( !bCurRowOnly )
685 for ( i = 0; i < aLines.Count(); ++i )
686 ::lcl_ProcessLineGet( aLines[i], rToFill, pTabFmt );
689 rToFill.Remove( 0, 1 );
692 //Die Koordinaten sind jetzt relativ zum linken Rand der Tabelle - also
693 //relativ zum nLeft vom SwTabCols. Die Werte werden aber relativ zum
694 //linken Rand - also nLeftMin vom SwTabCols - erwartet.
695 //Alle Werte muessen also um nLeft erweitert werden.
696 for ( i = 0; i < rToFill.Count(); ++i )
698 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
699 rEntry.nPos += rToFill.GetLeft();
700 rEntry.nMin += rToFill.GetLeft();
701 rEntry.nMax += rToFill.GetLeft();
705 #if defined(ALPHA) && defined(WNT)
706 #pragma optimize("", on)
707 #endif
709 /*************************************************************************
711 |* SwTable::SetTabCols()
713 |* Ersterstellung MA 04. May. 93
714 |* Letzte Aenderung MA 26. Aug. 98
716 |*************************************************************************/
717 //Struktur zur Parameteruebergabe
718 struct Parm
720 const SwTabCols &rNew;
721 const SwTabCols &rOld;
722 long nNewWish,
723 nOldWish;
724 SvPtrarr aBoxArr;
725 SwShareBoxFmts aShareFmts;
727 Parm( const SwTabCols &rN, const SwTabCols &rO ) :
728 rNew( rN ), rOld( rO ), aBoxArr( 10, 1 ) {}
730 inline BOOL BoxInArr( SvPtrarr& rArr, SwTableBox* pBox )
732 BOOL bRet = USHRT_MAX != rArr.GetPos( (VoidPtr)pBox );
733 if( !bRet )
734 rArr.Insert( (VoidPtr)pBox, rArr.Count() );
735 return bRet;
738 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm );
740 void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
742 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
743 for ( int i = rBoxes.Count()-1; i >= 0; --i )
744 ::lcl_ProcessBoxSet( rBoxes[ static_cast< USHORT >(i) ], rParm );
747 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
749 if ( pBox->GetTabLines().Count() )
750 { SwTableLines &rLines = pBox->GetTabLines();
751 for ( int i = rLines.Count()-1; i >= 0; --i )
752 lcl_ProcessLine( rLines[ static_cast< USHORT >(i) ], rParm );
754 else
756 //Aktuelle Position (linke und rechte Kante berechnen) und im
757 //alten TabCols suchen. Im neuen TabCols die Werte vergleichen und
758 //wenn es Unterschiede gibt die Box entsprechend anpassen.
759 //Wenn an der veraenderten Kante kein Nachbar existiert werden auch
760 //alle uebergeordneten Boxen angepasst.
762 const long nOldAct = rParm.rOld.GetRight() -
763 rParm.rOld.GetLeft(); // +1 why?
765 //Der Wert fuer die linke Kante der Box errechnet sich aus den
766 //Breiten der vorhergehenden Boxen plus dem linken Rand
767 long nLeft = rParm.rOld.GetLeft();
768 const SwTableBox *pCur = pBox;
769 const SwTableLine *pLine = pBox->GetUpper();
771 while ( pLine )
772 { const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
773 for ( USHORT i = 0; (i < rBoxes.Count()) && (rBoxes[i] != pCur); ++i)
775 sal_uInt64 nWidth = rBoxes[i]->GetFrmFmt()->
776 GetFrmSize().GetWidth();
777 nWidth *= nOldAct;
778 nWidth /= rParm.nOldWish;
779 nLeft += (USHORT)nWidth;
781 pCur = pLine->GetUpper();
782 pLine = pCur ? pCur->GetUpper() : 0;
784 long nLeftDiff;
785 long nRightDiff = 0;
786 if ( nLeft != rParm.rOld.GetLeft() ) //Es gibt noch Boxen davor.
788 //Rechte Kante ist linke Kante plus Breite.
789 sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
790 nWidth *= nOldAct;
791 nWidth /= rParm.nOldWish;
792 long nRight = nLeft + (long)nWidth;
793 USHORT nLeftPos = USHRT_MAX,
794 nRightPos = USHRT_MAX;
795 for ( USHORT i = 0; i < rParm.rOld.Count(); ++i )
797 if ( nLeft >= (rParm.rOld[i] - COLFUZZY) &&
798 nLeft <= (rParm.rOld[i] + COLFUZZY) )
799 nLeftPos = i;
800 else if ( nRight >= (rParm.rOld[i] - COLFUZZY) &&
801 nRight <= (rParm.rOld[i] + COLFUZZY) )
802 nRightPos = i;
804 nLeftDiff = nLeftPos != USHRT_MAX ?
805 (int)rParm.rOld[nLeftPos] - (int)rParm.rNew[nLeftPos] : 0;
806 nRightDiff= nRightPos!= USHRT_MAX ?
807 (int)rParm.rNew[nRightPos] - (int)rParm.rOld[nRightPos] : 0;
809 else //Die erste Box.
811 nLeftDiff = (long)rParm.rOld.GetLeft() - (long)rParm.rNew.GetLeft();
812 if ( rParm.rOld.Count() )
814 //Differnz zu der Kante berechnen, von der die erste Box
815 //beruehrt wird.
816 sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
817 nWidth *= nOldAct;
818 nWidth /= rParm.nOldWish;
819 long nTmp = (long)nWidth;
820 nTmp += rParm.rOld.GetLeft();
821 USHORT nLeftPos = USHRT_MAX;
822 for ( USHORT i = 0; i < rParm.rOld.Count() &&
823 nLeftPos == USHRT_MAX; ++i )
825 if ( nTmp >= (rParm.rOld[i] - COLFUZZY) &&
826 nTmp <= (rParm.rOld[i] + COLFUZZY) )
827 nLeftPos = i;
829 if ( nLeftPos != USHRT_MAX )
830 nRightDiff = (long)rParm.rNew[nLeftPos] -
831 (long)rParm.rOld[nLeftPos];
833 //MA 11. Feb. 99: #61577# 0 sollte doch gerade richtig sein, weil die
834 //Kante doch schon in SetTabCols() korrigiert wurde.
835 // else
836 // nRightDiff = (long)rParm.rNew.GetRight() -
837 // (long)rParm.rOld.GetRight();
840 if( pBox->getRowSpan() == 1 )
842 SwTableBoxes& rTblBoxes = pBox->GetUpper()->GetTabBoxes();
843 USHORT nPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox );
844 if( nPos && rTblBoxes[ nPos - 1 ]->getRowSpan() != 1 )
845 nLeftDiff = 0;
846 if( nPos + 1 < rTblBoxes.Count() &&
847 rTblBoxes[ nPos + 1 ]->getRowSpan() != 1 )
848 nRightDiff = 0;
850 else
851 nLeftDiff = nRightDiff = 0;
853 if ( nLeftDiff || nRightDiff )
855 //Die Differenz ist der tatsaechliche Differenzbetrag; die
856 //Attribute der Boxen um diesen Betrag anzupassen macht keinen
857 //Sinn wenn die Tabelle gestrecht ist. Der Differenzbetrag muss
858 //entsprechend umgerechnet werden.
859 long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
860 nLeftDiff *= rParm.nNewWish;
861 nLeftDiff /= nTmp;
862 nRightDiff *= rParm.nNewWish;
863 nRightDiff /= nTmp;
864 long nDiff = nLeftDiff + nRightDiff;
866 //Box und alle uebergeordneten um den Differenzbetrag anpassen.
867 while ( pBox )
869 SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
870 aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
871 if ( aFmtFrmSize.GetWidth() < 0 )
872 aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
873 rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
875 // The outer cells of the last row are responsible to adjust a surrounding cell.
876 // Last line check:
877 if ( pBox->GetUpper()->GetUpper() &&
878 pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines()
879 [pBox->GetUpper()->GetUpper()->GetTabLines().Count()-1])
881 pBox = 0;
883 else
885 // Middle cell check:
886 if ( pBox != pBox->GetUpper()->GetTabBoxes()[0] )
887 nDiff = nRightDiff;
889 if ( pBox != pBox->GetUpper()->GetTabBoxes()
890 [pBox->GetUpper()->GetTabBoxes().Count()-1] )
891 nDiff -= nRightDiff;
893 pBox = nDiff ? pBox->GetUpper()->GetUpper() : 0;
900 void lcl_ProcessBoxPtr( SwTableBox *pBox, SvPtrarr &rBoxArr,
901 BOOL bBefore )
903 if ( pBox->GetTabLines().Count() )
905 const SwTableLines &rLines = pBox->GetTabLines();
906 for ( USHORT i = 0; i < rLines.Count(); ++i )
908 const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
909 for ( USHORT j = 0; j < rBoxes.Count(); ++j )
910 ::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore );
913 else if ( bBefore )
914 rBoxArr.Insert( (VoidPtr)pBox, 0 );
915 else
916 rBoxArr.Insert( (VoidPtr)pBox, rBoxArr.Count() );
919 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm );
921 void lcl_AdjustLines( SwTableLines &rLines, const long nDiff, Parm &rParm )
923 for ( USHORT i = 0; i < rLines.Count(); ++i )
925 SwTableBox *pBox = rLines[i]->GetTabBoxes()
926 [rLines[i]->GetTabBoxes().Count()-1];
927 lcl_AdjustBox( pBox, nDiff, rParm );
931 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm )
933 if ( pBox->GetTabLines().Count() )
934 ::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm );
936 //Groesse der Box anpassen.
937 SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
938 aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
939 //#30009# if ( aFmtFrmSize.GetWidth() < 0 )
940 // aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
942 rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
945 void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld,
946 const SwTableBox *pStart, BOOL bCurRowOnly )
948 CHECK_TABLE( *this )
950 SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen
952 // FME: Made rOld const. The caller is responsible for passing correct
953 // values of rOld. Therefore we do not have to call GetTabCols anymore:
954 //GetTabCols( rOld, pStart );
956 Parm aParm( rNew, rOld );
958 ASSERT( rOld.Count() == rNew.Count(), "Columnanzahl veraendert.");
960 //Raender verarbeiten. Groesse der Tabelle und ein paar Boxen mussen
961 //angepasst werden. Bei der Groesseneinstellung darf allerdings das
962 //Modify nicht verarbeitet werden - dieses wuerde alle Boxen anpassen
963 //und das koennen wir ueberhaupt nicht gebrauchen.
964 SwFrmFmt *pFmt = GetFrmFmt();
965 aParm.nOldWish = aParm.nNewWish = pFmt->GetFrmSize().GetWidth();
966 if ( (rOld.GetLeft() != rNew.GetLeft()) ||
967 (rOld.GetRight()!= rNew.GetRight()) )
969 LockModify();
971 SvxLRSpaceItem aLR( pFmt->GetLRSpace() );
972 SvxShadowItem aSh( pFmt->GetShadow() );
974 SwTwips nShRight = aSh.CalcShadowSpace( SHADOW_RIGHT );
975 SwTwips nShLeft = aSh.CalcShadowSpace( SHADOW_LEFT );
977 aLR.SetLeft ( rNew.GetLeft() - nShLeft );
978 aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight );
979 pFmt->SetFmtAttr( aLR );
981 //Die Ausrichtung der Tabelle muss entsprechend angepasst werden,
982 //das geschieht so, dass die Tabelle genauso stehenbleibt wie der
983 //Anwender sie gerade hingezuppelt hat.
984 SwFmtHoriOrient aOri( pFmt->GetHoriOrient() );
985 if(text::HoriOrientation::NONE != aOri.GetHoriOrient())
987 const BOOL bLeftDist = rNew.GetLeft() != nShLeft;
988 const BOOL bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax();
989 if(!bLeftDist && !bRightDist)
990 aOri.SetHoriOrient( text::HoriOrientation::FULL );
991 else if(!bRightDist && rNew.GetLeft() > nShLeft )
992 aOri.SetHoriOrient( text::HoriOrientation::RIGHT );
993 else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax())
994 aOri.SetHoriOrient( text::HoriOrientation::LEFT );
995 else
996 aOri.SetHoriOrient( text::HoriOrientation::NONE );
998 pFmt->SetFmtAttr( aOri );
1000 const long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why?
1001 long nTabDiff = 0;
1003 if ( rOld.GetLeft() != rNew.GetLeft() )
1005 nTabDiff = rOld.GetLeft() - rNew.GetLeft();
1006 nTabDiff *= aParm.nOldWish;
1007 nTabDiff /= nAct;
1009 if ( rOld.GetRight() != rNew.GetRight() )
1011 long nDiff = rNew.GetRight() - rOld.GetRight();
1012 nDiff *= aParm.nOldWish;
1013 nDiff /= nAct;
1014 nTabDiff += nDiff;
1015 if( !IsNewModel() )
1016 ::lcl_AdjustLines( GetTabLines(), nDiff, aParm );
1019 //Groesse der Tabelle anpassen. Es muss beachtet werden, das die
1020 //Tabelle gestrecht sein kann.
1021 if ( nTabDiff )
1023 aParm.nNewWish += nTabDiff;
1024 if ( aParm.nNewWish < 0 )
1025 aParm.nNewWish = USHRT_MAX; //Uuups! Eine Rolle rueckwaerts.
1026 SwFmtFrmSize aSz( pFmt->GetFrmSize() );
1027 if ( aSz.GetWidth() != aParm.nNewWish )
1029 aSz.SetWidth( aParm.nNewWish );
1030 aSz.SetWidthPercent( 0 );
1031 pFmt->SetFmtAttr( aSz );
1034 UnlockModify();
1037 if( IsNewModel() )
1038 NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly );
1039 else
1041 if ( bCurRowOnly )
1043 //Um die aktuelle Zeile anzupassen muessen wir analog zu dem
1044 //Verfahren zum fuellen der TabCols (siehe GetTabCols()) die
1045 //Boxen der aktuellen Zeile abklappern.
1046 //Leider muessen wir auch hier dafuer sorgen, dass die Boxen von
1047 //hinten nach vorne bzw. von innen nach aussen veraendert werden.
1048 //Der beste Weg hierzu scheint mir darin zu liegen die
1049 //entsprechenden Boxen in einem PtrArray vorzumerken.
1051 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
1052 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
1053 ::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, FALSE );
1055 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
1056 pStart->GetUpper()->GetUpper()->GetUpper() : 0;
1057 const SwTableBox *pExcl = pStart->GetUpper()->GetUpper();
1058 while ( pLine )
1060 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
1061 BOOL bBefore = TRUE;
1062 for ( USHORT i = 0; i < rBoxes2.Count(); ++i )
1064 if ( rBoxes2[i] != pExcl )
1065 ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore );
1066 else
1067 bBefore = FALSE;
1069 pExcl = pLine->GetUpper();
1070 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
1072 //Nachdem wir haufenweise Boxen (hoffentlich alle und in der richtigen
1073 //Reihenfolge) eingetragen haben, brauchen diese nur noch rueckwaerts
1074 //verarbeitet zu werden.
1075 for ( int j = aParm.aBoxArr.Count()-1; j >= 0; --j )
1077 SwTableBox *pBox = (SwTableBox*)aParm.aBoxArr[ static_cast< USHORT >(j)];
1078 ::lcl_ProcessBoxSet( pBox, aParm );
1081 else
1082 { //Die gesamte Tabelle anzupassen ist 'einfach'.
1083 //Es werden alle Boxen, die keine Lines mehr enthalten angepasst.
1084 //Diese Boxen passen alle uebergeordneten Boxen entsprechend mit an.
1085 //Um uns nicht selbst hereinzulegen muss natuerlich rueckwaerst
1086 //gearbeitet werden!
1087 SwTableLines &rLines = GetTabLines();
1088 for ( int i = rLines.Count()-1; i >= 0; --i )
1089 ::lcl_ProcessLine( rLines[ static_cast< USHORT >(i) ], aParm );
1093 #ifndef PRODUCT
1095 // steht im tblrwcl.cxx
1096 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1097 // checke doch mal ob die Tabellen korrekte Breiten haben
1098 SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth();
1099 for( USHORT n = 0; n < aLines.Count(); ++n )
1100 _CheckBoxWidth( *aLines[ n ], nSize );
1102 #endif
1105 typedef std::pair<USHORT, USHORT> ColChange;
1106 typedef std::list< ColChange > ChangeList;
1108 static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew,
1109 Parm& rParm, USHORT nColFuzzy )
1111 ChangeList::iterator pCurr = rOldNew.begin();
1112 if( pCurr == rOldNew.end() )
1113 return;
1114 USHORT nCount = pLine->GetTabBoxes().Count();
1115 USHORT i = 0;
1116 SwTwips nBorder = 0;
1117 SwTwips nRest = 0;
1118 while( i < nCount )
1120 SwTableBox* pBox = pLine->GetTabBoxes()[i++];
1121 SwTwips nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1122 SwTwips nNewWidth = nWidth - nRest;
1123 nRest = 0;
1124 nBorder += nWidth;
1125 if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first )
1127 nBorder -= nColFuzzy;
1128 while( pCurr != rOldNew.end() && nBorder > pCurr->first )
1129 ++pCurr;
1130 if( pCurr != rOldNew.end() )
1132 nBorder += nColFuzzy;
1133 if( nBorder + nColFuzzy >= pCurr->first )
1135 if( pCurr->second == pCurr->first )
1136 nRest = 0;
1137 else
1138 nRest = pCurr->second - nBorder;
1139 nNewWidth += nRest;
1140 ++pCurr;
1144 if( nNewWidth != nWidth )
1146 if( nNewWidth < 0 )
1148 nRest += 1 - nNewWidth;
1149 nNewWidth = 1;
1151 SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
1152 aFmtFrmSize.SetWidth( nNewWidth );
1153 rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
1158 static void lcl_CalcNewWidths( std::list<USHORT> &rSpanPos, ChangeList& rChanges,
1159 SwTableLine* pLine, long nWish, long nWidth, bool bTop )
1161 if( !rChanges.size() )
1163 rSpanPos.clear();
1164 return;
1166 if( !rSpanPos.size() )
1168 rChanges.clear();
1169 return;
1171 std::list<USHORT> aNewSpanPos;
1172 ChangeList aNewChanges;
1173 ChangeList::iterator pCurr = rChanges.begin();
1174 aNewChanges.push_back( *pCurr ); // Nullposition
1175 std::list<USHORT>::iterator pSpan = rSpanPos.begin();
1176 USHORT nCurr = 0;
1177 USHORT nOrgSum = 0;
1178 bool bRowSpan = false;
1179 USHORT nRowSpanCount = 0;
1180 USHORT nCount = pLine->GetTabBoxes().Count();
1181 for( USHORT nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1183 SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1184 SwTwips nCurrWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1185 const long nRowSpan = pBox->getRowSpan();
1186 const bool bCurrRowSpan = bTop ? nRowSpan < 0 :
1187 ( nRowSpan > 1 || nRowSpan < -1 );
1188 if( bRowSpan || bCurrRowSpan )
1189 aNewSpanPos.push_back( nRowSpanCount );
1190 bRowSpan = bCurrRowSpan;
1191 nOrgSum = (USHORT)(nOrgSum + nCurrWidth);
1192 sal_uInt64 nSum = nOrgSum;
1193 nSum *= nWidth;
1194 nSum /= nWish;
1195 nSum *= nWish;
1196 nSum /= nWidth;
1197 USHORT nPos = (USHORT)nSum;
1198 while( pCurr != rChanges.end() && pCurr->first < nPos )
1200 #ifndef PRODUCT
1201 USHORT nTemp = pCurr->first;
1202 nTemp = pCurr->second;
1203 #endif
1204 ++nCurr;
1205 ++pCurr;
1207 bool bNew = true;
1208 if( pCurr != rChanges.end() && pCurr->first <= nPos &&
1209 pCurr->first != pCurr->second )
1211 while( pSpan != rSpanPos.end() && *pSpan < nCurr )
1212 ++pSpan;
1213 if( pSpan != rSpanPos.end() && *pSpan == nCurr )
1215 aNewChanges.push_back( *pCurr );
1216 ++nRowSpanCount;
1217 bNew = false;
1220 if( bNew )
1222 ColChange aTmp( nPos, nPos );
1223 aNewChanges.push_back( aTmp );
1224 ++nRowSpanCount;
1228 pCurr = aNewChanges.begin();
1229 ChangeList::iterator pLast = pCurr;
1230 ChangeList::iterator pLeftMove = pCurr;
1231 while( pCurr != aNewChanges.end() )
1233 if( pLeftMove == pCurr )
1235 while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second )
1238 if( pCurr->second == pCurr->first )
1240 if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second )
1242 if( pLeftMove->first == pLast->first )
1243 pCurr->second = pLeftMove->second;
1244 else
1246 sal_uInt64 nTmp = pCurr->first - pLast->first;
1247 nTmp *= pLeftMove->second - pLast->second;
1248 nTmp /= pLeftMove->first - pLast->first;
1249 nTmp += pLast->second;
1250 pCurr->second = (USHORT)nTmp;
1253 pLast = pCurr;
1254 ++pCurr;
1256 else if( pCurr->second > pCurr->first )
1258 pLast = pCurr;
1259 ++pCurr;
1260 ChangeList::iterator pNext = pCurr;
1261 while( pNext != pLeftMove && pNext->second == pNext->first &&
1262 pNext->second < pLast->second )
1263 ++pNext;
1264 while( pCurr != pNext )
1266 if( pNext == aNewChanges.end() || pNext->first == pLast->first )
1267 pCurr->second = pLast->second;
1268 else
1270 sal_uInt64 nTmp = pCurr->first - pLast->first;
1271 nTmp *= pNext->second - pLast->second;
1272 nTmp /= pNext->first - pLast->first;
1273 nTmp += pLast->second;
1274 pCurr->second = (USHORT)nTmp;
1276 ++pCurr;
1278 pLast = pCurr;
1280 else
1282 pLast = pCurr;
1283 ++pCurr;
1287 rChanges.clear();
1288 ChangeList::iterator pCopy = aNewChanges.begin();
1289 while( pCopy != aNewChanges.end() )
1290 rChanges.push_back( *pCopy++ );
1291 rSpanPos.clear();
1292 std::list<USHORT>::iterator pSpCopy = aNewSpanPos.begin();
1293 while( pSpCopy != aNewSpanPos.end() )
1294 rSpanPos.push_back( *pSpCopy++ );
1297 void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew,
1298 const SwTabCols &rOld, const SwTableBox *pStart, BOOL bCurRowOnly )
1300 #ifndef PRODUCT
1301 static int nCallCount = 0;
1302 ++nCallCount;
1303 #endif
1304 // First step: evaluate which lines have been moved/which widths changed
1305 ChangeList aOldNew;
1306 const long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1307 const long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1308 if( nNewWidth < 1 || nOldWidth < 1 )
1309 return;
1310 for( USHORT i = 0; i <= rOld.Count(); ++i )
1312 sal_uInt64 nNewPos;
1313 sal_uInt64 nOldPos;
1314 if( i == rOld.Count() )
1316 nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1317 nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1319 else
1321 nOldPos = rOld[i] - rParm.rOld.GetLeft();
1322 nNewPos = rNew[i] - rParm.rNew.GetLeft();
1324 nNewPos *= rParm.nNewWish;
1325 nNewPos /= nNewWidth;
1326 nOldPos *= rParm.nOldWish;
1327 nOldPos /= nOldWidth;
1328 if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 )
1330 ColChange aChg( (USHORT)nOldPos, (USHORT)nNewPos );
1331 aOldNew.push_back( aChg );
1334 // Finished first step
1335 int nCount = aOldNew.size();
1336 if( !nCount )
1337 return; // no change, nothing to do
1338 SwTableLines &rLines = GetTabLines();
1339 if( bCurRowOnly )
1341 const SwTableLine* pCurrLine = pStart->GetUpper();
1342 USHORT nCurr = rLines.C40_GETPOS( SwTableLine, pCurrLine );
1343 if( nCurr >= USHRT_MAX )
1344 return;
1346 ColChange aChg( 0, 0 );
1347 aOldNew.push_front( aChg );
1348 std::list<USHORT> aRowSpanPos;
1349 if( nCurr )
1351 ChangeList aCopy;
1352 ChangeList::iterator pCop = aOldNew.begin();
1353 USHORT nPos = 0;
1354 while( pCop != aOldNew.end() )
1356 aCopy.push_back( *pCop );
1357 ++pCop;
1358 aRowSpanPos.push_back( nPos++ );
1360 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1361 rParm.nOldWish, nOldWidth, true );
1362 bool bGoOn = aRowSpanPos.size() > 0;
1363 USHORT j = nCurr;
1364 while( bGoOn )
1366 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j],
1367 rParm.nOldWish, nOldWidth, true );
1368 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1369 bGoOn = aRowSpanPos.size() > 0 && j > 0;
1371 aRowSpanPos.clear();
1373 if( nCurr+1 < rLines.Count() )
1375 ChangeList aCopy;
1376 ChangeList::iterator pCop = aOldNew.begin();
1377 USHORT nPos = 0;
1378 while( pCop != aOldNew.end() )
1380 aCopy.push_back( *pCop );
1381 ++pCop;
1382 aRowSpanPos.push_back( nPos++ );
1384 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1385 rParm.nOldWish, nOldWidth, false );
1386 bool bGoOn = aRowSpanPos.size() > 0;
1387 USHORT j = nCurr;
1388 while( bGoOn )
1390 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j],
1391 rParm.nOldWish, nOldWidth, false );
1392 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1393 bGoOn = aRowSpanPos.size() > 0 && j+1 < rLines.Count();
1396 ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, 1 );
1398 else for( USHORT i = 0; i < rLines.Count(); ++i )
1399 ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY );
1400 CHECK_TABLE( *this )
1404 /*************************************************************************
1406 |* const SwTableBox* SwTable::GetTblBox( const Strn?ng& rName ) const
1407 |* gebe den Pointer auf die benannte Box zurueck.
1409 |* Ersterstellung JP 30. Jun. 93
1410 |* Letzte Aenderung JP 30. Jun. 93
1412 |*************************************************************************/
1414 BOOL IsValidRowName( const String& rStr )
1416 BOOL bIsValid = TRUE;
1417 xub_StrLen nLen = rStr.Len();
1418 for (xub_StrLen i = 0; i < nLen && bIsValid; ++i)
1420 const sal_Unicode cChar = rStr.GetChar(i);
1421 if (cChar < '0' || cChar > '9')
1422 bIsValid = FALSE;
1424 return bIsValid;
1427 // --> OD 2007-08-03 #i80314#
1428 // add 3rd parameter and its handling
1429 USHORT SwTable::_GetBoxNum( String& rStr, BOOL bFirstPart,
1430 const bool bPerformValidCheck )
1432 USHORT nRet = 0;
1433 xub_StrLen nPos = 0;
1434 if( bFirstPart ) // TRUE == column; FALSE == row
1436 // die 1. ist mit Buchstaben addressiert!
1437 sal_Unicode cChar;
1438 BOOL bFirst = TRUE;
1439 while( 0 != ( cChar = rStr.GetChar( nPos )) &&
1440 ( (cChar >= 'A' && cChar <= 'Z') ||
1441 (cChar >= 'a' && cChar <= 'z') ) )
1443 if( (cChar -= 'A') >= 26 )
1444 cChar -= 'a' - '[';
1445 if( bFirst )
1446 bFirst = FALSE;
1447 else
1448 ++nRet;
1449 nRet = nRet * 52 + cChar;
1450 ++nPos;
1452 rStr.Erase( 0, nPos ); // Zeichen aus dem String loeschen
1454 else if( STRING_NOTFOUND == ( nPos = rStr.Search( aDotStr ) ))
1456 nRet = 0;
1457 if ( !bPerformValidCheck || IsValidRowName( rStr ) )
1459 nRet = static_cast<USHORT>(rStr.ToInt32());
1461 rStr.Erase();
1463 else
1465 nRet = 0;
1466 String aTxt( rStr.Copy( 0, nPos ) );
1467 if ( !bPerformValidCheck || IsValidRowName( aTxt ) )
1469 nRet = static_cast<USHORT>(aTxt.ToInt32());
1471 rStr.Erase( 0, nPos+1 );
1473 return nRet;
1475 // <--
1477 // --> OD 2007-08-03 #i80314#
1478 // add 2nd parameter and its handling
1479 const SwTableBox* SwTable::GetTblBox( const String& rName,
1480 const bool bPerformValidCheck ) const
1482 const SwTableBox* pBox = 0;
1483 const SwTableLine* pLine;
1484 const SwTableLines* pLines;
1485 const SwTableBoxes* pBoxes;
1487 USHORT nLine, nBox;
1488 String aNm( rName );
1489 while( aNm.Len() )
1491 nBox = SwTable::_GetBoxNum( aNm, 0 == pBox, bPerformValidCheck );
1492 // erste Box ?
1493 if( !pBox )
1494 pLines = &GetTabLines();
1495 else
1497 pLines = &pBox->GetTabLines();
1498 if( nBox )
1499 --nBox;
1502 nLine = SwTable::_GetBoxNum( aNm, FALSE, bPerformValidCheck );
1504 // bestimme die Line
1505 if( !nLine || nLine > pLines->Count() )
1506 return 0;
1507 pLine = (*pLines)[ nLine-1 ];
1509 // bestimme die Box
1510 pBoxes = &pLine->GetTabBoxes();
1511 if( nBox >= pBoxes->Count() )
1512 return 0;
1513 pBox = (*pBoxes)[ nBox ];
1516 // abpruefen, ob die gefundene Box auch wirklich eine Inhaltstragende
1517 // Box ist ??
1518 if( pBox && !pBox->GetSttNd() )
1520 ASSERT( FALSE, "Box ohne Inhalt, suche die naechste !!" );
1521 // "herunterfallen lassen" bis zur ersten Box
1522 while( pBox->GetTabLines().Count() )
1523 pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
1525 return pBox;
1528 SwTableBox* SwTable::GetTblBox( ULONG nSttIdx )
1530 //MA: Zur Optimierung nicht immer umstaendlich das ganze SortArray abhuenern.
1531 //OS: #102675# converting text to table tries und certain conditions
1532 // to ask for a table box of a table that is not yet having a format
1533 if(!GetFrmFmt())
1534 return 0;
1535 SwTableBox* pRet = 0;
1536 SwNodes& rNds = GetFrmFmt()->GetDoc()->GetNodes();
1537 ULONG nIndex = nSttIdx + 1;
1538 SwCntntNode* pCNd = 0;
1539 SwTableNode* pTblNd = 0;
1541 while ( nIndex < rNds.Count() )
1543 pTblNd = rNds[ nIndex ]->GetTableNode();
1544 if ( pTblNd )
1545 break;
1547 pCNd = rNds[ nIndex ]->GetCntntNode();
1548 if ( pCNd )
1549 break;
1551 ++nIndex;
1554 if ( pCNd || pTblNd )
1556 SwModify* pModify = pCNd;
1557 // --> FME 2007-3-26 #144862# Better handling of table in table:
1558 if ( pTblNd && pTblNd->GetTable().GetFrmFmt() )
1559 pModify = pTblNd->GetTable().GetFrmFmt();
1560 // <--
1562 SwClientIter aIter( *pModify );
1563 SwFrm *pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) );
1564 while ( pFrm && !pFrm->IsCellFrm() )
1565 pFrm = pFrm->GetUpper();
1566 if ( pFrm )
1567 pRet = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1570 //Falls es das Layout noch nicht gibt oder sonstwie etwas schieft geht.
1571 if ( !pRet )
1573 for( USHORT n = aSortCntBoxes.Count(); n; )
1574 if( aSortCntBoxes[ --n ]->GetSttIdx() == nSttIdx )
1575 return aSortCntBoxes[ n ];
1577 return pRet;
1580 BOOL SwTable::IsTblComplex() const
1582 // returnt TRUE wenn sich in der Tabelle Verschachtelungen befinden
1583 // steht eine Box nicht in der obersten Line, da wurde gesplittet/
1584 // gemergt und die Struktur ist komplexer.
1585 for( USHORT n = 0; n < aSortCntBoxes.Count(); ++n )
1586 if( aSortCntBoxes[ n ]->GetUpper()->GetUpper() )
1587 return TRUE;
1588 return FALSE;
1593 /*************************************************************************
1595 |* SwTableLine::SwTableLine()
1597 |* Ersterstellung MA 09. Mar. 93
1598 |* Letzte Aenderung MA 09. Mar. 93
1600 |*************************************************************************/
1601 SwTableLine::SwTableLine( SwTableLineFmt *pFmt, USHORT nBoxes,
1602 SwTableBox *pUp )
1603 : SwClient( pFmt ),
1604 aBoxes( (BYTE)nBoxes, 1 ),
1605 pUpper( pUp )
1609 SwTableLine::~SwTableLine()
1611 // ist die TabelleLine der letzte Client im FrameFormat, kann dieses
1612 // geloescht werden
1613 SwModify* pMod = GetFrmFmt();
1614 pMod->Remove( this ); // austragen,
1615 if( !pMod->GetDepends() )
1616 delete pMod; // und loeschen
1619 /*************************************************************************
1621 |* SwTableLine::ClaimFrmFmt(), ChgFrmFmt()
1623 |* Ersterstellung MA 03. May. 93
1624 |* Letzte Aenderung MA 07. Feb. 96
1626 |*************************************************************************/
1627 SwFrmFmt* SwTableLine::ClaimFrmFmt()
1629 //Wenn noch andere TableLines ausser mir selbst an dem FrmFmt haengen,
1630 //sehe ich mich leider gezwungen mir ein eingenes zu machen und mich
1631 //bei diesem anzumelden.
1632 SwTableLineFmt *pOld = (SwTableLineFmt*)GetFrmFmt();
1633 SwClientIter aIter( *pOld );
1635 SwClient* pLast;
1637 for( pLast = aIter.First( TYPE( SwTableLine )); pLast && pLast == this;
1638 pLast = aIter.Next() )
1641 if( pLast )
1643 SwTableLineFmt *pNewFmt = pOld->GetDoc()->MakeTableLineFmt();
1644 *pNewFmt = *pOld;
1646 //Erstmal die Frms ummelden.
1647 for( pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
1648 if( ((SwRowFrm*)pLast)->GetTabLine() == this )
1649 pNewFmt->Add( pLast );
1651 //Jetzt noch mich selbst ummelden.
1652 pNewFmt->Add( this );
1653 pOld = pNewFmt;
1656 return pOld;
1659 void SwTableLine::ChgFrmFmt( SwTableLineFmt *pNewFmt )
1661 SwFrmFmt *pOld = GetFrmFmt();
1662 SwClientIter aIter( *pOld );
1663 SwClient* pLast;
1665 //Erstmal die Frms ummelden.
1666 for( pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
1668 SwRowFrm *pRow = (SwRowFrm*)pLast;
1669 if( pRow->GetTabLine() == this )
1671 pNewFmt->Add( pLast );
1673 pRow->InvalidateSize();
1674 pRow->_InvalidatePrt();
1675 pRow->SetCompletePaint();
1676 pRow->ReinitializeFrmSizeAttrFlags();
1678 // --> FME 2004-10-27 #i35063#
1679 // consider 'split row allowed' attribute
1680 SwTabFrm* pTab = pRow->FindTabFrm();
1681 bool bInFollowFlowRow = false;
1682 const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
1683 pRow == pTab->GetFirstNonHeadlineRow();
1684 if ( bInFirstNonHeadlineRow ||
1685 !pRow->GetNext() ||
1686 0 != ( bInFollowFlowRow = pRow->IsInFollowFlowRow() ) ||
1687 0 != pRow->IsInSplitTableRow() )
1689 if ( bInFirstNonHeadlineRow || bInFollowFlowRow )
1690 pTab = pTab->FindMaster();
1692 pTab->SetRemoveFollowFlowLinePending( TRUE );
1693 pTab->InvalidatePos();
1695 // <--
1699 //Jetzt noch mich selbst ummelden.
1700 pNewFmt->Add( this );
1702 if ( !aIter.GoStart() )
1703 delete pOld;
1706 SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
1708 SwTwips nRet = 0;
1709 bLayoutAvailable = false;
1710 SwClientIter aIter( *GetFrmFmt() );
1711 // A row could appear several times in headers/footers so only one chain of master/follow tables
1712 // will be accepted...
1713 const SwTabFrm* pChain = NULL; // My chain
1714 for( SwClient* pLast = aIter.First( TYPE( SwFrm ) ); pLast;
1715 pLast = aIter.Next() )
1717 if( ((SwRowFrm*)pLast)->GetTabLine() == this )
1719 const SwTabFrm* pTab = static_cast<SwRowFrm*>(pLast)->FindTabFrm();
1720 bLayoutAvailable = ( pTab && pTab->IsVertical() ) ?
1721 ( 0 < pTab->Frm().Height() ) :
1722 ( 0 < pTab->Frm().Width() );
1724 // The first one defines the chain, if a chain is defined, only members of the chain
1725 // will be added.
1726 if( !pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow( pChain ) )
1728 pChain = pTab; // defines my chain (even it is already)
1729 if( pTab->IsVertical() )
1730 nRet += static_cast<SwRowFrm*>(pLast)->Frm().Width();
1731 else
1732 nRet += static_cast<SwRowFrm*>(pLast)->Frm().Height();
1733 // Optimization, if there are no master/follows in my chain, nothing more to add
1734 if( !pTab->HasFollow() && !pTab->IsFollow() )
1735 break;
1736 // This is not an optimization, this is necessary to avoid double additions of
1737 // repeating rows
1738 if( pTab->IsInHeadline( *static_cast<SwRowFrm*>(pLast) ) )
1739 break;
1743 return nRet;
1746 /*************************************************************************
1748 |* SwTableBox::SwTableBox()
1750 |* Ersterstellung MA 04. May. 93
1751 |* Letzte Aenderung MA 04. May. 93
1753 |*************************************************************************/
1754 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, USHORT nLines, SwTableLine *pUp )
1755 : SwClient( 0 ),
1756 aLines( (BYTE)nLines, 1 ),
1757 pSttNd( 0 ),
1758 pUpper( pUp ),
1759 pImpl( 0 )
1761 CheckBoxFmt( pFmt )->Add( this );
1764 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwNodeIndex &rIdx,
1765 SwTableLine *pUp )
1766 : SwClient( 0 ),
1767 aLines( 0, 0 ),
1768 pUpper( pUp ),
1769 pImpl( 0 )
1771 SwDoc* pDoc = pFmt->GetDoc();
1772 CheckBoxFmt( pFmt )->Add( this );
1774 pSttNd = pDoc->GetNodes()[ rIdx ]->GetStartNode();
1776 // an der Table eintragen
1777 const SwTableNode* pTblNd = pSttNd->FindTableNode();
1778 ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1779 SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1780 GetTabSortBoxes();
1781 SwTableBox* p = this; // error: &this
1782 rSrtArr.Insert( p ); // eintragen
1785 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwStartNode& rSttNd, SwTableLine *pUp ) :
1786 SwClient( 0 ),
1787 aLines( 0, 0 ),
1788 pSttNd( &rSttNd ),
1789 pUpper( pUp ),
1790 pImpl( 0 )
1792 CheckBoxFmt( pFmt )->Add( this );
1794 // an der Table eintragen
1795 const SwTableNode* pTblNd = pSttNd->FindTableNode();
1796 ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1797 SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1798 GetTabSortBoxes();
1799 SwTableBox* p = this; // error: &this
1800 rSrtArr.Insert( p ); // eintragen
1803 SwTableBox::~SwTableBox()
1805 // Inhaltstragende Box ?
1806 if( !GetFrmFmt()->GetDoc()->IsInDtor() && pSttNd )
1808 // an der Table austragen
1809 const SwTableNode* pTblNd = pSttNd->FindTableNode();
1810 ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1811 SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1812 GetTabSortBoxes();
1813 SwTableBox *p = this; // error: &this
1814 rSrtArr.Remove( p ); // austragen
1817 // ist die TabelleBox der letzte Client im FrameFormat, kann dieses
1818 // geloescht werden
1819 SwModify* pMod = GetFrmFmt();
1820 pMod->Remove( this ); // austragen,
1821 if( !pMod->GetDepends() )
1822 delete pMod; // und loeschen
1824 delete pImpl;
1827 SwTableBoxFmt* SwTableBox::CheckBoxFmt( SwTableBoxFmt* pFmt )
1829 // sollte das Format eine Formel oder einen Value tragen, dann muss die
1830 // Box alleine am Format haengen. Ggfs. muss ein neues angelegt werden.
1831 if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, FALSE ) ||
1832 SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, FALSE ) )
1834 SwClient* pOther = SwClientIter( *pFmt ).First( TYPE( SwTableBox ));
1835 if( pOther )
1837 SwTableBoxFmt* pNewFmt = pFmt->GetDoc()->MakeTableBoxFmt();
1838 pNewFmt->LockModify();
1839 *pNewFmt = *pFmt;
1841 // Values und Formeln entfernen
1842 pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1843 pNewFmt->UnlockModify();
1845 pFmt = pNewFmt;
1848 return pFmt;
1851 /*************************************************************************
1853 |* SwTableBox::ClaimFrmFmt(), ChgFrmFmt()
1855 |* Ersterstellung MA 04. May. 93
1856 |* Letzte Aenderung MA 07. Feb. 96
1858 |*************************************************************************/
1859 SwFrmFmt* SwTableBox::ClaimFrmFmt()
1861 //Wenn noch andere TableBoxen ausser mir selbst an dem FrmFmt haengen,
1862 //sehe ich mich leider gezwungen mir ein eingenes zu machen und mich
1863 //bei diesem anzumelden.
1864 SwTableBoxFmt *pOld = (SwTableBoxFmt*)GetFrmFmt();
1865 SwClientIter aIter( *pOld );
1866 SwClient* pLast;
1868 for( pLast = aIter.First( TYPE( SwTableBox )); pLast && pLast == this;
1869 pLast = aIter.Next() )
1872 if( pLast )
1874 SwTableBoxFmt* pNewFmt = pOld->GetDoc()->MakeTableBoxFmt();
1876 pNewFmt->LockModify();
1877 *pNewFmt = *pOld;
1879 // Values und Formeln nie kopieren
1880 pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1881 pNewFmt->UnlockModify();
1883 //Erstmal die Frms ummelden.
1884 for( pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
1885 if( ((SwCellFrm*)pLast)->GetTabBox() == this )
1886 pNewFmt->Add( pLast );
1888 //Jetzt noch mich selbst ummelden.
1889 pNewFmt->Add( this );
1890 pOld = pNewFmt;
1892 return pOld;
1895 void SwTableBox::ChgFrmFmt( SwTableBoxFmt* pNewFmt )
1897 SwFrmFmt *pOld = GetFrmFmt();
1898 SwClientIter aIter( *pOld );
1899 SwClient* pLast;
1901 //Erstmal die Frms ummelden.
1902 for( pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
1904 SwCellFrm *pCell = (SwCellFrm*)pLast;
1905 if( pCell->GetTabBox() == this )
1907 pNewFmt->Add( pLast );
1908 pCell->InvalidateSize();
1909 pCell->_InvalidatePrt();
1910 pCell->SetCompletePaint();
1911 pCell->SetDerivedVert( FALSE );
1912 pCell->CheckDirChange();
1914 // --> FME 2005-04-15 #i47489#
1915 // make sure that the row will be formatted, in order
1916 // to have the correct Get(Top|Bottom)MarginForLowers values
1917 // set at the row.
1918 const SwTabFrm* pTab = pCell->FindTabFrm();
1919 if ( pTab && pTab->IsCollapsingBorders() )
1921 SwFrm* pRow = pCell->GetUpper();
1922 pRow->_InvalidateSize();
1923 pRow->_InvalidatePrt();
1925 // <--
1929 //Jetzt noch mich selbst ummelden.
1930 pNewFmt->Add( this );
1932 if( !aIter.GoStart() )
1933 delete pOld;
1936 /*************************************************************************
1938 |* String SwTableBox::GetName() const
1939 |* gebe den Namen dieser Box zurueck. Dieser wird dynamisch bestimmt
1940 |* und ergibt sich aus der Position in den Lines/Boxen/Tabelle
1942 |* Ersterstellung JP 30. Jun. 93
1943 |* Letzte Aenderung JP 30. Jun. 93
1945 |*************************************************************************/
1946 void lcl_GetTblBoxColStr( USHORT nCol, String& rNm )
1948 const USHORT coDiff = 52; // 'A'-'Z' 'a' - 'z'
1949 USHORT nCalc;
1951 do {
1952 nCalc = nCol % coDiff;
1953 if( nCalc >= 26 )
1954 rNm.Insert( sal_Unicode('a' - 26 + nCalc ), 0 );
1955 else
1956 rNm.Insert( sal_Unicode('A' + nCalc ), 0 );
1958 if( 0 == (nCol = nCol - nCalc) )
1959 break;
1960 nCol /= coDiff;
1961 --nCol;
1962 } while( 1 );
1965 String SwTableBox::GetName() const
1967 if( !pSttNd ) // keine Content Box ??
1969 // die naechste erste Box suchen ??
1970 return aEmptyStr;
1973 const SwTable& rTbl = pSttNd->FindTableNode()->GetTable();
1974 USHORT nPos;
1975 String sNm, sTmp;
1976 const SwTableBox* pBox = this;
1977 do {
1978 const SwTableBoxes* pBoxes = &pBox->GetUpper()->GetTabBoxes();
1979 const SwTableLine* pLine = pBox->GetUpper();
1980 // auf oberstere Ebene ?
1981 const SwTableLines* pLines = pLine->GetUpper()
1982 ? &pLine->GetUpper()->GetTabLines() : &rTbl.GetTabLines();
1984 sTmp = String::CreateFromInt32( nPos = pLines->GetPos( pLine ) + 1 );
1985 if( sNm.Len() )
1986 sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
1987 else
1988 sNm = sTmp;
1990 sTmp = String::CreateFromInt32(( nPos = pBoxes->GetPos( pBox )) + 1 );
1991 if( 0 != ( pBox = pLine->GetUpper()) )
1992 sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
1993 else
1994 ::lcl_GetTblBoxColStr( nPos, sNm );
1996 } while( pBox );
1997 return sNm;
2000 BOOL SwTableBox::IsInHeadline( const SwTable* pTbl ) const
2002 if( !GetUpper() ) // sollte nur beim Merge vorkommen.
2003 return FALSE;
2005 if( !pTbl )
2006 pTbl = &pSttNd->FindTableNode()->GetTable();
2008 const SwTableLine* pLine = GetUpper();
2009 while( pLine->GetUpper() )
2010 pLine = pLine->GetUpper()->GetUpper();
2012 // Headerline?
2013 return pTbl->GetTabLines()[ 0 ] == pLine;
2016 #ifndef PRODUCT
2018 ULONG SwTableBox::GetSttIdx() const
2020 return pSttNd ? pSttNd->GetIndex() : 0;
2022 #endif
2024 // erfrage vom Client Informationen
2025 BOOL SwTable::GetInfo( SfxPoolItem& rInfo ) const
2027 switch( rInfo.Which() )
2029 case RES_AUTOFMT_DOCNODE:
2031 const SwTableNode* pTblNode = GetTableNode();
2032 if( pTblNode && &pTblNode->GetNodes() == ((SwAutoFmtGetDocNode&)rInfo).pNodes )
2034 if ( aSortCntBoxes.Count() )
2036 SwNodeIndex aIdx( *aSortCntBoxes[ 0 ]->GetSttNd() );
2037 ((SwAutoFmtGetDocNode&)rInfo).pCntntNode =
2038 GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx );
2040 return FALSE;
2042 break;
2044 case RES_FINDNEARESTNODE:
2045 if( GetFrmFmt() && ((SwFmtPageDesc&)GetFrmFmt()->GetFmtAttr(
2046 RES_PAGEDESC )).GetPageDesc() &&
2047 aSortCntBoxes.Count() &&
2048 aSortCntBoxes[ 0 ]->GetSttNd()->GetNodes().IsDocNodes() )
2049 ((SwFindNearestNode&)rInfo).CheckNode( *
2050 aSortCntBoxes[ 0 ]->GetSttNd()->FindTableNode() );
2051 break;
2053 case RES_CONTENT_VISIBLE:
2055 ((SwPtrMsgPoolItem&)rInfo).pObject =
2056 SwClientIter( *GetFrmFmt() ).First( TYPE(SwFrm) );
2058 return FALSE;
2060 return TRUE;
2063 SwTable* SwTable::FindTable( SwFrmFmt* pFmt )
2065 return pFmt ? (SwTable*)SwClientIter( *pFmt ).First( TYPE(SwTable) ) : 0;
2068 SwTableNode* SwTable::GetTableNode() const
2070 return GetTabSortBoxes().Count() ?
2071 (SwTableNode*)GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode() :
2072 pTableNode;
2075 void SwTable::SetRefObject( SwServerObject* pObj )
2077 if( refObj.Is() )
2078 refObj->Closed();
2080 refObj = pObj;
2084 void SwTable::SetHTMLTableLayout( SwHTMLTableLayout *p )
2086 delete pHTMLLayout;
2087 pHTMLLayout = p;
2091 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
2092 BOOL bChgAlign )
2094 ULONG nNdPos = rBox.IsValidNumTxtNd( TRUE );
2095 if( ULONG_MAX != nNdPos )
2097 SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2098 SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2099 const SfxPoolItem* pItem;
2101 // Ausrichtung umsetzen
2102 if( bChgAlign )
2104 pItem = &pTNd->SwCntntNode::GetAttr( RES_PARATR_ADJUST );
2105 SvxAdjust eAdjust = ((SvxAdjustItem*)pItem)->GetAdjust();
2106 if( SVX_ADJUST_LEFT == eAdjust || SVX_ADJUST_BLOCK == eAdjust )
2108 SvxAdjustItem aAdjust( *(SvxAdjustItem*)pItem );
2109 aAdjust.SetAdjust( SVX_ADJUST_RIGHT );
2110 pTNd->SetAttr( aAdjust );
2114 // Farbe umsetzen oder "Benutzer Farbe" sichern
2115 if( !pTNd->GetpSwAttrSet() || SFX_ITEM_SET != pTNd->GetpSwAttrSet()->
2116 GetItemState( RES_CHRATR_COLOR, FALSE, &pItem ))
2117 pItem = 0;
2119 const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2120 const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2122 if( ( pNewUserColor && pOldNumFmtColor &&
2123 *pNewUserColor == *pOldNumFmtColor ) ||
2124 ( !pNewUserColor && !pOldNumFmtColor ))
2126 // User Color nicht veraendern aktuellen Werte setzen
2127 // ggfs. die alte NumFmtColor loeschen
2128 if( pCol )
2129 // ggfs. die Farbe setzen
2130 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2131 else if( pItem )
2133 pNewUserColor = rBox.GetSaveUserColor();
2134 if( pNewUserColor )
2135 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2136 else
2137 pTNd->ResetAttr( RES_CHRATR_COLOR );
2140 else
2142 // User Color merken, ggfs. die NumFormat Color setzen, aber
2143 // nie die Farbe zurueck setzen
2144 rBox.SetSaveUserColor( pNewUserColor );
2146 if( pCol )
2147 // ggfs. die Farbe setzen
2148 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2151 rBox.SetSaveNumFmtColor( pCol );
2153 if( pTNd->GetTxt() != rTxt )
2155 // Text austauschen
2156 //JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten!)
2157 const String& rOrig = pTNd->GetTxt();
2158 xub_StrLen n;
2160 for( n = 0; n < rOrig.Len() && '\x9' == rOrig.GetChar( n ); ++n )
2162 SwIndex aIdx( pTNd, n );
2163 for( n = rOrig.Len(); n && '\x9' == rOrig.GetChar( --n ); )
2165 n -= aIdx.GetIndex() - 1;
2167 //JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2168 // zuruecksetzen, damit sie wieder aufgespannt werden
2170 SwIndex aResetIdx( aIdx, n );
2171 pTNd->DontExpandFmt( aResetIdx, FALSE, FALSE );
2174 if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
2176 SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.Len());
2177 pDoc->DeleteRedline(aTemp, true, USHRT_MAX);
2180 pTNd->EraseText( aIdx, n,
2181 IDocumentContentOperations::INS_EMPTYEXPAND );
2182 pTNd->InsertText( rTxt, aIdx,
2183 IDocumentContentOperations::INS_EMPTYEXPAND );
2185 if( pDoc->IsRedlineOn() )
2187 SwPaM aTemp(*pTNd, 0, *pTNd, rTxt.Len());
2188 pDoc->AppendRedline(new SwRedline(nsRedlineType_t::REDLINE_INSERT, aTemp), true);
2192 // vertikale Ausrichtung umsetzen
2193 if( bChgAlign &&
2194 ( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(
2195 RES_VERT_ORIENT, TRUE, &pItem ) ||
2196 text::VertOrientation::TOP == ((SwFmtVertOrient*)pItem)->GetVertOrient() ))
2198 rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::BOTTOM ));
2203 void ChgNumToText( SwTableBox& rBox, ULONG nFmt )
2205 ULONG nNdPos = rBox.IsValidNumTxtNd( FALSE );
2206 if( ULONG_MAX != nNdPos )
2208 SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2209 SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2210 BOOL bChgAlign = pDoc->IsInsTblAlignNum();
2211 const SfxPoolItem* pItem;
2213 Color* pCol = 0;
2214 if( NUMBERFORMAT_TEXT != nFmt )
2216 // speziellen Textformat:
2217 String sTmp, sTxt( pTNd->GetTxt() );
2218 pDoc->GetNumberFormatter()->GetOutputString( sTxt, nFmt, sTmp, &pCol );
2219 if( sTxt != sTmp )
2221 // Text austauschen
2222 SwIndex aIdx( pTNd, sTxt.Len() );
2223 //JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2224 // zuruecksetzen, damit sie wieder aufgespannt werden
2225 pTNd->DontExpandFmt( aIdx, FALSE, FALSE );
2226 aIdx = 0;
2227 pTNd->EraseText( aIdx, STRING_LEN,
2228 IDocumentContentOperations::INS_EMPTYEXPAND );
2229 pTNd->InsertText( sTmp, aIdx,
2230 IDocumentContentOperations::INS_EMPTYEXPAND );
2234 const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
2236 // Ausrichtung umsetzen
2237 if( bChgAlign && pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState(
2238 RES_PARATR_ADJUST, FALSE, &pItem ) &&
2239 SVX_ADJUST_RIGHT == ((SvxAdjustItem*)pItem)->GetAdjust() )
2241 pTNd->SetAttr( SvxAdjustItem( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ) );
2244 // Farbe umsetzen oder "Benutzer Farbe" sichern
2245 if( !pAttrSet || SFX_ITEM_SET != pAttrSet->
2246 GetItemState( RES_CHRATR_COLOR, FALSE, &pItem ))
2247 pItem = 0;
2249 const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2250 const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2252 if( ( pNewUserColor && pOldNumFmtColor &&
2253 *pNewUserColor == *pOldNumFmtColor ) ||
2254 ( !pNewUserColor && !pOldNumFmtColor ))
2256 // User Color nicht veraendern aktuellen Werte setzen
2257 // ggfs. die alte NumFmtColor loeschen
2258 if( pCol )
2259 // ggfs. die Farbe setzen
2260 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2261 else if( pItem )
2263 pNewUserColor = rBox.GetSaveUserColor();
2264 if( pNewUserColor )
2265 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2266 else
2267 pTNd->ResetAttr( RES_CHRATR_COLOR );
2270 else
2272 // User Color merken, ggfs. die NumFormat Color setzen, aber
2273 // nie die Farbe zurueck setzen
2274 rBox.SetSaveUserColor( pNewUserColor );
2276 if( pCol )
2277 // ggfs. die Farbe setzen
2278 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2281 rBox.SetSaveNumFmtColor( pCol );
2284 // vertikale Ausrichtung umsetzen
2285 if( bChgAlign &&
2286 SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState(
2287 RES_VERT_ORIENT, FALSE, &pItem ) &&
2288 text::VertOrientation::BOTTOM == ((SwFmtVertOrient*)pItem)->GetVertOrient() )
2290 rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::TOP ));
2295 // zum Erkennen von Veraenderungen (haupts. TableBoxAttribute)
2296 void SwTableBoxFmt::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew )
2298 if( !IsModifyLocked() && !IsInDocDTOR() )
2300 const SwTblBoxNumFormat *pNewFmt = 0;
2301 const SwTblBoxFormula *pNewFml = 0;
2302 const SwTblBoxValue *pNewVal = 0;
2303 double aOldValue = 0;
2304 ULONG nOldFmt = NUMBERFORMAT_TEXT;
2306 switch( pNew ? pNew->Which() : 0 )
2308 case RES_ATTRSET_CHG:
2310 const SfxItemSet& rSet = *((SwAttrSetChg*)pNew)->GetChgSet();
2311 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT,
2312 FALSE, (const SfxPoolItem**)&pNewFmt ) )
2313 nOldFmt = ((SwTblBoxNumFormat&)((SwAttrSetChg*)pOld)->
2314 GetChgSet()->Get( RES_BOXATR_FORMAT )).GetValue();
2315 rSet.GetItemState( RES_BOXATR_FORMULA, FALSE,
2316 (const SfxPoolItem**)&pNewFml );
2317 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE,
2318 FALSE, (const SfxPoolItem**)&pNewVal ) )
2319 aOldValue = ((SwTblBoxValue&)((SwAttrSetChg*)pOld)->
2320 GetChgSet()->Get( RES_BOXATR_VALUE )).GetValue();
2322 break;
2324 case RES_BOXATR_FORMAT:
2325 pNewFmt = (SwTblBoxNumFormat*)pNew;
2326 nOldFmt = ((SwTblBoxNumFormat*)pOld)->GetValue();
2327 break;
2328 case RES_BOXATR_FORMULA:
2329 pNewFml = (SwTblBoxFormula*)pNew;
2330 break;
2331 case RES_BOXATR_VALUE:
2332 pNewVal = (SwTblBoxValue*)pNew;
2333 aOldValue = ((SwTblBoxValue*)pOld)->GetValue();
2334 break;
2337 // es hat sich etwas getan und im Set ist noch irgendein BoxAttribut
2338 // vorhanden!
2339 if( pNewFmt || pNewFml || pNewVal )
2341 GetDoc()->SetFieldsDirty(true, NULL, 0);
2343 if( SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMAT, FALSE ) ||
2344 SFX_ITEM_SET == GetItemState( RES_BOXATR_VALUE, FALSE ) ||
2345 SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMULA, FALSE ) )
2347 // die Box holen
2348 SwClientIter aIter( *this );
2349 SwTableBox* pBox = (SwTableBox*)aIter.First( TYPE( SwTableBox ) );
2350 if( pBox )
2352 ASSERT( !aIter.Next(), "keine Box oder mehrere am Format" );
2354 ULONG nNewFmt;
2355 if( pNewFmt )
2357 nNewFmt = pNewFmt->GetValue();
2358 // neu Formatieren
2359 // ist es neuer oder wurde der akt. entfernt?
2360 if( SFX_ITEM_SET != GetItemState( RES_BOXATR_VALUE, FALSE ))
2361 pNewFmt = 0;
2363 else
2365 // das akt. Item besorgen
2366 GetItemState( RES_BOXATR_FORMAT, FALSE,
2367 (const SfxPoolItem**)&pNewFmt );
2368 nOldFmt = GetTblBoxNumFmt().GetValue();
2369 nNewFmt = pNewFmt ? pNewFmt->GetValue() : nOldFmt;
2372 // ist es neuer oder wurde der akt. entfernt?
2373 if( pNewVal )
2375 if( NUMBERFORMAT_TEXT != nNewFmt )
2377 if( SFX_ITEM_SET == GetItemState(
2378 RES_BOXATR_VALUE, FALSE ))
2379 nOldFmt = NUMBERFORMAT_TEXT;
2380 else
2381 nNewFmt = NUMBERFORMAT_TEXT;
2383 else if( NUMBERFORMAT_TEXT == nNewFmt )
2384 nOldFmt = 0;
2387 // Logik:
2388 // ValueAenderung: -> "simuliere" eine FormatAenderung!
2389 // FormatAenderung:
2390 // Text -> !Text oder FormatAenderung:
2391 // - Ausrichtung auf RECHTS, wenn LINKS oder Blocksatz
2392 // - vertikale Ausrichtung auf UNTEN wenn OBEN oder nicht
2393 // gesetzt ist.
2394 // - Text ersetzen (Farbe?? neg. Zahlen ROT??)
2395 // !Text -> Text:
2396 // - Ausrichtung auf LINKS, wenn RECHTS
2397 // - vertikale Ausrichtung auf OEBN, wenn UNTEN gesetzt ist
2399 SvNumberFormatter* pNumFmtr = GetDoc()->GetNumberFormatter();
2400 BOOL bNewIsTxtFmt = pNumFmtr->IsTextFormat( nNewFmt ) ||
2401 NUMBERFORMAT_TEXT == nNewFmt;
2403 if( !bNewIsTxtFmt && nOldFmt != nNewFmt || pNewFml )
2405 BOOL bChgTxt = TRUE;
2406 double fVal = 0;
2407 if( !pNewVal && SFX_ITEM_SET != GetItemState(
2408 RES_BOXATR_VALUE, FALSE, (const SfxPoolItem**)&pNewVal ))
2410 // es wurde noch nie ein Wert gesetzt, dann versuche
2411 // doch mal den Inhalt auszuwerten
2412 ULONG nNdPos = pBox->IsValidNumTxtNd( TRUE );
2413 if( ULONG_MAX != nNdPos )
2415 sal_uInt32 nTmpFmtIdx = nNewFmt;
2416 String aTxt( GetDoc()->GetNodes()[ nNdPos ]
2417 ->GetTxtNode()->GetRedlineTxt());
2418 if( !aTxt.Len() )
2419 bChgTxt = FALSE;
2420 else
2422 //JP 15.09.98: Bug 55741 - Tabs beibehalten
2423 lcl_TabToBlankAtSttEnd( aTxt );
2425 // JP 22.04.98: Bug 49659 -
2426 // Sonderbehandlung fuer Prozent
2427 BOOL bIsNumFmt = FALSE;
2428 if( NUMBERFORMAT_PERCENT ==
2429 pNumFmtr->GetType( nNewFmt ))
2431 sal_uInt32 nTmpFmt = 0;
2432 if( pNumFmtr->IsNumberFormat(
2433 aTxt, nTmpFmt, fVal ))
2435 if( NUMBERFORMAT_NUMBER ==
2436 pNumFmtr->GetType( nTmpFmt ))
2437 aTxt += '%';
2439 bIsNumFmt = pNumFmtr->IsNumberFormat(
2440 aTxt, nTmpFmtIdx, fVal );
2443 else
2444 bIsNumFmt = pNumFmtr->IsNumberFormat(
2445 aTxt, nTmpFmtIdx, fVal );
2447 if( bIsNumFmt )
2449 // dann setze den Value direkt in den Set -
2450 // ohne Modify
2451 int bIsLockMod = IsModifyLocked();
2452 LockModify();
2453 SetFmtAttr( SwTblBoxValue( fVal ));
2454 if( !bIsLockMod )
2455 UnlockModify();
2460 else
2461 fVal = pNewVal->GetValue();
2463 // den Inhalt mit dem neuen Wert Formtieren und in den Absatz
2464 // schbreiben
2465 Color* pCol = 0;
2466 String sNewTxt;
2467 if( DBL_MAX == fVal )
2468 sNewTxt = ViewShell::GetShellRes()->aCalc_Error;
2469 else
2471 pNumFmtr->GetOutputString( fVal, nNewFmt, sNewTxt, &pCol );
2473 if( !bChgTxt )
2474 sNewTxt.Erase();
2477 // ueber alle Boxen
2478 ChgTextToNum( *pBox, sNewTxt, pCol,
2479 GetDoc()->IsInsTblAlignNum() );
2482 else if( bNewIsTxtFmt && nOldFmt != nNewFmt )
2484 // auf jedenfall muessen jetzt die Formeln/Values
2485 // geloescht werden!
2486 // LockModify();
2487 // ResetAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
2488 // UnlockModify();
2491 ChgNumToText( *pBox, nNewFmt );
2497 // Und die Basis-Klasse rufen
2498 SwFrmFmt::Modify( pOld, pNew );
2501 BOOL SwTableBox::HasNumCntnt( double& rNum, sal_uInt32& rFmtIndex,
2502 BOOL& rIsEmptyTxtNd ) const
2504 BOOL bRet = FALSE;
2505 ULONG nNdPos = IsValidNumTxtNd( TRUE );
2506 if( ULONG_MAX != nNdPos )
2508 String aTxt( pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->
2509 GetRedlineTxt() );
2510 //JP 15.09.98: Bug 55741 - Tabs beibehalten
2511 lcl_TabToBlankAtSttEnd( aTxt );
2512 rIsEmptyTxtNd = 0 == aTxt.Len();
2513 SvNumberFormatter* pNumFmtr = GetFrmFmt()->GetDoc()->GetNumberFormatter();
2515 const SfxPoolItem* pItem;
2516 if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
2517 FALSE, &pItem ))
2519 rFmtIndex = ((SwTblBoxNumFormat*)pItem)->GetValue();
2520 // JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
2521 if( !rIsEmptyTxtNd &&
2522 NUMBERFORMAT_PERCENT == pNumFmtr->GetType( rFmtIndex ))
2524 sal_uInt32 nTmpFmt = 0;
2525 if( pNumFmtr->IsNumberFormat( aTxt, nTmpFmt, rNum ) &&
2526 NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt ))
2527 aTxt += '%';
2530 else
2531 rFmtIndex = 0;
2533 bRet = pNumFmtr->IsNumberFormat( aTxt, rFmtIndex, rNum );
2536 // wie bekommt man aus dem neuen String den neuen Wert?
2537 // denn der Numberformater erkennt aus "123.--DM" kein Zahlenformat!
2538 if( !bRet && rFmtIndex && !pNumFmtr->IsTextFormat( rFmtIndex ) &&
2539 SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_VALUE,
2540 FALSE, &pItem ))
2542 Color* pCol;
2543 String sNewTxt;
2544 pNumFmtr->GetOutputString( ((SwTblBoxValue*)pItem)->GetValue(),
2545 rFmtIndex, sNewTxt, &pCol );
2546 bRet = aTxt == sNewTxt;
2550 else
2551 rIsEmptyTxtNd = FALSE;
2552 return bRet;
2555 BOOL SwTableBox::IsNumberChanged() const
2557 BOOL bRet = TRUE;
2559 if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA, FALSE ))
2561 const SwTblBoxNumFormat *pNumFmt;
2562 const SwTblBoxValue *pValue;
2564 if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_VALUE, FALSE,
2565 (const SfxPoolItem**)&pValue ))
2566 pValue = 0;
2567 if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, FALSE,
2568 (const SfxPoolItem**)&pNumFmt ))
2569 pNumFmt = 0;
2571 ULONG nNdPos;
2572 if( pNumFmt && pValue &&
2573 ULONG_MAX != ( nNdPos = IsValidNumTxtNd( TRUE ) ) )
2575 String sNewTxt, sOldTxt( pSttNd->GetNodes()[ nNdPos ]->
2576 GetTxtNode()->GetRedlineTxt() );
2577 lcl_DelTabsAtSttEnd( sOldTxt );
2579 Color* pCol = 0;
2580 GetFrmFmt()->GetDoc()->GetNumberFormatter()->GetOutputString(
2581 pValue->GetValue(), pNumFmt->GetValue(), sNewTxt, &pCol );
2583 bRet = sNewTxt != sOldTxt ||
2584 !( ( !pCol && !GetSaveNumFmtColor() ) ||
2585 ( pCol && GetSaveNumFmtColor() &&
2586 *pCol == *GetSaveNumFmtColor() ));
2589 return bRet;
2592 ULONG SwTableBox::IsValidNumTxtNd( BOOL bCheckAttr ) const
2594 ULONG nPos = ULONG_MAX;
2595 if( pSttNd )
2597 SwNodeIndex aIdx( *pSttNd );
2598 ULONG nIndex = aIdx.GetIndex();
2599 const ULONG nIndexEnd = pSttNd->GetNodes()[ nIndex ]->EndOfSectionIndex();
2600 const SwTxtNode *pTextNode = 0;
2601 while( ++nIndex < nIndexEnd )
2603 const SwNode* pNode = pSttNd->GetNodes()[nIndex];
2604 if( pNode->IsTableNode() )
2605 { /*return ULONG_MAX if the cell contains a table(in table)*/
2606 pTextNode = 0;
2607 break;
2609 if( pNode->IsTxtNode() )
2611 if( pTextNode )
2612 { /*return ULONG_MAX if the cell contains complex paragraphs*/
2613 pTextNode = 0;
2614 break;
2616 else
2618 pTextNode = pNode->GetTxtNode();
2619 nPos = nIndex;
2623 if( pTextNode )
2625 if( bCheckAttr )
2627 const SwpHints* pHts = pTextNode->GetpSwpHints();
2628 const String& rTxt = pTextNode->GetTxt();
2629 // dann teste doch mal, ob das wirklich nur Text im Node steht!
2630 // Flys/Felder/..
2631 if( pHts )
2633 for( USHORT n = 0; n < pHts->Count(); ++n )
2635 const SwTxtAttr* pAttr = (*pHts)[ n ];
2636 if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() ||
2637 *pAttr->GetStart() ||
2638 *pAttr->GetAnyEnd() < rTxt.Len() )
2640 nPos = ULONG_MAX;
2641 break;
2647 else
2648 nPos = ULONG_MAX;
2650 return nPos;
2653 // ist das eine FormelBox oder eine Box mit numerischen Inhalt (AutoSum)
2654 USHORT SwTableBox::IsFormulaOrValueBox() const
2656 USHORT nWhich = 0;
2657 const SwTxtNode* pTNd;
2658 SwFrmFmt* pFmt = GetFrmFmt();
2659 if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, FALSE ))
2660 nWhich = RES_BOXATR_FORMULA;
2661 else if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, FALSE ) &&
2662 !pFmt->GetDoc()->GetNumberFormatter()->IsTextFormat(
2663 pFmt->GetTblBoxNumFmt().GetValue() ))
2664 nWhich = RES_BOXATR_VALUE;
2665 else if( pSttNd && pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex()
2666 && 0 != ( pTNd = pSttNd->GetNodes()[ pSttNd->GetIndex() + 1 ]
2667 ->GetTxtNode() ) && !pTNd->GetTxt().Len() )
2668 nWhich = USHRT_MAX;
2670 return nWhich;
2673 void SwTableBox::ActualiseValueBox()
2675 const SfxPoolItem *pFmtItem, *pValItem;
2676 SwFrmFmt* pFmt = GetFrmFmt();
2677 if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT, TRUE, &pFmtItem )
2678 && SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, TRUE, &pValItem ))
2680 const ULONG nFmtId = ((SwTblBoxNumFormat*)pFmtItem)->GetValue();
2681 ULONG nNdPos = ULONG_MAX;
2682 SvNumberFormatter* pNumFmtr = pFmt->GetDoc()->GetNumberFormatter();
2684 if( !pNumFmtr->IsTextFormat( nFmtId ) &&
2685 ULONG_MAX != (nNdPos = IsValidNumTxtNd( TRUE )) )
2687 double fVal = ((SwTblBoxValue*)pValItem)->GetValue();
2688 Color* pCol = 0;
2689 String sNewTxt;
2690 pNumFmtr->GetOutputString( fVal, nFmtId, sNewTxt, &pCol );
2692 const String& rTxt = pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->GetTxt();
2693 if( rTxt != sNewTxt )
2694 ChgTextToNum( *this, sNewTxt, pCol, FALSE );
2699 void SwTableBox_Impl::SetNewCol( Color** ppCol, const Color* pNewCol )
2701 if( *ppCol != pNewCol )
2703 delete *ppCol;
2704 if( pNewCol )
2705 *ppCol = new Color( *pNewCol );
2706 else
2707 *ppCol = 0;