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