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