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 #include "hintids.hxx"
27
28 //#define TEST_DELAYED_RESIZE
29
30 #ifdef TEST_DELAYED_RESIZE
31 #include <vcl/sound.hxx>
32 #endif
33 #include <vcl/wrkwin.hxx>
34 #include <vcl/svapp.hxx>
35 #include <sot/storage.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtfsize.hxx>
38 #include <frmfmt.hxx>
39 #include <docary.hxx>
40 #include "ndtxt.hxx"
41 #include "doc.hxx"
42 #include "swtable.hxx"
43 #include "rootfrm.hxx"
44 #include "docsh.hxx"
45 #include "flyfrm.hxx"
46 #include "poolfmt.hxx"
47 #include "viewsh.hxx"
48 #include "tabfrm.hxx"
49 #include "viewopt.hxx"
50 #include "htmltbl.hxx"
51 #include "ndindex.hxx"
52 #include "switerator.hxx"
53
54 using namespace ::com::sun::star;
55
56
57 #define COLFUZZY 20
58 #define MAX_TABWIDTH (USHRT_MAX - 2001)
59
60
61 class SwHTMLTableLayoutConstraints
62 {
63 sal_uInt16 nRow; // Start-Zeile
64 sal_uInt16 nCol; // Start-Spalte
65 sal_uInt16 nColSpan; // COLSPAN der Zelle
66
67 SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung
68
69 sal_uLong nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1
70
71 public:
72
73 SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
74 sal_uInt16 nCol, sal_uInt16 nColSp );
75 ~SwHTMLTableLayoutConstraints();
76
GetMinNoAlign() const77 sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
GetMaxNoAlign() const78 sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }
79
80 SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
GetNext() const81 SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
82
GetRow() const83 sal_uInt16 GetRow() const { return nRow; }
84
GetColSpan() const85 sal_uInt16 GetColSpan() const { return nColSpan; }
GetColumn() const86 sal_uInt16 GetColumn() const { return nCol; }
87 };
88
89 /* */
90
SwHTMLTableLayoutCnts(const SwStartNode * pSttNd,SwHTMLTableLayout * pTab,sal_Bool bNoBrTag,SwHTMLTableLayoutCnts * pNxt)91 SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
92 SwHTMLTableLayout* pTab,
93 sal_Bool bNoBrTag,
94 SwHTMLTableLayoutCnts* pNxt ) :
95 pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
96 nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
97 {}
98
~SwHTMLTableLayoutCnts()99 SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
100 {
101 delete pNext;
102 delete pTable;
103 }
104
GetStartNode() const105 const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
106 {
107 return pBox ? pBox->GetSttNd() : pStartNode;
108 }
109
110
111 /* */
112
SwHTMLTableLayoutCell(SwHTMLTableLayoutCnts * pCnts,sal_uInt16 nRSpan,sal_uInt16 nCSpan,sal_uInt16 nWidth,sal_Bool bPrcWidth,sal_Bool bNWrapOpt)113 SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
114 sal_uInt16 nRSpan, sal_uInt16 nCSpan,
115 sal_uInt16 nWidth, sal_Bool bPrcWidth,
116 sal_Bool bNWrapOpt ) :
117 pContents( pCnts ),
118 nRowSpan( nRSpan ), nColSpan( nCSpan ),
119 nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
120 bNoWrapOption( bNWrapOpt )
121 {}
122
~SwHTMLTableLayoutCell()123 SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
124 {
125 if( nRowSpan==1 && nColSpan==1 )
126 {
127 delete pContents;
128 }
129 }
130
131 /* */
132
SwHTMLTableLayoutColumn(sal_uInt16 nWidth,sal_Bool bRelWidth,sal_Bool bLBorder)133 SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
134 sal_Bool bRelWidth,
135 sal_Bool bLBorder ) :
136 nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
137 nMin(0), nMax(0),
138 nAbsColWidth(0), nRelColWidth(0),
139 nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
140 bLeftBorder( bLBorder )
141 {}
142
143
144 /* */
145
SwHTMLTableLayoutConstraints(sal_uLong nMin,sal_uLong nMax,sal_uInt16 nRw,sal_uInt16 nColumn,sal_uInt16 nColSp)146 SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
147 sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ):
148 nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
149 pNext( 0 ),
150 nMinNoAlign( nMin ), nMaxNoAlign( nMax )
151 {}
152
~SwHTMLTableLayoutConstraints()153 SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
154 {
155 delete pNext;
156 }
157
InsertNext(SwHTMLTableLayoutConstraints * pNxt)158 SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
159 SwHTMLTableLayoutConstraints *pNxt )
160 {
161 SwHTMLTableLayoutConstraints *pPrev = 0;
162 SwHTMLTableLayoutConstraints *pConstr = this;
163 while( pConstr )
164 {
165 if( pConstr->GetRow() > pNxt->GetRow() ||
166 pConstr->GetColumn() > pNxt->GetColumn() )
167 break;
168 pPrev = pConstr;
169 pConstr = pConstr->GetNext();
170 }
171
172 if( pPrev )
173 {
174 pNxt->pNext = pPrev->GetNext();
175 pPrev->pNext = pNxt;
176 pConstr = this;
177 }
178 else
179 {
180 pNxt->pNext = this;
181 pConstr = pNxt;
182 }
183
184 return pConstr;
185 }
186
187 /* */
188
189 typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
190 typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
191
SwHTMLTableLayout(const SwTable * pSwTbl,sal_uInt16 nRws,sal_uInt16 nCls,sal_Bool bColsOpt,sal_Bool bColTgs,sal_uInt16 nWdth,sal_Bool bPrcWdth,sal_uInt16 nBorderOpt,sal_uInt16 nCellPad,sal_uInt16 nCellSp,SvxAdjust eAdjust,sal_uInt16 nLMargin,sal_uInt16 nRMargin,sal_uInt16 nBWidth,sal_uInt16 nLeftBWidth,sal_uInt16 nRightBWidth,sal_uInt16 nInhLeftBWidth,sal_uInt16 nInhRightBWidth)192 SwHTMLTableLayout::SwHTMLTableLayout(
193 const SwTable * pSwTbl,
194 sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs,
195 sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt,
196 sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust,
197 sal_uInt16 nLMargin, sal_uInt16 nRMargin,
198 sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth,
199 sal_uInt16 nRightBWidth,
200 sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) :
201 aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
202 aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
203 pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
204 nMin( 0 ), nMax( 0 ),
205 nRows( nRws ), nCols( nCls ),
206 nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
207 nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
208 nRelLeftFill( 0 ), nRelRightFill( 0 ),
209 nRelTabWidth( 0 ), nWidthOption( nWdth ),
210 nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
211 nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
212 nInhLeftBorderWidth( nInhLeftBWidth ),
213 nInhRightBorderWidth( nInhRightBWidth ),
214 nBorderWidth( nBWidth ),
215 nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
216 nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
217 bColsOption( bColsOpt ), bColTags( bColTgs ),
218 bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ),
219 bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ),
220 bMustNotResize( sal_False ), bMustNotRecalc( sal_False )
221 {
222 aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
223 DelayedResize_Impl ) );
224 }
225
~SwHTMLTableLayout()226 SwHTMLTableLayout::~SwHTMLTableLayout()
227 {
228 sal_uInt16 i;
229
230 for( i = 0; i < nCols; i++ )
231 delete aColumns[i];
232 delete[] aColumns;
233
234 sal_uInt16 nCount = nRows*nCols;
235 for( i=0; i<nCount; i++ )
236 delete aCells[i];
237 delete[] aCells;
238 }
239
240 // Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet:
241 // Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING
242 // Innere Umrandung: CELLSPACING + CELLPADDING
243 // Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn
244 // bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird.
245 // MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden,
246 // und zwar auch dann, wenn wenn nur die gegenueberliegende Seite
247 // eine Umrandung hat.
GetLeftCellSpace(sal_uInt16 nCol,sal_uInt16 nColSpan,sal_Bool bSwBorders) const248 sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
249 sal_Bool bSwBorders ) const
250 {
251 sal_uInt16 nSpace = nCellSpacing + nCellPadding;
252
253 if( nCol == 0 )
254 {
255 nSpace = nSpace + nBorder;
256
257 if( bSwBorders && nSpace < nLeftBorderWidth )
258 nSpace = nLeftBorderWidth;
259 }
260 else if( bSwBorders )
261 {
262 if( GetColumn(nCol)->HasLeftBorder() )
263 {
264 if( nSpace < nBorderWidth )
265 nSpace = nBorderWidth;
266 }
267 else if( nCol+nColSpan == nCols && nRightBorderWidth &&
268 nSpace < MIN_BORDER_DIST )
269 {
270 ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
271 // Wenn die Gegenueberliegende Seite umrandet ist muessen
272 // wir zumindest den minimalen Abstand zum Inhalt
273 // beruecksichtigen. (Koennte man zusaetzlich auch an
274 // nCellPadding festmachen.)
275 nSpace = MIN_BORDER_DIST;
276 }
277 }
278
279 return nSpace;
280 }
281
GetRightCellSpace(sal_uInt16 nCol,sal_uInt16 nColSpan,sal_Bool bSwBorders) const282 sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
283 sal_Bool bSwBorders ) const
284 {
285 sal_uInt16 nSpace = nCellPadding;
286
287 if( nCol+nColSpan == nCols )
288 {
289 nSpace += nBorder + nCellSpacing;
290 if( bSwBorders && nSpace < nRightBorderWidth )
291 nSpace = nRightBorderWidth;
292 }
293 else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
294 nSpace < MIN_BORDER_DIST )
295 {
296 ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
297 // Wenn die Gegenueberliegende Seite umrandet ist muessen
298 // wir zumindest den minimalen Abstand zum Inhalt
299 // beruecksichtigen. (Koennte man zusaetzlich auch an
300 // nCellPadding festmachen.)
301 nSpace = MIN_BORDER_DIST;
302 }
303
304 return nSpace;
305 }
306
AddBorderWidth(sal_uLong & rMin,sal_uLong & rMax,sal_uLong & rAbsMin,sal_uInt16 nCol,sal_uInt16 nColSpan,sal_Bool bSwBorders) const307 void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
308 sal_uLong &rAbsMin,
309 sal_uInt16 nCol, sal_uInt16 nColSpan,
310 sal_Bool bSwBorders ) const
311 {
312 sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
313 GetRightCellSpace( nCol, nColSpan, bSwBorders );
314
315 rMin += nAdd;
316 rMax += nAdd;
317 rAbsMin += nAdd;
318 }
319
SetBoxWidth(SwTableBox * pBox,sal_uInt16 nCol,sal_uInt16 nColSpan) const320 void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
321 sal_uInt16 nColSpan ) const
322 {
323 SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
324
325 // die Breite der Box berechnen
326 SwTwips nFrmWidth = 0;
327 while( nColSpan-- )
328 nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
329
330 // und neu setzen
331
332 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
333 }
334
GetAvail(sal_uInt16 nCol,sal_uInt16 nColSpan,sal_uInt16 & rAbsAvail,sal_uInt16 & rRelAvail) const335 void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
336 sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
337 {
338 rAbsAvail = 0;
339 rRelAvail = 0;
340 for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
341 {
342 const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
343 rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
344 rRelAvail = rRelAvail + pColumn->GetRelColWidth();
345 }
346 }
347
GetBrowseWidthByVisArea(const SwDoc & rDoc)348 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
349 {
350 ViewShell *pVSh = 0;
351 rDoc.GetEditShell( &pVSh );
352 if( pVSh )
353 {
354 return (sal_uInt16)pVSh->GetBrowseWidth();
355 }
356
357 return 0;
358 }
359
GetBrowseWidth(const SwDoc & rDoc)360 sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
361 {
362 // Wenn ein Layout da ist, koennen wir die Breite dort herholen.
363 const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); //swmod 080218
364 if( pRootFrm )
365 {
366 const SwFrm *pPageFrm = pRootFrm->GetLower();
367 if( pPageFrm )
368 return (sal_uInt16)pPageFrm->Prt().Width();
369 }
370
371 // --> OD 2010-05-12 #i91658#
372 // Assertion removed which state that no browse width is available.
373 // Investigation reveals that all calls can handle the case that no browse
374 // width is provided.
375 return GetBrowseWidthByVisArea( rDoc );
376 // <--
377 }
378
GetBrowseWidthByTabFrm(const SwTabFrm & rTabFrm) const379 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
380 const SwTabFrm& rTabFrm ) const
381 {
382 SwTwips nWidth = 0;
383
384 const SwFrm *pUpper = rTabFrm.GetUpper();
385 if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
386 ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
387 {
388 // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist
389 // die Breite Ankers und nicht die Breite Rahmens von Bedeutung.
390 // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet.
391 const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
392 if( pAnchor->IsTxtFrm() )
393 nWidth = pAnchor->Frm().Width();
394 else
395 nWidth = pAnchor->Prt().Width();
396 }
397 else
398 {
399 nWidth = pUpper->Prt().Width();
400 }
401
402 SwTwips nUpperDummy = 0;
403 long nRightOffset = 0,
404 nLeftOffset = 0;
405 rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
406 nWidth -= (nLeftOffset + nRightOffset);
407
408 return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
409 }
410
GetBrowseWidthByTable(const SwDoc & rDoc) const411 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
412 {
413 sal_uInt16 nBrowseWidth = 0;
414 SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
415 if( pFrm )
416 {
417 nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
418 }
419 else
420 {
421 nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
422 }
423
424 return nBrowseWidth;
425 }
426
GetAnyBoxStartNode() const427 const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
428 {
429 const SwStartNode *pBoxSttNd;
430
431 const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
432 while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
433 {
434 ASSERT( pBox->GetTabLines().Count() > 0,
435 "Box ohne Start-Node und Lines" );
436 ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0,
437 "Line ohne Boxen" );
438 pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
439 }
440
441 return pBoxSttNd;
442 }
443
FindFlyFrmFmt() const444 SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
445 {
446 const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
447 ASSERT( pTblNd, "Kein Table-Node?" );
448 return pTblNd->GetFlyFmt();
449 }
450
lcl_GetMinMaxSize(sal_uLong & rMinNoAlignCnts,sal_uLong & rMaxNoAlignCnts,sal_uLong & rAbsMinNoAlignCnts,sal_Bool & rHR,SwTxtNode * pTxtNd,sal_uLong nIdx,sal_Bool bNoBreak)451 static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
452 sal_uLong& rAbsMinNoAlignCnts,
453 #ifdef FIX41370
454 sal_Bool& rHR,
455 #endif
456 SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak )
457 {
458 pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
459 rAbsMinNoAlignCnts );
460 ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
461 "GetMinMaxSize: absmin > min" );
462 ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts,
463 "GetMinMaxSize: max > min" );
464
465 //Bei einen <PRE>-Absatz entspricht die maximale Breite der
466 // minimalen breite
467 const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
468 while( pColl && !pColl->IsDefault() &&
469 (USER_FMT & pColl->GetPoolFmtId()) )
470 {
471 pColl = (const SwFmtColl *)pColl->DerivedFrom();
472 }
473
474 // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht
475 // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken.
476 if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
477 {
478 rMinNoAlignCnts = rMaxNoAlignCnts;
479 rAbsMinNoAlignCnts = rMaxNoAlignCnts;
480 }
481 #ifdef FIX41370
482 else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() )
483 {
484 rHR |= !pTxtNd->HasSwAttrSet() ||
485 SFX_ITEM_SET != pTxtNd->GetpSwAttrSet()
486 ->GetItemState( RES_LR_SPACE, sal_False );
487 }
488 #endif
489 }
490
AutoLayoutPass1()491 void SwHTMLTableLayout::AutoLayoutPass1()
492 {
493 nPass1Done++;
494
495 ClearPass1Info();
496
497 sal_Bool bFixRelWidths = sal_False;
498 sal_uInt16 i;
499
500 SwHTMLTableLayoutConstraints *pConstraints = 0;
501
502 for( i=0; i<nCols; i++ )
503 {
504 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
505 pColumn->ClearPass1Info( !HasColTags() );
506 sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir
507 // berechnete Breite bezieht
508 sal_uInt16 nColSkip = USHRT_MAX; // Wie viele Spalten muessen
509 // uebersprungen werden
510
511 for( sal_uInt16 j=0; j<nRows; j++ )
512 {
513 SwHTMLTableLayoutCell *pCell = GetCell(j,i);
514 SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
515
516 // fix #31488#: Zum Ermitteln der naechsten zu berechnenden
517 // Spalte muessen alle Zeilen herangezogen werden
518 sal_uInt16 nColSpan = pCell->GetColSpan();
519 if( nColSpan < nColSkip )
520 nColSkip = nColSpan;
521
522 if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
523 {
524 // die Zelle ist leer oder ihr Inhalt wurde nich nicht
525 // bearbeitet
526 if( nColSpan < nMinColSpan )
527 nMinColSpan = nColSpan;
528
529 sal_uLong nMinNoAlignCell = 0;
530 sal_uLong nMaxNoAlignCell = 0;
531 sal_uLong nAbsMinNoAlignCell = 0;
532 sal_uLong nMaxTableCell = 0;
533 sal_uLong nAbsMinTableCell = 0;
534 #ifdef FIX41370
535 sal_Bool bHR = sal_False;
536 #endif
537
538 while( pCnts )
539 {
540 const SwStartNode *pSttNd = pCnts->GetStartNode();
541 if( pSttNd )
542 {
543 const SwDoc *pDoc = pSttNd->GetDoc();
544 sal_uLong nIdx = pSttNd->GetIndex();
545 while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
546 {
547 SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
548 if( pTxtNd )
549 {
550 sal_uLong nMinNoAlignCnts = 0;
551 sal_uLong nMaxNoAlignCnts = 0;
552 sal_uLong nAbsMinNoAlignCnts = 0;
553
554 lcl_GetMinMaxSize( nMinNoAlignCnts,
555 nMaxNoAlignCnts,
556 nAbsMinNoAlignCnts,
557 #ifdef FIX41370
558 bHR,
559 #endif
560 pTxtNd, nIdx,
561 pCnts->HasNoBreakTag() );
562
563 if( nMinNoAlignCnts > nMinNoAlignCell )
564 nMinNoAlignCell = nMinNoAlignCnts;
565 if( nMaxNoAlignCnts > nMaxNoAlignCell )
566 nMaxNoAlignCell = nMaxNoAlignCnts;
567 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
568 nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
569 }
570 else
571 {
572 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
573 if( pTabNd )
574 {
575 SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
576 if( pChild )
577 {
578 pChild->AutoLayoutPass1();
579 sal_uLong nMaxTableCnts = pChild->nMax;
580 sal_uLong nAbsMinTableCnts = pChild->nMin;
581
582 // Eine feste Tabellen-Breite wird als Minimum
583 // und Maximum gleichzeitig uebernommen
584 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
585 {
586 sal_uLong nTabWidth = pChild->nWidthOption;
587 if( nTabWidth >= nAbsMinTableCnts )
588 {
589 nMaxTableCnts = nTabWidth;
590 nAbsMinTableCnts = nTabWidth;
591 }
592 else
593 {
594 nMaxTableCnts = nAbsMinTableCnts;
595 }
596 }
597
598 if( nMaxTableCnts > nMaxTableCell )
599 nMaxTableCell = nMaxTableCnts;
600 if( nAbsMinTableCnts > nAbsMinTableCell )
601 nAbsMinTableCell = nAbsMinTableCnts;
602 }
603 nIdx = pTabNd->EndOfSectionNode()->GetIndex();
604 }
605 }
606 nIdx++;
607 }
608 }
609 else
610 {
611 ASSERT( !this, "Sub tables in HTML import?" )
612 SwHTMLTableLayout *pChild = pCnts->GetTable();
613 pChild->AutoLayoutPass1();
614 sal_uLong nMaxTableCnts = pChild->nMax;
615 sal_uLong nAbsMinTableCnts = pChild->nMin;
616
617 // Eine feste Tabellen-Breite wird als Minimum
618 // und Maximum gleichzeitig uebernommen
619 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
620 {
621 sal_uLong nTabWidth = pChild->nWidthOption;
622 if( nTabWidth >= nAbsMinTableCnts )
623 {
624 nMaxTableCnts = nTabWidth;
625 nAbsMinTableCnts = nTabWidth;
626 }
627 else
628 {
629 nMaxTableCnts = nAbsMinTableCnts;
630 }
631 }
632
633 if( nMaxTableCnts > nMaxTableCell )
634 nMaxTableCell = nMaxTableCnts;
635 if( nAbsMinTableCnts > nAbsMinTableCell )
636 nAbsMinTableCell = nAbsMinTableCnts;
637 }
638 pCnts->SetPass1Done( nPass1Done );
639 pCnts = pCnts->GetNext();
640 }
641
642 // War frueher hinter AddBorderWidth
643 // Wenn die Breite einer Tabelle in der Zelle breiter ist als
644 // das, was wir fuer sonstigen Inhalt berechnet haben, mussen
645 // wir die Breite der Tabelle nutzen
646 if( nMaxTableCell > nMaxNoAlignCell )
647 nMaxNoAlignCell = nMaxTableCell;
648 if( nAbsMinTableCell > nAbsMinNoAlignCell )
649 {
650 nAbsMinNoAlignCell = nAbsMinTableCell;
651 if( nMinNoAlignCell < nAbsMinNoAlignCell )
652 nMinNoAlignCell = nAbsMinNoAlignCell;
653 if( nMaxNoAlignCell < nMinNoAlignCell )
654 nMaxNoAlignCell = nMinNoAlignCell;
655 }
656 // War frueher hinter AddBorderWidth
657
658 sal_Bool bRelWidth = pCell->IsPrcWidthOption();
659 sal_uInt16 nWidth = pCell->GetWidthOption();
660
661 // Eine NOWRAP-Option bezieht sich auf Text und auf
662 // Tabellen, wird aber bei fester Zellenbreite
663 // nicht uebernommen. Stattdessen wirkt die angegebene
664 // Zellenbreite wie eine Mindestbreite.
665 if( pCell->HasNoWrapOption() )
666 {
667 if( nWidth==0 || bRelWidth )
668 {
669 nMinNoAlignCell = nMaxNoAlignCell;
670 nAbsMinNoAlignCell = nMaxNoAlignCell;
671 }
672 else
673 {
674 if( nWidth>nMinNoAlignCell )
675 nMinNoAlignCell = nWidth;
676 if( nWidth>nAbsMinNoAlignCell )
677 nAbsMinNoAlignCell = nWidth;
678 }
679 }
680 #ifdef FIX41370
681 else if( bHR && nWidth>0 && !bRelWidth )
682 {
683 // Ein kleiner Hack, um einen Bug in Netscape 4.0
684 // nachzubilden (siehe #41370#). Wenn eine Zelle eine
685 // fixe Breite besitzt und gleichzeitig ein HR, wird
686 // sie nie schmaler als die angegebene Breite.
687 // (Genaugenomen scheint die Zelle nie schmaler zu werden
688 // als die HR-Linie, denn wenn man fuer die Linie eine
689 // Breite angibt, die breiter ist als die der Zelle, dann
690 // wird die Zelle so breit wie die Linie. Das bekommen wir
691 // natuerlich nicht hin.)
692 if( nWidth>nMinNoAlignCell )
693 nMinNoAlignCell = nWidth;
694 if( nWidth>nAbsMinNoAlignCell )
695 nAbsMinNoAlignCell = nWidth;
696 }
697 #endif
698
699 // Mindestbreite fuer Inhalt einhalten
700 if( nMinNoAlignCell < MINLAY )
701 nMinNoAlignCell = MINLAY;
702 if( nMaxNoAlignCell < MINLAY )
703 nMaxNoAlignCell = MINLAY;
704 if( nAbsMinNoAlignCell < MINLAY )
705 nAbsMinNoAlignCell = MINLAY;
706
707 // Umrandung und Abstand zum Inhalt beachten.
708 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
709 nAbsMinNoAlignCell, i, nColSpan );
710
711 if( 1==nColSpan )
712 {
713 // die Werte direkt uebernehmen
714 pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
715 nMaxNoAlignCell,
716 nAbsMinNoAlignCell );
717
718 // bei den WIDTH angaben gewinnt die breiteste
719 if( !HasColTags() )
720 pColumn->MergeCellWidthOption( nWidth, bRelWidth );
721 }
722 else
723 {
724 // die Angaben erst am Ende, und zwar zeilenweise von
725 // links nach rechts bearbeiten
726
727 // Wann welche Werte wie uebernommen werden ist weiter
728 // unten erklaert.
729 if( !HasColTags() && nWidth && !bRelWidth )
730 {
731 sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
732 AddBorderWidth( nAbsWidth, nDummy, nDummy2,
733 i, nColSpan, sal_False );
734
735 if( nAbsWidth >= nMinNoAlignCell )
736 {
737 nMaxNoAlignCell = nAbsWidth;
738 if( HasColsOption() )
739 nMinNoAlignCell = nAbsWidth;
740 }
741 else if( nAbsWidth >= nAbsMinNoAlignCell )
742 {
743 nMaxNoAlignCell = nAbsWidth;
744 nMinNoAlignCell = nAbsWidth;
745 }
746 else
747 {
748 nMaxNoAlignCell = nAbsMinNoAlignCell;
749 nMinNoAlignCell = nAbsMinNoAlignCell;
750 }
751 }
752 else if( HasColsOption() || HasColTags() )
753 nMinNoAlignCell = nAbsMinNoAlignCell;
754
755 SwHTMLTableLayoutConstraints *pConstr =
756 new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
757 nMaxNoAlignCell, j, i, nColSpan );
758 if( pConstraints )
759 pConstraints = pConstraints->InsertNext( pConstr );
760 else
761 pConstraints = pConstr;
762 }
763 }
764 }
765
766 ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
767 "Layout Pass 1: Da werden Spalten vergessen!" );
768 ASSERT( nMinColSpan!=USHRT_MAX,
769 "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" );
770
771 if( 1==nMinColSpan )
772 {
773 // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle
774 // Werte in pColumn
775
776 // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen:
777 //
778 // WIDTH: kein COLS COLS
779 //
780 // keine min = min min = absmin
781 // max = max max = max
782 //
783 // >= min min = min min = width
784 // max = width max = width
785 //
786 // >= absmin min = wdith(*) min = width
787 // max = width max = width
788 //
789 // < absmin min = absmin min = absmin
790 // max = absmin max = absmin
791 //
792 // (*) Netscape benutzt hier die Mindestbreite ohne einen
793 // Umbruch vor der letzten Grafik. Haben wir (noch?) nicht,
794 // also belassen wir es bei width.^
795
796 if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
797 {
798 // absolute Breiten als Minimal- und Maximalbreite
799 // uebernehmen.
800 sal_uLong nAbsWidth = pColumn->GetWidthOption();
801 sal_uLong nDummy = 0, nDummy2 = 0;
802 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False );
803
804 if( nAbsWidth >= pColumn->GetMinNoAlign() )
805 {
806 pColumn->SetMinMax( HasColsOption() ? nAbsWidth
807 : pColumn->GetMinNoAlign(),
808 nAbsWidth );
809 }
810 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
811 {
812 pColumn->SetMinMax( nAbsWidth, nAbsWidth );
813 }
814 else
815 {
816 pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
817 pColumn->GetAbsMinNoAlign() );
818 }
819 }
820 else
821 {
822 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
823 : pColumn->GetMinNoAlign(),
824 pColumn->GetMaxNoAlign() );
825 }
826 }
827 else if( USHRT_MAX!=nMinColSpan )
828 {
829 // kann irgendwas !=0 sein, weil es durch die Constraints
830 // angepasst wird.
831 pColumn->SetMinMax( MINLAY, MINLAY );
832
833 // die naechsten Spalten muessen nicht bearbeitet werden
834 i += (nColSkip-1);
835 }
836
837 nMin += pColumn->GetMin();
838 nMax += pColumn->GetMax();
839 bFixRelWidths |= pColumn->IsRelWidthOption();
840 }
841
842 // jetzt noch die Constrains verarbeiten
843 SwHTMLTableLayoutConstraints *pConstr = pConstraints;
844 while( pConstr )
845 {
846 // Erstmal muss die Breite analog zu den den Spaltenbreiten
847 // aufbereitet werden
848 sal_uInt16 nCol = pConstr->GetColumn();
849 sal_uInt16 nColSpan = pConstr->GetColSpan();
850 sal_uLong nConstrMin = pConstr->GetMinNoAlign();
851 sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
852
853 // jetzt holen wir uns die bisherige Breite der ueberspannten
854 // Spalten
855 sal_uLong nColsMin = 0;
856 sal_uLong nColsMax = 0;
857 for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
858 {
859 SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
860 nColsMin += pColumn->GetMin();
861 nColsMax += pColumn->GetMax();
862 }
863
864 if( nColsMin<nConstrMin )
865 {
866 // den Minimalwert anteilig auf die Spalten verteilen
867 sal_uLong nMinD = nConstrMin-nColsMin;
868
869 if( nConstrMin > nColsMax )
870 {
871 // Anteilig anhand der Mindestbreiten
872 sal_uInt16 nEndCol = nCol+nColSpan;
873 sal_uLong nDiff = nMinD;
874 for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
875 {
876 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
877
878 sal_uLong nColMin = pColumn->GetMin();
879 sal_uLong nColMax = pColumn->GetMax();
880
881 nMin -= nColMin;
882 sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
883 : nDiff;
884 nColMin += nAdd;
885 nMin += nColMin;
886 ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" );
887 nDiff -= nAdd;
888
889 if( nColMax < nColMin )
890 {
891 nMax -= nColMax;
892 nColsMax -= nColMax;
893 nColMax = nColMin;
894 nMax += nColMax;
895 nColsMax += nColMax;
896 }
897
898 pColumn->SetMinMax( nColMin, nColMax );
899 }
900 }
901 else
902 {
903 // Anteilig anhand der Differenz zwischen Max und Min
904 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
905 {
906 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
907
908 sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
909 if( nMinD < nDiff )
910 nDiff = nMinD;
911
912 pColumn->AddToMin( nDiff );
913
914 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
915 "Wieso ist die SPalte auf einmal zu schmal?" )
916
917 nMin += nDiff;
918 nMinD -= nDiff;
919 }
920 }
921 }
922
923 if( !HasColTags() && nColsMax<nConstrMax )
924 {
925 sal_uLong nMaxD = nConstrMax-nColsMax;
926
927 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
928 {
929 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
930
931 nMax -= pColumn->GetMax();
932
933 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
934
935 nMax += pColumn->GetMax();
936 }
937 }
938
939 pConstr = pConstr->GetNext();
940 }
941
942
943 if( bFixRelWidths )
944 {
945 if( HasColTags() )
946 {
947 // Zum Anpassen der relativen Breiten werden im 1. Schritt die
948 // Minmalbreiten aller anzupassenden Zellen jeweils mit der
949 // relativen Breite einer Spalte multipliziert. Dadurch stimmen
950 // dann die Breitenverhaeltnisse der Spalten untereinander.
951 // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch
952 // breiter gworden ist als die Minmalbreite.
953 // Im 2. Schritt werden dann die berechneten Breiten durch diesen
954 // Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle
955 // erhalten und dient als Ausgangsbasis fuer die andern Breiten.
956 // Es werden auch hier nur die Maximalbreiten beeinflusst!
957
958 sal_uLong nAbsMin = 0; // absolte Min-Breite alter Spalten mit
959 // relativer Breite
960 sal_uLong nRel = 0; // Summe der relativen Breiten aller Spalten
961 for( i=0; i<nCols; i++ )
962 {
963 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
964 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
965 {
966 nAbsMin += pColumn->GetMin();
967 nRel += pColumn->GetWidthOption();
968 }
969 }
970
971 sal_uLong nQuot = ULONG_MAX;
972 for( i=0; i<nCols; i++ )
973 {
974 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
975 if( pColumn->IsRelWidthOption() )
976 {
977 nMax -= pColumn->GetMax();
978 if( pColumn->GetWidthOption() && pColumn->GetMin() )
979 {
980 pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
981 sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
982 if( nColQuot<nQuot )
983 nQuot = nColQuot;
984 }
985 }
986 }
987 ASSERT( 0==nRel || nQuot!=ULONG_MAX,
988 "Wo sind die relativen Spalten geblieben?" );
989 for( i=0; i<nCols; i++ )
990 {
991 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
992 if( pColumn->IsRelWidthOption() )
993 {
994 if( pColumn->GetWidthOption() )
995 pColumn->SetMax( pColumn->GetMax() / nQuot );
996 else
997 pColumn->SetMax( pColumn->GetMin() );
998 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
999 "Maximale Spaltenbreite kleiner als Minimale" );
1000 nMax += pColumn->GetMax();
1001 }
1002 }
1003 }
1004 else
1005 {
1006 sal_uInt16 nRel = 0; // Summe der relativen Breiten aller Spalten
1007 sal_uInt16 nRelCols = 0; // Anzahl Spalten mit relativer Angabe
1008 sal_uLong nRelMax = 0; // Anteil am Maximum dieser Spalten
1009 for( i=0; i<nCols; i++ )
1010 {
1011 ASSERT( nRel<=100, "relative Breite aller Spalten>100%" );
1012 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1013 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1014 {
1015 // Sicherstellen, dass die relativen breiten nicht
1016 // ueber 100% landen
1017 sal_uInt16 nColWidth = pColumn->GetWidthOption();
1018 if( nRel+nColWidth > 100 )
1019 {
1020 nColWidth = 100 - nRel;
1021 pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
1022 }
1023 nRelMax += pColumn->GetMax();
1024 nRel = nRel + nColWidth;
1025 nRelCols++;
1026 }
1027 else if( !pColumn->GetMin() )
1028 {
1029 // Die Spalte ist leer (wurde also auschliesslich
1030 // durch COLSPAN erzeugt) und darf deshalb auch
1031 // keine %-Breite zugewiesen bekommen.
1032 nRelCols++;
1033 }
1034 }
1035
1036 // Eventuell noch vorhandene Prozente werden auf die Spalten ohne
1037 // eine Breiten-Angabe verteilt. Wie in Netscape werden die
1038 // verbleibenden Prozente enstprechend der Verhaeltnisse
1039 // der Maximalbreiten der in Frage kommenden Spalten
1040 // untereinander verteilt.
1041 // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten
1042 // mit fester Breite. Ist das richtig???
1043 if( nRel < 100 && nRelCols < nCols )
1044 {
1045 sal_uInt16 nRelLeft = 100 - nRel;
1046 sal_uLong nFixMax = nMax - nRelMax;
1047 for( i=0; i<nCols; i++ )
1048 {
1049 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1050 if( !pColumn->IsRelWidthOption() &&
1051 !pColumn->GetWidthOption() &&
1052 pColumn->GetMin() )
1053 {
1054 // den Rest bekommt die naechste Spalte
1055 sal_uInt16 nColWidth =
1056 (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
1057 pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
1058 }
1059 }
1060 }
1061
1062 // nun die Maximalbreiten entsprechend anpassen
1063 sal_uLong nQuotMax = ULONG_MAX;
1064 sal_uLong nOldMax = nMax;
1065 nMax = 0;
1066 for( i=0; i<nCols; i++ )
1067 {
1068 // Spalten mit %-Angaben werden enstprechend angepasst.
1069 // Spalten, die
1070 // - keine %-Angabe besitzen und in einer Tabelle mit COLS
1071 // oder WIDTH vorkommen, oder
1072 // - als Breite 0% angegeben haben erhalten die Minimalbreite
1073 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1074 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1075 {
1076 sal_uLong nNewMax;
1077 sal_uLong nColQuotMax;
1078 if( !nWidthOption )
1079 {
1080 nNewMax = nOldMax * pColumn->GetWidthOption();
1081 nColQuotMax = nNewMax / pColumn->GetMax();
1082 }
1083 else
1084 {
1085 nNewMax = nMin * pColumn->GetWidthOption();
1086 nColQuotMax = nNewMax / pColumn->GetMin();
1087 }
1088 pColumn->SetMax( nNewMax );
1089 if( nColQuotMax < nQuotMax )
1090 nQuotMax = nColQuotMax;
1091 }
1092 else if( HasColsOption() || nWidthOption ||
1093 (pColumn->IsRelWidthOption() &&
1094 !pColumn->GetWidthOption()) )
1095 pColumn->SetMax( pColumn->GetMin() );
1096 }
1097 // und durch den Quotienten teilen
1098 ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" );
1099 for( i=0; i<nCols; i++ )
1100 {
1101 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1102 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1103 {
1104 if( pColumn->GetWidthOption() )
1105 {
1106 pColumn->SetMax( pColumn->GetMax() / nQuotMax );
1107 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
1108 "Minimalbreite ein Spalte Groesser Maximum" );
1109 if( pColumn->GetMax() < pColumn->GetMin() )
1110 pColumn->SetMax( pColumn->GetMin() );
1111 }
1112 }
1113 nMax += pColumn->GetMax();
1114 }
1115 }
1116 }
1117
1118 delete pConstraints;
1119 }
1120
1121 // nAbsAvail ist der verfuegbare Platz in TWIPS.
1122 // nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0
1123 // nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle
1124 // fur die Umrandung und den Abstand zum Inhalt reserviert ist.
AutoLayoutPass2(sal_uInt16 nAbsAvail,sal_uInt16 nRelAvail,sal_uInt16 nAbsLeftSpace,sal_uInt16 nAbsRightSpace,sal_uInt16 nParentInhAbsSpace)1125 void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
1126 sal_uInt16 nAbsLeftSpace,
1127 sal_uInt16 nAbsRightSpace,
1128 sal_uInt16 nParentInhAbsSpace )
1129 {
1130 // Erstmal fuehren wie jede Menge Plausibilaets-Test durch
1131
1132 // Eine abolute zur Verfuegung stehende Breite muss immer uebergeben
1133 // werden.
1134 ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" );
1135
1136 // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer
1137 // Tabellen in Tabellen uebergeben
1138 ASSERT( IsTopTable() == (nRelAvail==0),
1139 "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" );
1140
1141 // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein
1142 // als das die Maximalbreite.
1143 ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" );
1144
1145 // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken.
1146 // (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung
1147 // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.)
1148 nLastResizeAbsAvail = nAbsAvail;
1149
1150 // Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender,
1151 // vorhandene Filler-Zellen und Abstande angepasst
1152
1153 // Abstand zum Inhalt und Unrandung
1154 sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
1155 if( !IsTopTable() &&
1156 GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
1157 {
1158 nAbsLeftFill = nAbsLeftSpace;
1159 nAbsRightFill = nAbsRightSpace;
1160 }
1161
1162 // Linker und rechter Abstand
1163 if( nLeftMargin || nRightMargin )
1164 {
1165 if( IsTopTable() )
1166 {
1167 // fuer die Top-Table beruecksichtigen wir die Raender immer,
1168 // den die Minimalbreite der Tabelle wird hier nie unterschritten
1169 nAbsAvail -= (nLeftMargin + nRightMargin);
1170 }
1171 else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
1172 {
1173 // sonst beruecksichtigen wir die Raender nur, wenn auch Platz
1174 // fuer sie da ist (nMin ist hier bereits berechnet!)
1175 nAbsLeftFill = nAbsLeftFill + nLeftMargin;
1176 nAbsRightFill = nAbsRightFill + nRightMargin;
1177 }
1178 }
1179
1180 // Filler-Zellen
1181 if( !IsTopTable() )
1182 {
1183 if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
1184 nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
1185 if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
1186 nAbsRightFill = MINLAY+nInhRightBorderWidth;
1187 }
1188
1189 // Anpassen des verfuegbaren Platzes.
1190 nRelLeftFill = 0;
1191 nRelRightFill = 0;
1192 if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
1193 {
1194 sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
1195
1196 nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
1197 nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);
1198
1199 nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
1200 if( nRelAvail )
1201 nRelAvail -= (nRelLeftFill + nRelRightFill);
1202 }
1203
1204
1205 // Schritt 2: Die absolute Tabellenbreite wird berechnet.
1206 sal_uInt16 nAbsTabWidth = 0;
1207 bUseRelWidth = sal_False;
1208 if( nWidthOption )
1209 {
1210 if( bPrcWidthOption )
1211 {
1212 ASSERT( nWidthOption<=100, "Prozentangabe zu gross" );
1213 if( nWidthOption > 100 )
1214 nWidthOption = 100;
1215
1216 // Die absolute Breite entspricht den angegeben Prozent der
1217 // zur Verfuegung stehenden Breite.
1218 // Top-Tabellen bekommen nur eine relative Breite, wenn der
1219 // verfuegbare Platz *echt groesser* ist als die Minimalbreite.
1220 // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel
1221 // von einer relativen Breite zu einer absoluten Breite durch
1222 // Resize sonst zu einer Endlosschleife fuehrt.
1223 // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird,
1224 // wenn der Rahmen eine nicht-relative Breite besitzt, koennen
1225 // wir da solche Spielchen nicht spielen
1226 // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen
1227 // jetzt doch. Dort war eine Grafik in einer 1%-breiten
1228 // Tabelle und hat da natuerlich nicht hineingepasst.
1229 nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
1230 if( IsTopTable() &&
1231 ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
1232 {
1233 nRelAvail = USHRT_MAX;
1234 bUseRelWidth = sal_True;
1235 }
1236 }
1237 else
1238 {
1239 nAbsTabWidth = nWidthOption;
1240 if( nAbsTabWidth > MAX_TABWIDTH )
1241 nAbsTabWidth = MAX_TABWIDTH;
1242
1243 // Tabellen in Tabellen duerfen niemals breiter werden als der
1244 // verfuegbare Platz.
1245 if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
1246 nAbsTabWidth = nAbsAvail;
1247 }
1248 }
1249
1250 ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail,
1251 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" );
1252 ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail,
1253 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" );
1254
1255 // Catch fuer die beiden Asserts von oben (man weiss ja nie!)
1256 if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
1257 nAbsTabWidth = nAbsAvail;
1258
1259
1260 // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der
1261 // absoluten und relativen Tabellenbreiten.
1262 if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
1263 nMin > MAX_TABWIDTH )
1264 {
1265 // Wenn
1266 // - das Minumum einer inneren Tabelle groesser ist als der
1267 // verfuegbare Platz, oder
1268 // - das Minumum einer Top-Table groesser ist als USHRT_MAX
1269 // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX
1270 // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten
1271 // untereinander erhalten.
1272
1273 nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
1274 nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
1275
1276 // First of all, we check wether we can fit the layout constrains,
1277 // that are: Every cell's width excluding the borders must be at least
1278 // MINLAY:
1279
1280 sal_uLong nRealMin = 0;
1281 for( sal_uInt16 i=0; i<nCols; i++ )
1282 {
1283 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1284 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1285 nRealMin += nRealColMin;
1286 }
1287 if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
1288 {
1289 // "Nichts geht mehr". We cannot get the minimum column widths
1290 // the layout wants to have.
1291
1292 sal_uInt16 nAbs = 0, nRel = 0;
1293 SwHTMLTableLayoutColumn *pColumn;
1294 for( sal_uInt16 i=0; i<nCols-1; i++ )
1295 {
1296 pColumn = GetColumn( i );
1297 sal_uLong nColMin = pColumn->GetMin();
1298 if( nColMin <= USHRT_MAX )
1299 {
1300 pColumn->SetAbsColWidth(
1301 (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
1302 pColumn->SetRelColWidth(
1303 (sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
1304 }
1305 else
1306 {
1307 double nColMinD = nColMin;
1308 pColumn->SetAbsColWidth(
1309 (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
1310 pColumn->SetRelColWidth(
1311 (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
1312 }
1313
1314 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1315 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1316 }
1317 pColumn = GetColumn( nCols-1 );
1318 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1319 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1320 }
1321 else
1322 {
1323 sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
1324 sal_uLong nDistRel = nRelTabWidth - nRealMin;
1325 sal_uLong nDistMin = nMin - nRealMin;
1326 sal_uInt16 nAbs = 0, nRel = 0;
1327 SwHTMLTableLayoutColumn *pColumn;
1328 for( sal_uInt16 i=0; i<nCols-1; i++ )
1329 {
1330 pColumn = GetColumn( i );
1331 sal_uLong nColMin = pColumn->GetMin();
1332 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1333 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1334
1335 if( nColMin <= USHRT_MAX )
1336 {
1337 pColumn->SetAbsColWidth(
1338 (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1339 pColumn->SetRelColWidth(
1340 (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1341 }
1342 else
1343 {
1344 double nColMinD = nColMin;
1345 pColumn->SetAbsColWidth(
1346 (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1347 pColumn->SetRelColWidth(
1348 (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1349 }
1350
1351 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1352 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1353 }
1354 pColumn = GetColumn( nCols-1 );
1355 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1356 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1357 }
1358 }
1359 else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
1360 {
1361 // Wenn
1362 // - die Tabelle eine fixe Breite besitzt und das Maximum der
1363 // Tabelle kleiner ist, oder
1364 // - das Maximum kleiner ist als der verfuegbare Platz
1365 // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur
1366 // unter Beruecksichtigung des Maxumums an die fixe Breite
1367 // angepasst werden.
1368
1369 // Keine fixe Breite, dann das Maximum nehmen.
1370 if( !nAbsTabWidth )
1371 nAbsTabWidth = (sal_uInt16)nMax;
1372
1373 // Eine Top-Table darf auch beriter werden als der verfuegbare Platz.
1374 if( nAbsTabWidth > nAbsAvail )
1375 {
1376 ASSERT( IsTopTable(),
1377 "Tabelle in Tabelle soll breiter werden als umgebende Zelle" );
1378 nAbsAvail = nAbsTabWidth;
1379 }
1380
1381 // Nur den Anteil der relativen Breite verwenden, der auch fuer
1382 // die absolute Breite verwendet wuerde.
1383 sal_uLong nAbsTabWidthL = nAbsTabWidth;
1384 nRelTabWidth =
1385 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1386 : nAbsTabWidth );
1387
1388 // Gibt es Spalten mit und Spalten ohne %-Angabe?
1389 sal_uLong nFixMax = nMax;
1390 for( sal_uInt16 i=0; i<nCols; i++ )
1391 {
1392 const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1393 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
1394 nFixMax -= pColumn->GetMax();
1395 }
1396
1397 if( nFixMax > 0 && nFixMax < nMax )
1398 {
1399 // ja, dann den zu verteilenden Platz nur auf die Spalten
1400 // mit %-Angabe verteilen.
1401
1402 // In diesem (und nur in diesem) Fall gibt es Spalten,
1403 // die ihre Maximalbreite genau einhalten, also weder
1404 // schmaler noch breiter werden. Beim zurueckrechnen der
1405 // absoluten Breite aus der relativen Breite kann es
1406 // zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen
1407 // werden zuerst die fixen Breiten entsprechend korrigiert
1408 // eingestellt und erst danach die relativen.
1409
1410 sal_uInt16 nAbs = 0, nRel = 0;
1411 sal_uInt16 nFixedCols = 0;
1412 sal_uInt16 i;
1413
1414 for( i = 0; i < nCols; i++ )
1415 {
1416 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1417 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
1418 {
1419 // Die Spalte behaelt ihre Breite bei.
1420 nFixedCols++;
1421 sal_uLong nColMax = pColumn->GetMax();
1422 pColumn->SetAbsColWidth( (sal_uInt16)nColMax );
1423
1424 sal_uLong nRelColWidth =
1425 (nColMax * nRelTabWidth) / nAbsTabWidth;
1426 sal_uLong nChkWidth =
1427 (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
1428 if( nChkWidth < nColMax )
1429 nRelColWidth++;
1430 else if( nChkWidth > nColMax )
1431 nRelColWidth--;
1432 pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );
1433
1434 nAbs = nAbs + (sal_uInt16)nColMax;
1435 nRel = nRel + (sal_uInt16)nRelColWidth;
1436 }
1437 }
1438
1439 // Zu verteilende Anteile des Maximums und der relativen und
1440 // absoluten Breiten. nFixMax entspricht an dieser Stelle
1441 // nAbs, so dass man gleich nFixMax haette nehmen koennen.
1442 // Der Code ist so aber verstaendlicher.
1443 ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" )
1444 sal_uLong nDistMax = nMax - nFixMax;
1445 sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
1446 sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;
1447
1448 for( i=0; i<nCols; i++ )
1449 {
1450 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1451 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
1452 {
1453 // Die Spalte wird anteilig breiter.
1454 nFixedCols++;
1455 if( nFixedCols == nCols )
1456 {
1457 pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
1458 pColumn->SetRelColWidth( nRelTabWidth-nRel );
1459 }
1460 else
1461 {
1462 sal_uLong nColMax = pColumn->GetMax();
1463 pColumn->SetAbsColWidth(
1464 (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
1465 pColumn->SetRelColWidth(
1466 (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
1467 }
1468 nAbs = nAbs + pColumn->GetAbsColWidth();
1469 nRel = nRel + pColumn->GetRelColWidth();
1470 }
1471 }
1472 ASSERT( nCols==nFixedCols, "Spalte vergessen!" );
1473 }
1474 else
1475 {
1476 // nein, dann den zu verteilenden Platz auf alle Spalten
1477 // gleichmaessig vertilen.
1478 for( sal_uInt16 i=0; i<nCols; i++ )
1479 {
1480 sal_uLong nColMax = GetColumn( i )->GetMax();
1481 GetColumn( i )->SetAbsColWidth(
1482 (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
1483 GetColumn( i )->SetRelColWidth(
1484 (sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
1485 }
1486 }
1487 }
1488 else
1489 {
1490 // den ueber die Minimalbreite herausgehenden Platz entsprechend
1491 // den einzelnen Spalten anteilig zuschlagen
1492 if( !nAbsTabWidth )
1493 nAbsTabWidth = nAbsAvail;
1494 if( nAbsTabWidth < nMin )
1495 nAbsTabWidth = (sal_uInt16)nMin;
1496
1497 if( nAbsTabWidth > nAbsAvail )
1498 {
1499 ASSERT( IsTopTable(),
1500 "Tabelle in Tabelle soll breiter werden als Platz da ist" );
1501 nAbsAvail = nAbsTabWidth;
1502 }
1503
1504 sal_uLong nAbsTabWidthL = nAbsTabWidth;
1505 nRelTabWidth =
1506 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1507 : nAbsTabWidth );
1508 double nW = nAbsTabWidth - nMin;
1509 double nD = (nMax==nMin ? 1 : nMax-nMin);
1510 sal_uInt16 nAbs = 0, nRel = 0;
1511 for( sal_uInt16 i=0; i<nCols-1; i++ )
1512 {
1513 double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
1514 sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
1515 sal_uLong nRelColWidth = nRelAvail
1516 ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
1517 : nAbsColWidth;
1518
1519 GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
1520 GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
1521 nAbs = nAbs + (sal_uInt16)nAbsColWidth;
1522 nRel = nRel + (sal_uInt16)nRelColWidth;
1523 }
1524 GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
1525 GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
1526
1527 }
1528
1529 // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts
1530 // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet.
1531 nInhAbsLeftSpace = 0;
1532 nInhAbsRightSpace = 0;
1533 if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
1534 nAbsTabWidth<nAbsAvail) )
1535 {
1536 // Die Breite von zusaetzlichen Zellen zur Ausrichtung der
1537 // inneren Tabelle bestimmen
1538 sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
1539 sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
1540 sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
1541
1542 // Groesse und Position der zusaetzlichen Zellen bestimmen
1543 switch( eTableAdjust )
1544 {
1545 case SVX_ADJUST_RIGHT:
1546 nAbsLeftFill = nAbsLeftFill + nAbsDist;
1547 nRelLeftFill = nRelLeftFill + nRelDist;
1548 nParentInhAbsLeftSpace = nParentInhAbsSpace;
1549 break;
1550 case SVX_ADJUST_CENTER:
1551 {
1552 sal_uInt16 nAbsLeftDist = nAbsDist / 2;
1553 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
1554 nAbsRightFill += nAbsDist - nAbsLeftDist;
1555 sal_uInt16 nRelLeftDist = nRelDist / 2;
1556 nRelLeftFill = nRelLeftFill + nRelLeftDist;
1557 nRelRightFill += nRelDist - nRelLeftDist;
1558 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
1559 nParentInhAbsRightSpace = nParentInhAbsSpace -
1560 nParentInhAbsLeftSpace;
1561 }
1562 break;
1563 case SVX_ADJUST_LEFT:
1564 default:
1565 nAbsRightFill = nAbsRightFill + nAbsDist;
1566 nRelRightFill = nRelRightFill + nRelDist;
1567 nParentInhAbsRightSpace = nParentInhAbsSpace;
1568 break;
1569 }
1570
1571 ASSERT( !pLeftFillerBox || nRelLeftFill>0,
1572 "Fuer linke Filler-Box ist keine Breite da!" );
1573 ASSERT( !pRightFillerBox || nRelRightFill>0,
1574 "Fuer rechte Filler-Box ist keine Breite da!" );
1575
1576 // Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn
1577 // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0)
1578 // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und
1579 // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir
1580 // die Tabelle wahrscheinlich selbst exportiert)
1581 if( nRelLeftFill && !pLeftFillerBox &&
1582 ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
1583 (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
1584 // (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) )
1585 {
1586 SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
1587 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
1588 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
1589 nRelLeftFill = 0;
1590 nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
1591 }
1592 if( nRelRightFill && !pRightFillerBox &&
1593 ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
1594 (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
1595 // (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) )
1596 {
1597 SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
1598 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
1599 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
1600 nRelRightFill = 0;
1601 nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
1602 }
1603 }
1604 }
1605
1606 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara );
1607
lcl_ResizeBox(const SwTableBox * & rpBox,void * pPara)1608 static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara )
1609 {
1610 sal_uInt16 *pWidth = (sal_uInt16 *)pPara;
1611
1612 if( !rpBox->GetSttNd() )
1613 {
1614 sal_uInt16 nWidth = 0;
1615 ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth );
1616 rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1617 *pWidth = *pWidth + nWidth;
1618 }
1619 else
1620 {
1621 *pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
1622 }
1623
1624 return sal_True;
1625 }
1626
lcl_ResizeLine(const SwTableLine * & rpLine,void * pPara)1627 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara )
1628 {
1629 sal_uInt16 *pWidth = (sal_uInt16 *)pPara;
1630 #ifdef DBG_UTIL
1631 sal_uInt16 nOldWidth = *pWidth;
1632 #endif
1633 *pWidth = 0;
1634 ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth );
1635
1636 #ifdef DBG_UTIL
1637 ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
1638 "Zeilen einer Box sind unterschiedlich lang" );
1639 #endif
1640
1641 return sal_True;
1642 }
1643
SetWidths(sal_Bool bCallPass2,sal_uInt16 nAbsAvail,sal_uInt16 nRelAvail,sal_uInt16 nAbsLeftSpace,sal_uInt16 nAbsRightSpace,sal_uInt16 nParentInhAbsSpace)1644 void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail,
1645 sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
1646 sal_uInt16 nAbsRightSpace,
1647 sal_uInt16 nParentInhAbsSpace )
1648 {
1649 // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen
1650 // worden sein.
1651 nWidthSet++;
1652
1653 // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus
1654 // aufgerufen.
1655 if( bCallPass2 )
1656 AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
1657 nParentInhAbsSpace );
1658
1659 // Schritt 1: Setzten der neuen Breite an allen Content-Boxen.
1660 // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird
1661 // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen
1662 // in Tabellen wird rekursiv SetWidth aufgerufen.
1663 for( sal_uInt16 i=0; i<nRows; i++ )
1664 {
1665 for( sal_uInt16 j=0; j<nCols; j++ )
1666 {
1667 SwHTMLTableLayoutCell *pCell = GetCell( i, j );
1668
1669 SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
1670 while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
1671 {
1672 SwTableBox *pBox = pCntnts->GetTableBox();
1673 if( pBox )
1674 {
1675 SetBoxWidth( pBox, j, pCell->GetColSpan() );
1676 }
1677 else
1678 {
1679 sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
1680 nInhSpace = 0;
1681 if( bCallPass2 )
1682 {
1683 sal_uInt16 nColSpan = pCell->GetColSpan();
1684 GetAvail( j, nColSpan, nAbs, nRel );
1685 nLSpace = GetLeftCellSpace( j, nColSpan );
1686 nRSpace = GetRightCellSpace( j, nColSpan );
1687 nInhSpace = GetInhCellSpace( j, nColSpan );
1688 }
1689 pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
1690 nLSpace, nRSpace,
1691 nInhSpace );
1692 }
1693
1694 pCntnts->SetWidthSet( nWidthSet );
1695 pCntnts = pCntnts->GetNext();
1696 }
1697 }
1698 }
1699
1700 // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate
1701 // der Nicht-Content-Boxen angepasst. Da diese aufgrund der
1702 // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen
1703 // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch
1704 // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden
1705 // stattdessen die Breiten der Filler-Zellen gesetzt.
1706 if( IsTopTable() )
1707 {
1708 sal_uInt16 nCalcTabWidth = 0;
1709 ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine,
1710 &nCalcTabWidth );
1711 ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
1712 "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." );
1713
1714 // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst
1715 // die Boxformate erneut angepasst werden. Ausserdem muss eine
1716 // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben.
1717 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
1718 ((SwTable *)pSwTable)->LockModify();
1719 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
1720 aFrmSize.SetWidth( nRelTabWidth );
1721 sal_Bool bRel = bUseRelWidth &&
1722 text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
1723 aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
1724 pFrmFmt->SetFmtAttr( aFrmSize );
1725 ((SwTable *)pSwTable)->UnlockModify();
1726
1727 // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen
1728 // breite angepasst werden.
1729 if( MayBeInFlyFrame() )
1730 {
1731 SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
1732 if( pFlyFrmFmt )
1733 {
1734 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
1735
1736 if( bUseRelWidth )
1737 {
1738 // Bei %-Angaben wird die Breite auf das Minimum gesetzt.
1739 aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX
1740 : nMin );
1741 aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
1742 }
1743 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
1744 }
1745 }
1746
1747 #ifdef DBG_UTIL
1748 {
1749 // steht im tblrwcl.cxx
1750 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1751
1752 // checke doch mal ob die Tabellen korrekte Breiten haben
1753 SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
1754 const SwTableLines& rLines = pSwTable->GetTabLines();
1755 for( sal_uInt16 n = 0; n < rLines.Count(); ++n )
1756 _CheckBoxWidth( *rLines[ n ], nSize );
1757 }
1758 #endif
1759
1760 }
1761 else
1762 {
1763 if( pLeftFillerBox )
1764 {
1765 pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
1766 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
1767 }
1768 if( pRightFillerBox )
1769 {
1770 pRightFillerBox->GetFrmFmt()->SetFmtAttr(
1771 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
1772 }
1773 }
1774 }
1775
_Resize(sal_uInt16 nAbsAvail,sal_Bool bRecalc)1776 void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1777 {
1778 // Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas
1779 // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt
1780 // werden.
1781 if( bRecalc )
1782 AutoLayoutPass1();
1783
1784 SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout();
1785 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1786 pRoot->StartAllAction(); //swmod 071108//swmod 071225
1787
1788 // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils
1789 // noch der Pass 2 laufen muss.
1790 SetWidths( sal_True, nAbsAvail );
1791
1792 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1793 pRoot->EndAllAction( sal_True ); //True per VirDev (Browsen ruhiger) //swmod 071108//swmod 071225
1794 }
1795
IMPL_STATIC_LINK(SwHTMLTableLayout,DelayedResize_Impl,void *,EMPTYARG)1796 IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
1797 {
1798 #ifdef TEST_DELAYED_RESIZE
1799 Sound::Beep( SOUND_WARNING );
1800 #endif
1801 pThis->aResizeTimer.Stop();
1802 pThis->_Resize( pThis->nDelayedResizeAbsAvail,
1803 pThis->bDelayedResizeRecalc );
1804
1805 return 0;
1806 }
1807
1808
Resize(sal_uInt16 nAbsAvail,sal_Bool bRecalc,sal_Bool bForce,sal_uLong nDelay)1809 sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc,
1810 sal_Bool bForce, sal_uLong nDelay )
1811 {
1812 if( 0 == nAbsAvail )
1813 return sal_False;
1814 ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" );
1815
1816 // Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem?
1817 if( bMustNotResize && !bForce )
1818 return sal_False;
1819
1820 // Darf ein Recalc der Tabelle durchgefuehrt werden?
1821 if( bMustNotRecalc && !bForce )
1822 bRecalc = sal_False;
1823
1824 const SwDoc *pDoc = GetDoc();
1825
1826 // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames
1827 // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen
1828 // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden,
1829 // weil sond die Umschaltung von relativ nach absolut nicht funktioniert.
1830 if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
1831 {
1832 const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
1833 if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
1834 nAbsAvail = nVisAreaWidth;
1835 }
1836
1837 if( nDelay==0 && aResizeTimer.IsActive() )
1838 {
1839 // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones
1840 // Resize aussteht, dann werden nur die neuen Werte uebernommen.
1841
1842 bRecalc |= bDelayedResizeRecalc;
1843 nDelayedResizeAbsAvail = nAbsAvail;
1844 return sal_False;
1845 }
1846
1847 // Optimierung:
1848 // Wenn die Minima/Maxima nicht neu berechnet werden sollen und
1849 // - die Breite der Tabelle nie neu berechnet werden muss, oder
1850 // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder
1851 // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist
1852 // und die Tabelle bereits die Minimalbreite besitzt, oder
1853 // - der verfuegbare Platz groesser ist als die Maximalbreite und
1854 // die Tabelle bereits die Maximalbreite besitzt
1855 // wird sich an der Tabelle nichts aendern.
1856 if( !bRecalc && ( !bMustResize ||
1857 (nLastResizeAbsAvail==nAbsAvail) ||
1858 (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
1859 (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
1860 return sal_False;
1861
1862 if( nDelay==HTMLTABLE_RESIZE_NOW )
1863 {
1864 if( aResizeTimer.IsActive() )
1865 aResizeTimer.Stop();
1866 _Resize( nAbsAvail, bRecalc );
1867 }
1868 else if( nDelay > 0 )
1869 {
1870 nDelayedResizeAbsAvail = nAbsAvail;
1871 bDelayedResizeRecalc = bRecalc;
1872 aResizeTimer.SetTimeout( nDelay );
1873 aResizeTimer.Start();
1874 #ifdef TEST_DELAYED_RESIZE
1875 Sound::Beep( SOUND_DEFAULT );
1876 #endif
1877 }
1878 else
1879 {
1880 _Resize( nAbsAvail, bRecalc );
1881 }
1882
1883 return sal_True;
1884 }
1885
BordersChanged(sal_uInt16 nAbsAvail,sal_Bool bRecalc)1886 void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1887 {
1888 bBordersChanged = sal_True;
1889
1890 Resize( nAbsAvail, bRecalc );
1891 }
1892
1893
1894