Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "hintids.hxx"
30 : :
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 : : #include <boost/foreach.hpp>
52 : :
53 : : using namespace ::com::sun::star;
54 : :
55 : :
56 : : #define COLFUZZY 20
57 : : #define MAX_TABWIDTH (USHRT_MAX - 2001)
58 : :
59 : :
60 : : class SwHTMLTableLayoutConstraints
61 : : {
62 : : sal_uInt16 nRow; // start row
63 : : sal_uInt16 nCol; // start column
64 : : sal_uInt16 nColSpan; // the column's COLSPAN
65 : :
66 : : SwHTMLTableLayoutConstraints *pNext; // the next constraint
67 : :
68 : : sal_uLong nMinNoAlign, nMaxNoAlign; // provisional result of AL-Pass 1
69 : :
70 : : public:
71 : :
72 : : SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow,
73 : : sal_uInt16 nCol, sal_uInt16 nColSp );
74 : : ~SwHTMLTableLayoutConstraints();
75 : :
76 : 0 : sal_uLong GetMinNoAlign() const { return nMinNoAlign; }
77 : 0 : sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; }
78 : :
79 : : SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
80 : 0 : SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
81 : :
82 : 0 : sal_uInt16 GetRow() const { return nRow; }
83 : :
84 : 0 : sal_uInt16 GetColSpan() const { return nColSpan; }
85 : 0 : sal_uInt16 GetColumn() const { return nCol; }
86 : : };
87 : :
88 : :
89 : 0 : SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
90 : : SwHTMLTableLayout* pTab,
91 : : sal_Bool bNoBrTag,
92 : : SwHTMLTableLayoutCnts* pNxt ) :
93 : : pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
94 : 0 : nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
95 : 0 : {}
96 : :
97 : 0 : SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
98 : : {
99 [ # # ]: 0 : delete pNext;
100 [ # # ]: 0 : delete pTable;
101 : 0 : }
102 : :
103 : 0 : const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
104 : : {
105 [ # # ]: 0 : return pBox ? pBox->GetSttNd() : pStartNode;
106 : : }
107 : :
108 : :
109 : 0 : SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
110 : : sal_uInt16 nRSpan, sal_uInt16 nCSpan,
111 : : sal_uInt16 nWidth, sal_Bool bPrcWidth,
112 : : sal_Bool bNWrapOpt ) :
113 : : pContents( pCnts ),
114 : : nRowSpan( nRSpan ), nColSpan( nCSpan ),
115 : : nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
116 : 0 : bNoWrapOption( bNWrapOpt )
117 : 0 : {}
118 : :
119 : 0 : SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
120 : : {
121 [ # # ][ # # ]: 0 : if( nRowSpan==1 && nColSpan==1 )
122 : : {
123 [ # # ]: 0 : delete pContents;
124 : : }
125 : 0 : }
126 : :
127 : :
128 : 0 : SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth,
129 : : sal_Bool bRelWidth,
130 : : sal_Bool bLBorder ) :
131 : : nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
132 : : nMin(0), nMax(0),
133 : : nAbsColWidth(0), nRelColWidth(0),
134 : : nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
135 : 0 : bLeftBorder( bLBorder )
136 : 0 : {}
137 : :
138 : :
139 : 0 : SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
140 : : sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ):
141 : : nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
142 : : pNext( 0 ),
143 : 0 : nMinNoAlign( nMin ), nMaxNoAlign( nMax )
144 : 0 : {}
145 : :
146 : 0 : SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
147 : : {
148 [ # # ]: 0 : delete pNext;
149 : 0 : }
150 : :
151 : 0 : SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
152 : : SwHTMLTableLayoutConstraints *pNxt )
153 : : {
154 : 0 : SwHTMLTableLayoutConstraints *pPrev = 0;
155 : 0 : SwHTMLTableLayoutConstraints *pConstr = this;
156 [ # # ]: 0 : while( pConstr )
157 : : {
158 [ # # # # ]: 0 : if( pConstr->GetRow() > pNxt->GetRow() ||
[ # # ]
159 : 0 : pConstr->GetColumn() > pNxt->GetColumn() )
160 : 0 : break;
161 : 0 : pPrev = pConstr;
162 : 0 : pConstr = pConstr->GetNext();
163 : : }
164 : :
165 [ # # ]: 0 : if( pPrev )
166 : : {
167 : 0 : pNxt->pNext = pPrev->GetNext();
168 : 0 : pPrev->pNext = pNxt;
169 : 0 : pConstr = this;
170 : : }
171 : : else
172 : : {
173 : 0 : pNxt->pNext = this;
174 : 0 : pConstr = pNxt;
175 : : }
176 : :
177 : 0 : return pConstr;
178 : : }
179 : :
180 : :
181 : : typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
182 : : typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
183 : :
184 : 0 : SwHTMLTableLayout::SwHTMLTableLayout(
185 : : const SwTable * pSwTbl,
186 : : sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs,
187 : : sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt,
188 : : sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust,
189 : : sal_uInt16 nLMargin, sal_uInt16 nRMargin,
190 : : sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth,
191 : : sal_uInt16 nRightBWidth,
192 : : sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) :
193 [ # # ]: 0 : aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
194 [ # # ]: 0 : aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
195 : : pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
196 : : nMin( 0 ), nMax( 0 ),
197 : : nRows( nRws ), nCols( nCls ),
198 : : nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
199 : : nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
200 : : nRelLeftFill( 0 ), nRelRightFill( 0 ),
201 : : nRelTabWidth( 0 ), nWidthOption( nWdth ),
202 : : nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
203 : : nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
204 : : nInhLeftBorderWidth( nInhLeftBWidth ),
205 : : nInhRightBorderWidth( nInhRightBWidth ),
206 : : nBorderWidth( nBWidth ),
207 : : nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
208 : : nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
209 : : bColsOption( bColsOpt ), bColTags( bColTgs ),
210 : : bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ),
211 : : bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ),
212 : 0 : bMustNotResize( sal_False ), bMustNotRecalc( sal_False )
213 : : {
214 : : aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
215 [ # # ]: 0 : DelayedResize_Impl ) );
216 : 0 : }
217 : :
218 : 0 : SwHTMLTableLayout::~SwHTMLTableLayout()
219 : : {
220 : : sal_uInt16 i;
221 : :
222 [ # # ]: 0 : for( i = 0; i < nCols; i++ )
223 [ # # ]: 0 : delete aColumns[i];
224 [ # # ]: 0 : delete[] aColumns;
225 : :
226 : 0 : sal_uInt16 nCount = nRows*nCols;
227 [ # # ]: 0 : for( i=0; i<nCount; i++ )
228 [ # # ][ # # ]: 0 : delete aCells[i];
229 [ # # ]: 0 : delete[] aCells;
230 : 0 : }
231 : :
232 : : // The border width are calculated like in Netscape:
233 : : // Outer border: BORDER + CELLSPACING + CELLPADDING
234 : : // Inner border: CELLSPACING + CELLPADDING
235 : : // However, we respect the border width in SW if bSwBorders is set,
236 : : // so that we don't wrap wrongly.
237 : : // We also need to respect the distance to the content. Even if
238 : : // only the opposite side has a border.
239 : 0 : sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
240 : : sal_Bool bSwBorders ) const
241 : : {
242 : 0 : sal_uInt16 nSpace = nCellSpacing + nCellPadding;
243 : :
244 [ # # ]: 0 : if( nCol == 0 )
245 : : {
246 : 0 : nSpace = nSpace + nBorder;
247 : :
248 [ # # ][ # # ]: 0 : if( bSwBorders && nSpace < nLeftBorderWidth )
249 : 0 : nSpace = nLeftBorderWidth;
250 : : }
251 [ # # ]: 0 : else if( bSwBorders )
252 : : {
253 [ # # ]: 0 : if( GetColumn(nCol)->HasLeftBorder() )
254 : : {
255 [ # # ]: 0 : if( nSpace < nBorderWidth )
256 : 0 : nSpace = nBorderWidth;
257 : : }
258 [ # # ][ # # ]: 0 : else if( nCol+nColSpan == nCols && nRightBorderWidth &&
[ # # ]
259 : : nSpace < MIN_BORDER_DIST )
260 : : {
261 : : OSL_ENSURE( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
262 : : // If the opposite side has a border we need to respect at
263 : : // least the minimum distance to the content.
264 : : // Additionally, we could also use nCellPadding for this.
265 : 0 : nSpace = MIN_BORDER_DIST;
266 : : }
267 : : }
268 : :
269 : 0 : return nSpace;
270 : : }
271 : :
272 : 0 : sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan,
273 : : sal_Bool bSwBorders ) const
274 : : {
275 : 0 : sal_uInt16 nSpace = nCellPadding;
276 : :
277 [ # # ]: 0 : if( nCol+nColSpan == nCols )
278 : : {
279 : 0 : nSpace += nBorder + nCellSpacing;
280 [ # # ][ # # ]: 0 : if( bSwBorders && nSpace < nRightBorderWidth )
281 : 0 : nSpace = nRightBorderWidth;
282 : : }
283 [ # # ][ # # ]: 0 : else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
[ # # ][ # # ]
284 : : nSpace < MIN_BORDER_DIST )
285 : : {
286 : : OSL_ENSURE( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
287 : : // If the opposite side has a border we need to respect at
288 : : // least the minimum distance to the content.
289 : : // Additionally, we could also use nCellPadding for this.
290 : 0 : nSpace = MIN_BORDER_DIST;
291 : : }
292 : :
293 : 0 : return nSpace;
294 : : }
295 : :
296 : 0 : void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax,
297 : : sal_uLong &rAbsMin,
298 : : sal_uInt16 nCol, sal_uInt16 nColSpan,
299 : : sal_Bool bSwBorders ) const
300 : : {
301 : 0 : sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
302 : 0 : GetRightCellSpace( nCol, nColSpan, bSwBorders );
303 : :
304 : 0 : rMin += nAdd;
305 : 0 : rMax += nAdd;
306 : 0 : rAbsMin += nAdd;
307 : 0 : }
308 : :
309 : 0 : void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol,
310 : : sal_uInt16 nColSpan ) const
311 : : {
312 : 0 : SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
313 : :
314 : : // calculate the box's width
315 : 0 : SwTwips nFrmWidth = 0;
316 [ # # ]: 0 : while( nColSpan-- )
317 : 0 : nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
318 : :
319 : : // and reset
320 [ # # ]: 0 : pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
321 : 0 : }
322 : :
323 : 0 : void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan,
324 : : sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const
325 : : {
326 : 0 : rAbsAvail = 0;
327 : 0 : rRelAvail = 0;
328 [ # # ]: 0 : for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ )
329 : : {
330 : 0 : const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
331 : 0 : rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
332 : 0 : rRelAvail = rRelAvail + pColumn->GetRelColWidth();
333 : : }
334 : 0 : }
335 : :
336 : 0 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
337 : : {
338 : 0 : ViewShell *pVSh = 0;
339 [ # # ]: 0 : rDoc.GetEditShell( &pVSh );
340 [ # # ]: 0 : if( pVSh )
341 : : {
342 [ # # ]: 0 : return (sal_uInt16)pVSh->GetBrowseWidth();
343 : : }
344 : :
345 : 0 : return 0;
346 : : }
347 : :
348 : 0 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
349 : : {
350 : : // If we have a layout, we can get the width from there.
351 : 0 : const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); //swmod 080218
352 [ # # ]: 0 : if( pRootFrm )
353 : : {
354 : 0 : const SwFrm *pPageFrm = pRootFrm->GetLower();
355 [ # # ]: 0 : if( pPageFrm )
356 : 0 : return (sal_uInt16)pPageFrm->Prt().Width();
357 : : }
358 : :
359 : : // #i91658#
360 : : // Assertion removed which state that no browse width is available.
361 : : // Investigation reveals that all calls can handle the case that no browse
362 : : // width is provided.
363 : 0 : return GetBrowseWidthByVisArea( rDoc );
364 : : }
365 : :
366 : 0 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm(
367 : : const SwTabFrm& rTabFrm ) const
368 : : {
369 : 0 : SwTwips nWidth = 0;
370 : :
371 : 0 : const SwFrm *pUpper = rTabFrm.GetUpper();
372 [ # # ][ # # ]: 0 : if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
[ # # ][ # # ]
373 [ # # ]: 0 : ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
374 : : {
375 : : // If the table is located within a self-created frame, the anchor's
376 : : // width is relevant not the frame's width.
377 : : // For paragraph-bound frames we don't respect paragraph indents.
378 [ # # ]: 0 : const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
379 [ # # ]: 0 : if( pAnchor->IsTxtFrm() )
380 : 0 : nWidth = pAnchor->Frm().Width();
381 : : else
382 : 0 : nWidth = pAnchor->Prt().Width();
383 : : }
384 : : else
385 : : {
386 : 0 : nWidth = pUpper->Prt().Width();
387 : : }
388 : :
389 : 0 : SwTwips nUpperDummy = 0;
390 : 0 : long nRightOffset = 0,
391 : 0 : nLeftOffset = 0;
392 [ # # ]: 0 : rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
393 : 0 : nWidth -= (nLeftOffset + nRightOffset);
394 : :
395 [ # # ]: 0 : return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX;
396 : : }
397 : :
398 : 0 : sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
399 : : {
400 : 0 : sal_uInt16 nBrowseWidth = 0;
401 : 0 : SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() );
402 [ # # ]: 0 : if( pFrm )
403 : : {
404 : 0 : nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm );
405 : : }
406 : : else
407 : : {
408 : 0 : nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
409 : : }
410 : :
411 : 0 : return nBrowseWidth;
412 : : }
413 : :
414 : 0 : const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
415 : : {
416 : : const SwStartNode *pBoxSttNd;
417 : :
418 : 0 : const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
419 [ # # ]: 0 : while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
420 : : {
421 : : OSL_ENSURE( pBox->GetTabLines().size() > 0,
422 : : "Box without start node and lines" );
423 : : OSL_ENSURE( pBox->GetTabLines().front()->GetTabBoxes().size() > 0,
424 : : "Line without boxes" );
425 : 0 : pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
426 : : }
427 : :
428 : 0 : return pBoxSttNd;
429 : : }
430 : :
431 : 0 : SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
432 : : {
433 : 0 : const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
434 : : OSL_ENSURE( pTblNd, "Kein Table-Node?" );
435 : 0 : return pTblNd->GetFlyFmt();
436 : : }
437 : :
438 : 0 : static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts,
439 : : sal_uLong& rAbsMinNoAlignCnts,
440 : : SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak )
441 : : {
442 : : pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
443 : 0 : rAbsMinNoAlignCnts );
444 : : OSL_ENSURE( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
445 : : "GetMinMaxSize: absmin > min" );
446 : : OSL_ENSURE( rMinNoAlignCnts <= rMaxNoAlignCnts,
447 : : "GetMinMaxSize: max > min" );
448 : :
449 : : // The maximal width for a <PRE> paragraph is the minimal width
450 : 0 : const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
451 [ # # ]: 0 : while( pColl && !pColl->IsDefault() &&
[ # # # # ]
[ # # ]
452 : 0 : (USER_FMT & pColl->GetPoolFmtId()) )
453 : : {
454 : 0 : pColl = (const SwFmtColl *)pColl->DerivedFrom();
455 : : }
456 : :
457 : : // <NOBR> in the whole cell apply to text but not to tables.
458 : : // Netscape only considers this for graphics.
459 [ # # ][ # # ]: 0 : if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
[ # # ][ # # ]
460 : : {
461 : 0 : rMinNoAlignCnts = rMaxNoAlignCnts;
462 : 0 : rAbsMinNoAlignCnts = rMaxNoAlignCnts;
463 : : }
464 : 0 : }
465 : :
466 : 0 : void SwHTMLTableLayout::AutoLayoutPass1()
467 : : {
468 : 0 : nPass1Done++;
469 : :
470 : 0 : ClearPass1Info();
471 : :
472 : 0 : sal_Bool bFixRelWidths = sal_False;
473 : : sal_uInt16 i;
474 : :
475 : 0 : SwHTMLTableLayoutConstraints *pConstraints = 0;
476 : :
477 [ # # ]: 0 : for( i=0; i<nCols; i++ )
478 : : {
479 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
480 : 0 : pColumn->ClearPass1Info( !HasColTags() );
481 : 0 : sal_uInt16 nMinColSpan = USHRT_MAX; // Column count to which the calculated width refers to
482 : 0 : sal_uInt16 nColSkip = USHRT_MAX; // How many columns need to be skipped
483 : :
484 [ # # ]: 0 : for( sal_uInt16 j=0; j<nRows; j++ )
485 : : {
486 : 0 : SwHTMLTableLayoutCell *pCell = GetCell(j,i);
487 : 0 : SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
488 : :
489 : : // We need to examine all rows in order to
490 : : // get the column that should be calculated next.
491 : 0 : sal_uInt16 nColSpan = pCell->GetColSpan();
492 [ # # ]: 0 : if( nColSpan < nColSkip )
493 : 0 : nColSkip = nColSpan;
494 : :
495 [ # # ][ # # ]: 0 : if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
[ # # ][ # # ]
496 : : {
497 : : // The cell is empty or it's content was not edited
498 [ # # ]: 0 : if( nColSpan < nMinColSpan )
499 : 0 : nMinColSpan = nColSpan;
500 : :
501 : 0 : sal_uLong nMinNoAlignCell = 0;
502 : 0 : sal_uLong nMaxNoAlignCell = 0;
503 : 0 : sal_uLong nAbsMinNoAlignCell = 0;
504 : 0 : sal_uLong nMaxTableCell = 0;
505 : 0 : sal_uLong nAbsMinTableCell = 0;
506 : :
507 [ # # ]: 0 : while( pCnts )
508 : : {
509 : 0 : const SwStartNode *pSttNd = pCnts->GetStartNode();
510 [ # # ]: 0 : if( pSttNd )
511 : : {
512 : 0 : const SwDoc *pDoc = pSttNd->GetDoc();
513 : 0 : sal_uLong nIdx = pSttNd->GetIndex();
514 [ # # ][ # # ]: 0 : while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
[ # # ]
515 : : {
516 [ # # ][ # # ]: 0 : SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
517 [ # # ]: 0 : if( pTxtNd )
518 : : {
519 : 0 : sal_uLong nMinNoAlignCnts = 0;
520 : 0 : sal_uLong nMaxNoAlignCnts = 0;
521 : 0 : sal_uLong nAbsMinNoAlignCnts = 0;
522 : :
523 : : lcl_GetMinMaxSize( nMinNoAlignCnts,
524 : : nMaxNoAlignCnts,
525 : : nAbsMinNoAlignCnts,
526 : : pTxtNd, nIdx,
527 [ # # ]: 0 : pCnts->HasNoBreakTag() );
528 : :
529 [ # # ]: 0 : if( nMinNoAlignCnts > nMinNoAlignCell )
530 : 0 : nMinNoAlignCell = nMinNoAlignCnts;
531 [ # # ]: 0 : if( nMaxNoAlignCnts > nMaxNoAlignCell )
532 : 0 : nMaxNoAlignCell = nMaxNoAlignCnts;
533 [ # # ]: 0 : if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
534 : 0 : nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
535 : : }
536 : : else
537 : : {
538 [ # # ][ # # ]: 0 : SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
539 [ # # ]: 0 : if( pTabNd )
540 : : {
541 : 0 : SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
542 [ # # ]: 0 : if( pChild )
543 : : {
544 [ # # ]: 0 : pChild->AutoLayoutPass1();
545 : 0 : sal_uLong nMaxTableCnts = pChild->nMax;
546 : 0 : sal_uLong nAbsMinTableCnts = pChild->nMin;
547 : :
548 : : // A fixed table width is taken over as minimum and
549 : : // maximum at the same time
550 [ # # ][ # # ]: 0 : if( !pChild->bPrcWidthOption && pChild->nWidthOption )
551 : : {
552 : 0 : sal_uLong nTabWidth = pChild->nWidthOption;
553 [ # # ]: 0 : if( nTabWidth >= nAbsMinTableCnts )
554 : : {
555 : 0 : nMaxTableCnts = nTabWidth;
556 : 0 : nAbsMinTableCnts = nTabWidth;
557 : : }
558 : : else
559 : : {
560 : 0 : nMaxTableCnts = nAbsMinTableCnts;
561 : : }
562 : : }
563 : :
564 [ # # ]: 0 : if( nMaxTableCnts > nMaxTableCell )
565 : 0 : nMaxTableCell = nMaxTableCnts;
566 [ # # ]: 0 : if( nAbsMinTableCnts > nAbsMinTableCell )
567 : 0 : nAbsMinTableCell = nAbsMinTableCnts;
568 : : }
569 : 0 : nIdx = pTabNd->EndOfSectionNode()->GetIndex();
570 : : }
571 : : }
572 : 0 : nIdx++;
573 : : }
574 : : }
575 : : else
576 : : {
577 : : OSL_ENSURE( !this, "Sub tables in HTML import?" );
578 : 0 : SwHTMLTableLayout *pChild = pCnts->GetTable();
579 [ # # ]: 0 : pChild->AutoLayoutPass1();
580 : 0 : sal_uLong nMaxTableCnts = pChild->nMax;
581 : 0 : sal_uLong nAbsMinTableCnts = pChild->nMin;
582 : :
583 : : // A fixed table width is taken over as minimum and
584 : : // maximum at the same time
585 [ # # ][ # # ]: 0 : if( !pChild->bPrcWidthOption && pChild->nWidthOption )
586 : : {
587 : 0 : sal_uLong nTabWidth = pChild->nWidthOption;
588 [ # # ]: 0 : if( nTabWidth >= nAbsMinTableCnts )
589 : : {
590 : 0 : nMaxTableCnts = nTabWidth;
591 : 0 : nAbsMinTableCnts = nTabWidth;
592 : : }
593 : : else
594 : : {
595 : 0 : nMaxTableCnts = nAbsMinTableCnts;
596 : : }
597 : : }
598 : :
599 [ # # ]: 0 : if( nMaxTableCnts > nMaxTableCell )
600 : 0 : nMaxTableCell = nMaxTableCnts;
601 [ # # ]: 0 : if( nAbsMinTableCnts > nAbsMinTableCell )
602 : 0 : nAbsMinTableCell = nAbsMinTableCnts;
603 : : }
604 : 0 : pCnts->SetPass1Done( nPass1Done );
605 : 0 : pCnts = pCnts->GetNext();
606 : : }
607 : :
608 : : // This code previously came after AddBorderWidth
609 : : // If a table's width is wider in a cell than what we've calculated
610 : : // for the other content we need to use the table's width.
611 [ # # ]: 0 : if( nMaxTableCell > nMaxNoAlignCell )
612 : 0 : nMaxNoAlignCell = nMaxTableCell;
613 [ # # ]: 0 : if( nAbsMinTableCell > nAbsMinNoAlignCell )
614 : : {
615 : 0 : nAbsMinNoAlignCell = nAbsMinTableCell;
616 [ # # ]: 0 : if( nMinNoAlignCell < nAbsMinNoAlignCell )
617 : 0 : nMinNoAlignCell = nAbsMinNoAlignCell;
618 [ # # ]: 0 : if( nMaxNoAlignCell < nMinNoAlignCell )
619 : 0 : nMaxNoAlignCell = nMinNoAlignCell;
620 : : }
621 : : // This code previously came after AddBorderWidth
622 : :
623 : 0 : sal_Bool bRelWidth = pCell->IsPrcWidthOption();
624 : 0 : sal_uInt16 nWidth = pCell->GetWidthOption();
625 : :
626 : : // A NOWRAP option applies to text and tables, but is
627 : : // not applied for fixed cell width.
628 : : // Instead, the stated cell width behaves like a minimal
629 : : // width.
630 [ # # ]: 0 : if( pCell->HasNoWrapOption() )
631 : : {
632 [ # # ][ # # ]: 0 : if( nWidth==0 || bRelWidth )
633 : : {
634 : 0 : nMinNoAlignCell = nMaxNoAlignCell;
635 : 0 : nAbsMinNoAlignCell = nMaxNoAlignCell;
636 : : }
637 : : else
638 : : {
639 [ # # ]: 0 : if( nWidth>nMinNoAlignCell )
640 : 0 : nMinNoAlignCell = nWidth;
641 [ # # ]: 0 : if( nWidth>nAbsMinNoAlignCell )
642 : 0 : nAbsMinNoAlignCell = nWidth;
643 : : }
644 : : }
645 : :
646 : : // Respect minimum width for content
647 [ # # ]: 0 : if( nMinNoAlignCell < MINLAY )
648 : 0 : nMinNoAlignCell = MINLAY;
649 [ # # ]: 0 : if( nMaxNoAlignCell < MINLAY )
650 : 0 : nMaxNoAlignCell = MINLAY;
651 [ # # ]: 0 : if( nAbsMinNoAlignCell < MINLAY )
652 : 0 : nAbsMinNoAlignCell = MINLAY;
653 : :
654 : : // Respect the border and distance to the content
655 : : AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
656 : 0 : nAbsMinNoAlignCell, i, nColSpan );
657 : :
658 [ # # ]: 0 : if( 1==nColSpan )
659 : : {
660 : : // take over the values directly
661 : : pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
662 : : nMaxNoAlignCell,
663 : 0 : nAbsMinNoAlignCell );
664 : :
665 : : // the widest WIDTH wins
666 [ # # ]: 0 : if( !HasColTags() )
667 : 0 : pColumn->MergeCellWidthOption( nWidth, bRelWidth );
668 : : }
669 : : else
670 : : {
671 : : // Process the data line by line from left to right at the end
672 : :
673 : : // When which values is taken over will be explained further down.
674 [ # # ][ # # ]: 0 : if( !HasColTags() && nWidth && !bRelWidth )
[ # # ][ # # ]
675 : : {
676 : 0 : sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
677 : : AddBorderWidth( nAbsWidth, nDummy, nDummy2,
678 : 0 : i, nColSpan, sal_False );
679 : :
680 [ # # ]: 0 : if( nAbsWidth >= nMinNoAlignCell )
681 : : {
682 : 0 : nMaxNoAlignCell = nAbsWidth;
683 [ # # ]: 0 : if( HasColsOption() )
684 : 0 : nMinNoAlignCell = nAbsWidth;
685 : : }
686 [ # # ]: 0 : else if( nAbsWidth >= nAbsMinNoAlignCell )
687 : : {
688 : 0 : nMaxNoAlignCell = nAbsWidth;
689 : 0 : nMinNoAlignCell = nAbsWidth;
690 : : }
691 : : else
692 : : {
693 : 0 : nMaxNoAlignCell = nAbsMinNoAlignCell;
694 : 0 : nMinNoAlignCell = nAbsMinNoAlignCell;
695 : : }
696 : : }
697 [ # # ][ # # ]: 0 : else if( HasColsOption() || HasColTags() )
[ # # ]
698 : 0 : nMinNoAlignCell = nAbsMinNoAlignCell;
699 : :
700 : : SwHTMLTableLayoutConstraints *pConstr =
701 : : new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
702 [ # # ]: 0 : nMaxNoAlignCell, j, i, nColSpan );
703 [ # # ]: 0 : if( pConstraints )
704 : 0 : pConstraints = pConstraints->InsertNext( pConstr );
705 : : else
706 : 0 : pConstraints = pConstr;
707 : : }
708 : : }
709 : : }
710 : :
711 : : OSL_ENSURE( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
712 : : "Layout pass 1: Columns are being forgotten!" );
713 : : OSL_ENSURE( nMinColSpan!=USHRT_MAX,
714 : : "Layout pass 1: unnecessary pass through the loop or a bug" );
715 : :
716 [ # # ]: 0 : if( 1==nMinColSpan )
717 : : {
718 : : // There are cells with COLSPAN 1 and therefore also useful
719 : : // values in pColumn
720 : :
721 : : // Take over values according to the following table (Netscape 4.0 pv 3):
722 : : //
723 : : // WIDTH: no COLS COLS
724 : : //
725 : : // none min = min min = absmin
726 : : // max = max max = max
727 : : //
728 : : // >= min min = min min = width
729 : : // max = width max = width
730 : : //
731 : : // >= absmin min = wdith(*) min = width
732 : : // max = width max = width
733 : : //
734 : : // < absmin min = absmin min = absmin
735 : : // max = absmin max = absmin
736 : : //
737 : : // (*) Netscape uses the minimum width without a break before
738 : : // the last graphic here. We don't have that (yet?),
739 : : // so we leave it set to width.
740 : :
741 [ # # ][ # # ]: 0 : if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
[ # # ]
742 : : {
743 : : // Take over absolute widths as minimal and maximal widths.
744 : 0 : sal_uLong nAbsWidth = pColumn->GetWidthOption();
745 : 0 : sal_uLong nDummy = 0, nDummy2 = 0;
746 : 0 : AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False );
747 : :
748 [ # # ]: 0 : if( nAbsWidth >= pColumn->GetMinNoAlign() )
749 : : {
750 : 0 : pColumn->SetMinMax( HasColsOption() ? nAbsWidth
751 : : : pColumn->GetMinNoAlign(),
752 [ # # ]: 0 : nAbsWidth );
753 : : }
754 [ # # ]: 0 : else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
755 : : {
756 : 0 : pColumn->SetMinMax( nAbsWidth, nAbsWidth );
757 : : }
758 : : else
759 : : {
760 : : pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
761 : 0 : pColumn->GetAbsMinNoAlign() );
762 : : }
763 : : }
764 : : else
765 : : {
766 : 0 : pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
767 : : : pColumn->GetMinNoAlign(),
768 [ # # ]: 0 : pColumn->GetMaxNoAlign() );
769 : : }
770 : : }
771 [ # # ]: 0 : else if( USHRT_MAX!=nMinColSpan )
772 : : {
773 : : // Can be anything != 0, because it is altered by the constraints.
774 : 0 : pColumn->SetMinMax( MINLAY, MINLAY );
775 : :
776 : : // the next columns need not to be processed
777 : 0 : i += (nColSkip-1);
778 : : }
779 : :
780 : 0 : nMin += pColumn->GetMin();
781 : 0 : nMax += pColumn->GetMax();
782 : 0 : bFixRelWidths |= pColumn->IsRelWidthOption();
783 : : }
784 : :
785 : : // Now process the constraints
786 : 0 : SwHTMLTableLayoutConstraints *pConstr = pConstraints;
787 [ # # ]: 0 : while( pConstr )
788 : : {
789 : : // At first we need to process the width in the same way
790 : : // as the column widths
791 : 0 : sal_uInt16 nCol = pConstr->GetColumn();
792 : 0 : sal_uInt16 nColSpan = pConstr->GetColSpan();
793 : 0 : sal_uLong nConstrMin = pConstr->GetMinNoAlign();
794 : 0 : sal_uLong nConstrMax = pConstr->GetMaxNoAlign();
795 : :
796 : : // We get the hitherto width of the spanned columns
797 : 0 : sal_uLong nColsMin = 0;
798 : 0 : sal_uLong nColsMax = 0;
799 [ # # ]: 0 : for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ )
800 : : {
801 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
802 : 0 : nColsMin += pColumn->GetMin();
803 : 0 : nColsMax += pColumn->GetMax();
804 : : }
805 : :
806 [ # # ]: 0 : if( nColsMin<nConstrMin )
807 : : {
808 : : // Proportionately distribute the minimum value to the columns
809 : 0 : sal_uLong nMinD = nConstrMin-nColsMin;
810 : :
811 [ # # ]: 0 : if( nConstrMin > nColsMax )
812 : : {
813 : : // Proportional according to the minimum widths
814 : 0 : sal_uInt16 nEndCol = nCol+nColSpan;
815 : 0 : sal_uLong nDiff = nMinD;
816 [ # # ]: 0 : for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ )
817 : : {
818 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
819 : :
820 : 0 : sal_uLong nColMin = pColumn->GetMin();
821 : 0 : sal_uLong nColMax = pColumn->GetMax();
822 : :
823 : 0 : nMin -= nColMin;
824 : : sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
825 [ # # ]: 0 : : nDiff;
826 : 0 : nColMin += nAdd;
827 : 0 : nMin += nColMin;
828 : : OSL_ENSURE( nDiff >= nAdd, "Ooops: nDiff is not correct anymore" );
829 : 0 : nDiff -= nAdd;
830 : :
831 [ # # ]: 0 : if( nColMax < nColMin )
832 : : {
833 : 0 : nMax -= nColMax;
834 : 0 : nColsMax -= nColMax;
835 : 0 : nColMax = nColMin;
836 : 0 : nMax += nColMax;
837 : 0 : nColsMax += nColMax;
838 : : }
839 : :
840 : 0 : pColumn->SetMinMax( nColMin, nColMax );
841 : : }
842 : : }
843 : : else
844 : : {
845 : : // Proportional according to the difference of max and min
846 [ # # ]: 0 : for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
847 : : {
848 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
849 : :
850 : 0 : sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin();
851 [ # # ]: 0 : if( nMinD < nDiff )
852 : 0 : nDiff = nMinD;
853 : :
854 : 0 : pColumn->AddToMin( nDiff );
855 : :
856 : : OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
857 : : "Why is the Column suddenly too narrow?" );
858 : :
859 : 0 : nMin += nDiff;
860 : 0 : nMinD -= nDiff;
861 : : }
862 : : }
863 : : }
864 : :
865 [ # # ][ # # ]: 0 : if( !HasColTags() && nColsMax<nConstrMax )
[ # # ]
866 : : {
867 : 0 : sal_uLong nMaxD = nConstrMax-nColsMax;
868 : :
869 [ # # ]: 0 : for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ )
870 : : {
871 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
872 : :
873 : 0 : nMax -= pColumn->GetMax();
874 : :
875 : 0 : pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
876 : :
877 : 0 : nMax += pColumn->GetMax();
878 : : }
879 : : }
880 : :
881 : 0 : pConstr = pConstr->GetNext();
882 : : }
883 : :
884 : :
885 [ # # ]: 0 : if( bFixRelWidths )
886 : : {
887 [ # # ]: 0 : if( HasColTags() )
888 : : {
889 : : // To adapt the relative widths, in a first step we multiply the
890 : : // minimum width of all affected cells with the relative width
891 : : // of the column.
892 : : // Thus, the width ratio among the columns is correct.
893 : : //
894 : : // Furthermore, a factor is calculated that says by how much the
895 : : // cell has gotten wider than the minimum width.
896 : : //
897 : : // In the second step the calculated widths are divided by this
898 : : // factor. Thereby a cell's width is preserved and serves as a
899 : : // basis for the other cells.
900 : : // We only change the maximum widths here!
901 : :
902 : 0 : sal_uLong nAbsMin = 0; // absolute minimum width of all widths with relative width
903 : 0 : sal_uLong nRel = 0; // sum of all relative widths of all columns
904 [ # # ]: 0 : for( i=0; i<nCols; i++ )
905 : : {
906 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
907 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
[ # # ]
908 : : {
909 : 0 : nAbsMin += pColumn->GetMin();
910 : 0 : nRel += pColumn->GetWidthOption();
911 : : }
912 : : }
913 : :
914 : 0 : sal_uLong nQuot = ULONG_MAX;
915 [ # # ]: 0 : for( i=0; i<nCols; i++ )
916 : : {
917 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
918 [ # # ]: 0 : if( pColumn->IsRelWidthOption() )
919 : : {
920 : 0 : nMax -= pColumn->GetMax();
921 [ # # ][ # # ]: 0 : if( pColumn->GetWidthOption() && pColumn->GetMin() )
[ # # ]
922 : : {
923 : 0 : pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
924 : 0 : sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin();
925 [ # # ]: 0 : if( nColQuot<nQuot )
926 : 0 : nQuot = nColQuot;
927 : : }
928 : : }
929 : : }
930 : : OSL_ENSURE( 0==nRel || nQuot!=ULONG_MAX,
931 : : "Where did the relative columns go?" );
932 [ # # ]: 0 : for( i=0; i<nCols; i++ )
933 : : {
934 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
935 [ # # ]: 0 : if( pColumn->IsRelWidthOption() )
936 : : {
937 [ # # ]: 0 : if( pColumn->GetWidthOption() )
938 : 0 : pColumn->SetMax( pColumn->GetMax() / nQuot );
939 : : else
940 : 0 : pColumn->SetMax( pColumn->GetMin() );
941 : : OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
942 : : "Maximum column width is lower than the minimum column width" );
943 : 0 : nMax += pColumn->GetMax();
944 : : }
945 : : }
946 : : }
947 : : else
948 : : {
949 : 0 : sal_uInt16 nRel = 0; // sum of the relative widths of all columns
950 : 0 : sal_uInt16 nRelCols = 0; // count of the columns with a relative setting
951 : 0 : sal_uLong nRelMax = 0; // fraction of the maximum of this column
952 [ # # ]: 0 : for( i=0; i<nCols; i++ )
953 : : {
954 : : OSL_ENSURE( nRel<=100, "relative width of all columns > 100%" );
955 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
956 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
[ # # ]
957 : : {
958 : : // Make sure that the relative widths don't go above 100%
959 : 0 : sal_uInt16 nColWidth = pColumn->GetWidthOption();
960 [ # # ]: 0 : if( nRel+nColWidth > 100 )
961 : : {
962 : 0 : nColWidth = 100 - nRel;
963 : 0 : pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
964 : : }
965 : 0 : nRelMax += pColumn->GetMax();
966 : 0 : nRel = nRel + nColWidth;
967 : 0 : nRelCols++;
968 : : }
969 [ # # ]: 0 : else if( !pColumn->GetMin() )
970 : : {
971 : : // The column is empty (so it was solely created by
972 : : // COLSPAN) and therefore must not be assigned a % width.
973 : 0 : nRelCols++;
974 : : }
975 : : }
976 : :
977 : : // If there are percentages left we distribute them to the columns
978 : : // that don't have a width setting. Like in Netscape we distribute
979 : : // the remaining percentages according to the ratio of the maximum
980 : : // width of the affected columns.
981 : : // For the maximum widths we also take the fixed-width columns
982 : : // into account. Is that correct?
983 [ # # ][ # # ]: 0 : if( nRel < 100 && nRelCols < nCols )
984 : : {
985 : 0 : sal_uInt16 nRelLeft = 100 - nRel;
986 : 0 : sal_uLong nFixMax = nMax - nRelMax;
987 [ # # ]: 0 : for( i=0; i<nCols; i++ )
988 : : {
989 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
990 [ # # ][ # # : 0 : if( !pColumn->IsRelWidthOption() &&
# # # # ]
991 : 0 : !pColumn->GetWidthOption() &&
992 : 0 : pColumn->GetMin() )
993 : : {
994 : : // the next column gets the rest
995 : : sal_uInt16 nColWidth =
996 : 0 : (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax);
997 : 0 : pColumn->SetWidthOption( nColWidth, sal_True, sal_False );
998 : : }
999 : : }
1000 : : }
1001 : :
1002 : : // adjust the maximum widths now accordingly
1003 : 0 : sal_uLong nQuotMax = ULONG_MAX;
1004 : 0 : sal_uLong nOldMax = nMax;
1005 : 0 : nMax = 0;
1006 [ # # ]: 0 : for( i=0; i<nCols; i++ )
1007 : : {
1008 : : // Columns with a % setting are adapted accordingly.
1009 : : // Columns, that
1010 : : // - do not have a % setting and are located within a tables
1011 : : // with COLS and WIDTH, or
1012 : : // - their width is 0%
1013 : : // get set to the minimum width.
1014 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1015 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
[ # # ]
1016 : : {
1017 : : sal_uLong nNewMax;
1018 : : sal_uLong nColQuotMax;
1019 [ # # ]: 0 : if( !nWidthOption )
1020 : : {
1021 : 0 : nNewMax = nOldMax * pColumn->GetWidthOption();
1022 : 0 : nColQuotMax = nNewMax / pColumn->GetMax();
1023 : : }
1024 : : else
1025 : : {
1026 : 0 : nNewMax = nMin * pColumn->GetWidthOption();
1027 : 0 : nColQuotMax = nNewMax / pColumn->GetMin();
1028 : : }
1029 : 0 : pColumn->SetMax( nNewMax );
1030 [ # # ]: 0 : if( nColQuotMax < nQuotMax )
1031 : 0 : nQuotMax = nColQuotMax;
1032 : : }
1033 [ # # ][ # # : 0 : else if( HasColsOption() || nWidthOption ||
# # # # ]
[ # # ]
1034 : 0 : (pColumn->IsRelWidthOption() &&
1035 : 0 : !pColumn->GetWidthOption()) )
1036 : 0 : pColumn->SetMax( pColumn->GetMin() );
1037 : : }
1038 : : // and divide by the quotient
1039 : : OSL_ENSURE( nQuotMax!=ULONG_MAX, "Where did the relative columns go?" );
1040 [ # # ]: 0 : for( i=0; i<nCols; i++ )
1041 : : {
1042 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1043 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
[ # # ]
1044 : : {
1045 [ # # ]: 0 : if( pColumn->GetWidthOption() )
1046 : : {
1047 : 0 : pColumn->SetMax( pColumn->GetMax() / nQuotMax );
1048 : : OSL_ENSURE( pColumn->GetMax() >= pColumn->GetMin(),
1049 : : "Minimum width is one column bigger than maximum" );
1050 [ # # ]: 0 : if( pColumn->GetMax() < pColumn->GetMin() )
1051 : 0 : pColumn->SetMax( pColumn->GetMin() );
1052 : : }
1053 : : }
1054 : 0 : nMax += pColumn->GetMax();
1055 : : }
1056 : : }
1057 : : }
1058 : :
1059 [ # # ]: 0 : delete pConstraints;
1060 : 0 : }
1061 : :
1062 : : // nAbsAvail is the available space in TWIPS.
1063 : : // nRelAvail is the available space related to USHRT_MAX or 0
1064 : : // nAbsSpace is the fraction of nAbsAvail, which is reserved by the surrounding
1065 : : // cell for the border and the distance to the paragraph.
1066 : 0 : void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail,
1067 : : sal_uInt16 nAbsLeftSpace,
1068 : : sal_uInt16 nAbsRightSpace,
1069 : : sal_uInt16 nParentInhAbsSpace )
1070 : : {
1071 : : // For a start we do a lot of plausability tests
1072 : :
1073 : : // An absolute width always has to be passed
1074 : : OSL_ENSURE( nAbsAvail, "AutoLayout pass 2: No absolute width given" );
1075 : :
1076 : : // A relative width must only be passed for tables within tables (?)
1077 : : OSL_ENSURE( IsTopTable() == (nRelAvail==0),
1078 : : "AutoLayout pass 2: Relative width at table in table or the other way around" );
1079 : :
1080 : : // The table's minimum width must not be bigger than it's maximum width
1081 : : OSL_ENSURE( nMin<=nMax, "AutoLayout pass 2: nMin > nMax" );
1082 : :
1083 : : // Remember the available width for which the table was calculated.
1084 : : // This is a good place as we pass by here for the initial calculation
1085 : : // of the table in the parser and for each _Resize call.
1086 : 0 : nLastResizeAbsAvail = nAbsAvail;
1087 : :
1088 : : // Step 1: The available space is readjusted for the left/right border,
1089 : : // possibly existing filler cells and distances.
1090 : :
1091 : : // Distance to the content and border
1092 : 0 : sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0;
1093 [ # # # # ]: 0 : if( !IsTopTable() &&
[ # # ]
1094 : 0 : GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
1095 : : {
1096 : 0 : nAbsLeftFill = nAbsLeftSpace;
1097 : 0 : nAbsRightFill = nAbsRightSpace;
1098 : : }
1099 : :
1100 : : // Left and right distance
1101 [ # # ][ # # ]: 0 : if( nLeftMargin || nRightMargin )
1102 : : {
1103 [ # # ]: 0 : if( IsTopTable() )
1104 : : {
1105 : : // For the top table we always respect the borders, because we
1106 : : // never go below the table's minimum width.
1107 : 0 : nAbsAvail -= (nLeftMargin + nRightMargin);
1108 : : }
1109 [ # # ]: 0 : else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
1110 : : {
1111 : : // Else, we only respect the borders if there's space available
1112 : : // for them (nMin has already been calculated!)
1113 : 0 : nAbsLeftFill = nAbsLeftFill + nLeftMargin;
1114 : 0 : nAbsRightFill = nAbsRightFill + nRightMargin;
1115 : : }
1116 : : }
1117 : :
1118 : : // Filler cells
1119 [ # # ]: 0 : if( !IsTopTable() )
1120 : : {
1121 [ # # ][ # # ]: 0 : if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
1122 : 0 : nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
1123 [ # # ][ # # ]: 0 : if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
1124 : 0 : nAbsRightFill = MINLAY+nInhRightBorderWidth;
1125 : : }
1126 : :
1127 : : // Read just the available space
1128 : 0 : nRelLeftFill = 0;
1129 : 0 : nRelRightFill = 0;
1130 [ # # ][ # # ]: 0 : if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
[ # # ][ # # ]
1131 : : {
1132 : 0 : sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
1133 : :
1134 : 0 : nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
1135 : 0 : nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail);
1136 : :
1137 : 0 : nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
1138 [ # # ]: 0 : if( nRelAvail )
1139 : 0 : nRelAvail -= (nRelLeftFill + nRelRightFill);
1140 : : }
1141 : :
1142 : :
1143 : : // Step 2: Calculate the absolute table width.
1144 : 0 : sal_uInt16 nAbsTabWidth = 0;
1145 : 0 : bUseRelWidth = sal_False;
1146 [ # # ]: 0 : if( nWidthOption )
1147 : : {
1148 [ # # ]: 0 : if( bPrcWidthOption )
1149 : : {
1150 : : OSL_ENSURE( nWidthOption<=100, "Percentage value too high" );
1151 [ # # ]: 0 : if( nWidthOption > 100 )
1152 : 0 : nWidthOption = 100;
1153 : :
1154 : : // The absolute width is equal to the given percentage of
1155 : : // the available width.
1156 : : // Top tables only get a relative width if the available space
1157 : : // is *strictly larger* than the minimum width.
1158 : : //
1159 : : // CAUTION: We need the "strictly larger" because changing from a
1160 : : // relative width to an absolute width by resizing would lead
1161 : : // to an infinite loop.
1162 : : //
1163 : : // Because we do not call resize for tables in frames if the
1164 : : // frame has a non-relative width, we cannot play such games.
1165 : : //
1166 : : // Let's play such games now anyway. We had a graphic in a 1% wide
1167 : : // table and it didn't fit in of course.
1168 : 0 : nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 );
1169 [ # # ][ # # ]: 0 : if( IsTopTable() &&
[ # # ]
1170 : : ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) )
1171 : : {
1172 : 0 : nRelAvail = USHRT_MAX;
1173 : 0 : bUseRelWidth = sal_True;
1174 : : }
1175 : : }
1176 : : else
1177 : : {
1178 : 0 : nAbsTabWidth = nWidthOption;
1179 [ # # ]: 0 : if( nAbsTabWidth > MAX_TABWIDTH )
1180 : 0 : nAbsTabWidth = MAX_TABWIDTH;
1181 : :
1182 : : // Tables within tables must never get wider than the available
1183 : : // space.
1184 [ # # ][ # # ]: 0 : if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
[ # # ]
1185 : 0 : nAbsTabWidth = nAbsAvail;
1186 : : }
1187 : : }
1188 : :
1189 : : OSL_ENSURE( IsTopTable() || nAbsTabWidth<=nAbsAvail,
1190 : : "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for table in table" );
1191 : : OSL_ENSURE( !nRelAvail || nAbsTabWidth<=nAbsAvail,
1192 : : "AutoLayout pass 2: nAbsTabWidth > nAbsAvail for relative width" );
1193 : :
1194 : : // Catch for the two asserts above (we never know!)
1195 [ # # ][ # # ]: 0 : if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
[ # # ][ # # ]
1196 : 0 : nAbsTabWidth = nAbsAvail;
1197 : :
1198 : :
1199 : : // Step 3: Identify the column width and, if applicable, the absolute
1200 : : // and relative table widths.
1201 [ # # ][ # # ]: 0 : if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) ||
[ # # ][ # # ]
1202 : : nMin > MAX_TABWIDTH )
1203 : : {
1204 : : // If
1205 : : // - a inner table's minimum is larger than the available space, or
1206 : : // - a top table's minimum is larger than USHORT_MAX the table
1207 : : // has to be adapted to the available space or USHORT_MAX.
1208 : : // We preserve the widths' ratio amongst themselves, however.
1209 : :
1210 [ # # ]: 0 : nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
1211 [ # # ]: 0 : nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
1212 : :
1213 : : // First of all, we check whether we can fit the layout constrains,
1214 : : // which are: Every cell's width excluding the borders must be at least
1215 : : // MINLAY:
1216 : :
1217 : 0 : sal_uLong nRealMin = 0;
1218 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols; i++ )
1219 : : {
1220 : 0 : sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1221 : 0 : AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1222 : 0 : nRealMin += nRealColMin;
1223 : : }
1224 [ # # ][ # # ]: 0 : if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
1225 : : {
1226 : : // "Rien ne va plus": we cannot get the minimum column widths
1227 : : // the layout wants to have.
1228 : :
1229 : 0 : sal_uInt16 nAbs = 0, nRel = 0;
1230 : : SwHTMLTableLayoutColumn *pColumn;
1231 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols-1; i++ )
1232 : : {
1233 : 0 : pColumn = GetColumn( i );
1234 : 0 : sal_uLong nColMin = pColumn->GetMin();
1235 [ # # ]: 0 : if( nColMin <= USHRT_MAX )
1236 : : {
1237 : : pColumn->SetAbsColWidth(
1238 : 0 : (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) );
1239 : : pColumn->SetRelColWidth(
1240 : 0 : (sal_uInt16)((nColMin * nRelTabWidth) / nMin) );
1241 : : }
1242 : : else
1243 : : {
1244 : 0 : double nColMinD = nColMin;
1245 : : pColumn->SetAbsColWidth(
1246 : 0 : (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) );
1247 : : pColumn->SetRelColWidth(
1248 : 0 : (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) );
1249 : : }
1250 : :
1251 : 0 : nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1252 : 0 : nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1253 : : }
1254 : 0 : pColumn = GetColumn( nCols-1 );
1255 : 0 : pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1256 : 0 : pColumn->SetRelColWidth( nRelTabWidth - nRel );
1257 : : }
1258 : : else
1259 : : {
1260 : 0 : sal_uLong nDistAbs = nAbsTabWidth - nRealMin;
1261 : 0 : sal_uLong nDistRel = nRelTabWidth - nRealMin;
1262 : 0 : sal_uLong nDistMin = nMin - nRealMin;
1263 : 0 : sal_uInt16 nAbs = 0, nRel = 0;
1264 : : SwHTMLTableLayoutColumn *pColumn;
1265 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols-1; i++ )
1266 : : {
1267 : 0 : pColumn = GetColumn( i );
1268 : 0 : sal_uLong nColMin = pColumn->GetMin();
1269 : 0 : sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2;
1270 : 0 : AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1271 : :
1272 [ # # ]: 0 : if( nColMin <= USHRT_MAX )
1273 : : {
1274 : : pColumn->SetAbsColWidth(
1275 : 0 : (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1276 : : pColumn->SetRelColWidth(
1277 : 0 : (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1278 : : }
1279 : : else
1280 : : {
1281 : 0 : double nColMinD = nColMin;
1282 : : pColumn->SetAbsColWidth(
1283 : 0 : (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1284 : : pColumn->SetRelColWidth(
1285 : 0 : (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1286 : : }
1287 : :
1288 : 0 : nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth();
1289 : 0 : nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth();
1290 : : }
1291 : 0 : pColumn = GetColumn( nCols-1 );
1292 : 0 : pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1293 : 0 : pColumn->SetRelColWidth( nRelTabWidth - nRel );
1294 : : }
1295 : : }
1296 [ # # ][ # # ]: 0 : else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
1297 : : {
1298 : : // If
1299 : : // - the table has a fixed width and the table's maximum is
1300 : : // smaller, or
1301 : : //- the maximum is smaller than the available space,
1302 : : // we can take over the maximum as it is. Respectively
1303 : : // the table can only be adapted to the fixed width by
1304 : : // respecting the maximum.
1305 : :
1306 : : // No fixed width, use the maximum.
1307 [ # # ]: 0 : if( !nAbsTabWidth )
1308 : 0 : nAbsTabWidth = (sal_uInt16)nMax;
1309 : :
1310 : : // A top table may also get wider then the available space.
1311 [ # # ]: 0 : if( nAbsTabWidth > nAbsAvail )
1312 : : {
1313 : : OSL_ENSURE( IsTopTable(),
1314 : : "Table in table should get wider than the surrounding cell." );
1315 : 0 : nAbsAvail = nAbsTabWidth;
1316 : : }
1317 : :
1318 : : // Only use the relative widths' fraction, that is used for the
1319 : : // absolute width.
1320 : 0 : sal_uLong nAbsTabWidthL = nAbsTabWidth;
1321 : : nRelTabWidth =
1322 : : ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1323 [ # # ]: 0 : : nAbsTabWidth );
1324 : :
1325 : : // Are there columns width a percentage setting and some without one?
1326 : 0 : sal_uLong nFixMax = nMax;
1327 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols; i++ )
1328 : : {
1329 : 0 : const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1330 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
[ # # ]
1331 : 0 : nFixMax -= pColumn->GetMax();
1332 : : }
1333 : :
1334 [ # # ][ # # ]: 0 : if( nFixMax > 0 && nFixMax < nMax )
1335 : : {
1336 : : // Yes, distribute the to-be-distributed space only to the
1337 : : // columns with a percentage setting.
1338 : :
1339 : : // In this case (and in this case only) there are columns
1340 : : // that exactly keep their maximum width, that is they neither
1341 : : // get smaller nor wider. When calculating the absolute width
1342 : : // from the relative width we can get rounding errors.
1343 : : // To correct this, we first make the fixed widths compensate for
1344 : : // this error. We then fix the relative widths the same way.
1345 : :
1346 : 0 : sal_uInt16 nAbs = 0, nRel = 0;
1347 : 0 : sal_uInt16 nFixedCols = 0;
1348 : : sal_uInt16 i;
1349 : :
1350 [ # # ]: 0 : for( i = 0; i < nCols; i++ )
1351 : : {
1352 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1353 [ # # ][ # # ]: 0 : if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
[ # # ]
1354 : : {
1355 : : // The column keeps it's width.
1356 : 0 : nFixedCols++;
1357 : 0 : sal_uLong nColMax = pColumn->GetMax();
1358 : 0 : pColumn->SetAbsColWidth( (sal_uInt16)nColMax );
1359 : :
1360 : : sal_uLong nRelColWidth =
1361 : 0 : (nColMax * nRelTabWidth) / nAbsTabWidth;
1362 : : sal_uLong nChkWidth =
1363 : 0 : (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
1364 [ # # ]: 0 : if( nChkWidth < nColMax )
1365 : 0 : nRelColWidth++;
1366 [ # # ]: 0 : else if( nChkWidth > nColMax )
1367 : 0 : nRelColWidth--;
1368 : 0 : pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth );
1369 : :
1370 : 0 : nAbs = nAbs + (sal_uInt16)nColMax;
1371 : 0 : nRel = nRel + (sal_uInt16)nRelColWidth;
1372 : : }
1373 : : }
1374 : :
1375 : : // The to-be-distributed percentage of the maximum, the
1376 : : // relative and absolute widths. Here, nFixMax corresponds
1377 : : // to nAbs, so that we could've called it nAbs.
1378 : : // The code is, however, more readable like that.
1379 : : OSL_ENSURE( nFixMax == nAbs, "Two loops, two sums?" );
1380 : 0 : sal_uLong nDistMax = nMax - nFixMax;
1381 : 0 : sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs;
1382 : 0 : sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel;
1383 : :
1384 [ # # ]: 0 : for( i=0; i<nCols; i++ )
1385 : : {
1386 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1387 [ # # ][ # # ]: 0 : if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
[ # # ]
1388 : : {
1389 : : // The column gets proportionately wider.
1390 : 0 : nFixedCols++;
1391 [ # # ]: 0 : if( nFixedCols == nCols )
1392 : : {
1393 : 0 : pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
1394 : 0 : pColumn->SetRelColWidth( nRelTabWidth-nRel );
1395 : : }
1396 : : else
1397 : : {
1398 : 0 : sal_uLong nColMax = pColumn->GetMax();
1399 : : pColumn->SetAbsColWidth(
1400 : 0 : (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) );
1401 : : pColumn->SetRelColWidth(
1402 : 0 : (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) );
1403 : : }
1404 : 0 : nAbs = nAbs + pColumn->GetAbsColWidth();
1405 : 0 : nRel = nRel + pColumn->GetRelColWidth();
1406 : : }
1407 : : }
1408 : 0 : OSL_ENSURE( nCols==nFixedCols, "Missed a column!" );
1409 : : }
1410 : : else
1411 : : {
1412 : : // No. So distribute the space regularily among all columns.
1413 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols; i++ )
1414 : : {
1415 : 0 : sal_uLong nColMax = GetColumn( i )->GetMax();
1416 : : GetColumn( i )->SetAbsColWidth(
1417 : 0 : (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) );
1418 : : GetColumn( i )->SetRelColWidth(
1419 : 0 : (sal_uInt16)((nColMax * nRelTabWidth) / nMax) );
1420 : : }
1421 : : }
1422 : : }
1423 : : else
1424 : : {
1425 : : // Proportionately distribute the space that extends over the minimum
1426 : : // width among the columns.
1427 [ # # ]: 0 : if( !nAbsTabWidth )
1428 : 0 : nAbsTabWidth = nAbsAvail;
1429 [ # # ]: 0 : if( nAbsTabWidth < nMin )
1430 : 0 : nAbsTabWidth = (sal_uInt16)nMin;
1431 : :
1432 [ # # ]: 0 : if( nAbsTabWidth > nAbsAvail )
1433 : : {
1434 : : OSL_ENSURE( IsTopTable(),
1435 : : "A nested table should become wider than the available space." );
1436 : 0 : nAbsAvail = nAbsTabWidth;
1437 : : }
1438 : :
1439 : 0 : sal_uLong nAbsTabWidthL = nAbsTabWidth;
1440 : : nRelTabWidth =
1441 : : ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1442 [ # # ]: 0 : : nAbsTabWidth );
1443 : 0 : double nW = nAbsTabWidth - nMin;
1444 [ # # ]: 0 : double nD = (nMax==nMin ? 1 : nMax-nMin);
1445 : 0 : sal_uInt16 nAbs = 0, nRel = 0;
1446 [ # # ]: 0 : for( sal_uInt16 i=0; i<nCols-1; i++ )
1447 : : {
1448 : 0 : double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
1449 : 0 : sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD);
1450 : : sal_uLong nRelColWidth = nRelAvail
1451 : : ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
1452 [ # # ]: 0 : : nAbsColWidth;
1453 : :
1454 : 0 : GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth );
1455 : 0 : GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth );
1456 : 0 : nAbs = nAbs + (sal_uInt16)nAbsColWidth;
1457 : 0 : nRel = nRel + (sal_uInt16)nRelColWidth;
1458 : : }
1459 : 0 : GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
1460 : 0 : GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
1461 : :
1462 : : }
1463 : :
1464 : : // Step 4: For nested tables we can have balancing cells on the
1465 : : // left or right. Here we calculate their width.
1466 : 0 : nInhAbsLeftSpace = 0;
1467 : 0 : nInhAbsRightSpace = 0;
1468 [ # # ][ # # ]: 0 : if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
[ # # ][ # # ]
[ # # ]
1469 : : nAbsTabWidth<nAbsAvail) )
1470 : : {
1471 : : // Calculate the width of additional cells we use for
1472 : : // aligning inner tables.
1473 : 0 : sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth);
1474 : 0 : sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth);
1475 : 0 : sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
1476 : :
1477 : : // Calculate the size and position of the additional cells.
1478 [ # # # ]: 0 : switch( eTableAdjust )
1479 : : {
1480 : : case SVX_ADJUST_RIGHT:
1481 : 0 : nAbsLeftFill = nAbsLeftFill + nAbsDist;
1482 : 0 : nRelLeftFill = nRelLeftFill + nRelDist;
1483 : 0 : nParentInhAbsLeftSpace = nParentInhAbsSpace;
1484 : 0 : break;
1485 : : case SVX_ADJUST_CENTER:
1486 : : {
1487 : 0 : sal_uInt16 nAbsLeftDist = nAbsDist / 2;
1488 : 0 : nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
1489 : 0 : nAbsRightFill += nAbsDist - nAbsLeftDist;
1490 : 0 : sal_uInt16 nRelLeftDist = nRelDist / 2;
1491 : 0 : nRelLeftFill = nRelLeftFill + nRelLeftDist;
1492 : 0 : nRelRightFill += nRelDist - nRelLeftDist;
1493 : 0 : nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
1494 : : nParentInhAbsRightSpace = nParentInhAbsSpace -
1495 : 0 : nParentInhAbsLeftSpace;
1496 : : }
1497 : 0 : break;
1498 : : case SVX_ADJUST_LEFT:
1499 : : default:
1500 : 0 : nAbsRightFill = nAbsRightFill + nAbsDist;
1501 : 0 : nRelRightFill = nRelRightFill + nRelDist;
1502 : 0 : nParentInhAbsRightSpace = nParentInhAbsSpace;
1503 : 0 : break;
1504 : : }
1505 : :
1506 : : OSL_ENSURE( !pLeftFillerBox || nRelLeftFill>0,
1507 : : "We don't have a width for the left filler box!" );
1508 : : OSL_ENSURE( !pRightFillerBox || nRelRightFill>0,
1509 : : "We don't have a width for the right filler box!" );
1510 : :
1511 : : // Filler widths are added to the outer columns, if there are no boxes
1512 : : // for them after the first pass (nWidth>0) or their width would become
1513 : : // too small or if there are COL tags and the filler width corresponds
1514 : : // to the border width.
1515 : : // In the last case we probably exported the table ourselves.
1516 [ # # ][ # # ]: 0 : if( nRelLeftFill && !pLeftFillerBox &&
[ # # ]
[ # # # # ]
[ # # ][ # # ]
1517 : : ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
1518 : 0 : (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
1519 : : {
1520 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
1521 : 0 : pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
1522 : 0 : pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
1523 : 0 : nRelLeftFill = 0;
1524 : 0 : nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
1525 : : }
1526 [ # # ][ # # ]: 0 : if( nRelRightFill && !pRightFillerBox &&
[ # # ]
[ # # # # ]
[ # # ][ # # ]
1527 : : ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
1528 : 0 : (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
1529 : : {
1530 : 0 : SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
1531 : 0 : pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
1532 : 0 : pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
1533 : 0 : nRelRightFill = 0;
1534 : 0 : nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
1535 : : }
1536 : : }
1537 : 0 : }
1538 : :
1539 : : static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth );
1540 : :
1541 : 0 : static void lcl_ResizeBox( const SwTableBox* pBox, sal_uInt16* pWidth )
1542 : : {
1543 [ # # ]: 0 : if( !pBox->GetSttNd() )
1544 : : {
1545 : 0 : sal_uInt16 nWidth = 0;
1546 [ # # ][ # # ]: 0 : BOOST_FOREACH( const SwTableLine *pLine, pBox->GetTabLines() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1547 [ # # ]: 0 : lcl_ResizeLine( pLine, &nWidth );
1548 [ # # ][ # # ]: 0 : pBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
[ # # ]
1549 : 0 : *pWidth = *pWidth + nWidth;
1550 : : }
1551 : : else
1552 : : {
1553 : 0 : *pWidth = *pWidth + (sal_uInt16)pBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
1554 : : }
1555 : 0 : }
1556 : :
1557 : 0 : static void lcl_ResizeLine( const SwTableLine* pLine, sal_uInt16 *pWidth )
1558 : : {
1559 : : #if OSL_DEBUG_LEVEL > 0
1560 : : sal_uInt16 nOldWidth = *pWidth;
1561 : : #endif
1562 : 0 : *pWidth = 0;
1563 [ # # ][ # # ]: 0 : BOOST_FOREACH( const SwTableBox* pBox, pLine->GetTabBoxes() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1564 [ # # ]: 0 : lcl_ResizeBox(pBox, pWidth );
1565 : :
1566 : : #if OSL_DEBUG_LEVEL > 0
1567 : : OSL_ENSURE( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
1568 : : "A box's rows have all a different length." );
1569 : : #endif
1570 : 0 : }
1571 : :
1572 : 0 : void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail,
1573 : : sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
1574 : : sal_uInt16 nAbsRightSpace,
1575 : : sal_uInt16 nParentInhAbsSpace )
1576 : : {
1577 : : // SetWidth must have been passed through once more for every cell in the
1578 : : // end.
1579 : 0 : nWidthSet++;
1580 : :
1581 : : // Step 0: If necessary, we call the layout algorithm of Pass2.
1582 [ # # ]: 0 : if( bCallPass2 )
1583 : : AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
1584 : 0 : nParentInhAbsSpace );
1585 : :
1586 : : // Step 1: Set the new width in all content boxes.
1587 : : // Because the boxes don't know anything about the HTML table structure,
1588 : : // we iterate over the HTML table structure.
1589 : : // For tables in tables in tables we call SetWidth recursively.
1590 [ # # ]: 0 : for( sal_uInt16 i=0; i<nRows; i++ )
1591 : : {
1592 [ # # ]: 0 : for( sal_uInt16 j=0; j<nCols; j++ )
1593 : : {
1594 : 0 : SwHTMLTableLayoutCell *pCell = GetCell( i, j );
1595 : :
1596 : 0 : SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
1597 [ # # ][ # # ]: 0 : while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
[ # # ]
1598 : : {
1599 : 0 : SwTableBox *pBox = pCntnts->GetTableBox();
1600 [ # # ]: 0 : if( pBox )
1601 : : {
1602 : 0 : SetBoxWidth( pBox, j, pCell->GetColSpan() );
1603 : : }
1604 : : else
1605 : : {
1606 : 0 : sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
1607 : 0 : nInhSpace = 0;
1608 [ # # ]: 0 : if( bCallPass2 )
1609 : : {
1610 : 0 : sal_uInt16 nColSpan = pCell->GetColSpan();
1611 : 0 : GetAvail( j, nColSpan, nAbs, nRel );
1612 : 0 : nLSpace = GetLeftCellSpace( j, nColSpan );
1613 : 0 : nRSpace = GetRightCellSpace( j, nColSpan );
1614 [ # # ]: 0 : nInhSpace = GetInhCellSpace( j, nColSpan );
1615 : : }
1616 : : pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
1617 : : nLSpace, nRSpace,
1618 [ # # ]: 0 : nInhSpace );
1619 : : }
1620 : :
1621 : 0 : pCntnts->SetWidthSet( nWidthSet );
1622 : 0 : pCntnts = pCntnts->GetNext();
1623 : : }
1624 : : }
1625 : : }
1626 : :
1627 : : // Step 2: If we have a top table, we adapt the formats of the
1628 : : // non-content-boxes. Because they are not known in the HTML table
1629 : : // due to garbage collection there, we need the iterate over the
1630 : : // whole table.
1631 : : // We also adapt the table frame format. For nested tables we set the
1632 : : // filler cell's width instead.
1633 [ # # ]: 0 : if( IsTopTable() )
1634 : : {
1635 : 0 : sal_uInt16 nCalcTabWidth = 0;
1636 [ # # ][ # # ]: 0 : BOOST_FOREACH( const SwTableLine *pLine, pSwTable->GetTabLines() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1637 [ # # ]: 0 : lcl_ResizeLine( pLine, &nCalcTabWidth );
1638 : : OSL_ENSURE( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
1639 : : "Table width is not equal to the row width." );
1640 : :
1641 : : // Lock the table format when altering it, or else the box formats
1642 : : // are altered again.
1643 : : // Also, we need to preserve a percent setting if it exists.
1644 : 0 : SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
1645 : 0 : ((SwTable *)pSwTable)->LockModify();
1646 [ # # ][ # # ]: 0 : SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
1647 : 0 : aFrmSize.SetWidth( nRelTabWidth );
1648 : : sal_Bool bRel = bUseRelWidth &&
1649 [ # # ][ # # ]: 0 : text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
[ # # ]
1650 [ # # ]: 0 : aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) );
1651 [ # # ]: 0 : pFrmFmt->SetFmtAttr( aFrmSize );
1652 : 0 : ((SwTable *)pSwTable)->UnlockModify();
1653 : :
1654 : : // If the table is located in a frame, we also need to adapt the
1655 : : // frame's width.
1656 [ # # ]: 0 : if( MayBeInFlyFrame() )
1657 : : {
1658 [ # # ]: 0 : SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
1659 [ # # ]: 0 : if( pFlyFrmFmt )
1660 : : {
1661 [ # # ]: 0 : SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
1662 : :
1663 [ # # ]: 0 : if( bUseRelWidth )
1664 : : {
1665 : : // For percentage settings we set the width to the minimum.
1666 : : aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX
1667 : 0 : : nMin );
1668 : 0 : aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption );
1669 : : }
1670 [ # # ][ # # ]: 0 : pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
1671 : : }
1672 [ # # ]: 0 : }
1673 : :
1674 : : #ifdef DBG_UTIL
1675 : : {
1676 : : // is located in tblrwcl.cxx
1677 : : extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1678 : :
1679 : : // check if the tables have correct widths
1680 : : SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
1681 : : const SwTableLines& rLines = pSwTable->GetTabLines();
1682 : : for (size_t n = 0; n < rLines.size(); ++n)
1683 : : {
1684 : : _CheckBoxWidth( *rLines[ n ], nSize );
1685 : : }
1686 : : }
1687 : : #endif
1688 : :
1689 : : }
1690 : : else
1691 : : {
1692 [ # # ]: 0 : if( pLeftFillerBox )
1693 : : {
1694 : 0 : pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
1695 [ # # ]: 0 : SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
1696 : : }
1697 [ # # ]: 0 : if( pRightFillerBox )
1698 : : {
1699 : 0 : pRightFillerBox->GetFrmFmt()->SetFmtAttr(
1700 [ # # ]: 0 : SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
1701 : : }
1702 : : }
1703 : 0 : }
1704 : :
1705 : 0 : void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1706 : : {
1707 : : // If bRecalc is set, the table's content changed.
1708 : : // We need to execute pass 1 again.
1709 [ # # ]: 0 : if( bRecalc )
1710 : 0 : AutoLayoutPass1();
1711 : :
1712 : 0 : SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout();
1713 [ # # ][ # # ]: 0 : if ( pRoot && pRoot->IsCallbackActionEnabled() )
[ # # ]
1714 : 0 : pRoot->StartAllAction(); //swmod 071108//swmod 071225
1715 : :
1716 : : // Else we can set the widths, in which we have to run Pass 2 in each case.
1717 : 0 : SetWidths( sal_True, nAbsAvail );
1718 : :
1719 [ # # ][ # # ]: 0 : if ( pRoot && pRoot->IsCallbackActionEnabled() )
[ # # ]
1720 : 0 : pRoot->EndAllAction( sal_True ); //True per VirDev (browsing is calmer) //swmod 071108//swmod 071225
1721 : 0 : }
1722 : :
1723 : 0 : IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
1724 : : {
1725 : 0 : pThis->aResizeTimer.Stop();
1726 : : pThis->_Resize( pThis->nDelayedResizeAbsAvail,
1727 : 0 : pThis->bDelayedResizeRecalc );
1728 : :
1729 : 0 : return 0;
1730 : : }
1731 : :
1732 : :
1733 : 0 : sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc,
1734 : : sal_Bool bForce, sal_uLong nDelay )
1735 : : {
1736 [ # # ]: 0 : if( 0 == nAbsAvail )
1737 : 0 : return sal_False;
1738 : : OSL_ENSURE( IsTopTable(), "Resize must only be called for top tables!" );
1739 : :
1740 : : // May the table be resized at all? Or is it forced?
1741 [ # # ][ # # ]: 0 : if( bMustNotResize && !bForce )
1742 : 0 : return sal_False;
1743 : :
1744 : : // May the table be recalculated? Or is it forced?
1745 [ # # ][ # # ]: 0 : if( bMustNotRecalc && !bForce )
1746 : 0 : bRecalc = sal_False;
1747 : :
1748 : 0 : const SwDoc *pDoc = GetDoc();
1749 : :
1750 : : // If there is a layout, the root frame's size instead of the
1751 : : // VisArea's size was potentially passed.
1752 : : // If we're not in a frame we need to calculate the table for the VisArea,
1753 : : // because switching from relative to absolute wouldn't work.
1754 [ # # ][ # # ]: 0 : if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() )
[ # # ]
1755 : : {
1756 : 0 : const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
1757 [ # # ][ # # ]: 0 : if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
[ # # ]
1758 : 0 : nAbsAvail = nVisAreaWidth;
1759 : : }
1760 : :
1761 [ # # ][ # # ]: 0 : if( nDelay==0 && aResizeTimer.IsActive() )
[ # # ]
1762 : : {
1763 : : // If there is an asynchronous resize left to process when we call
1764 : : // a synchronous resize, we only take over the new values.
1765 : 0 : bRecalc |= bDelayedResizeRecalc;
1766 : 0 : nDelayedResizeAbsAvail = nAbsAvail;
1767 : 0 : return sal_False;
1768 : : }
1769 : :
1770 : : // Optimisation:
1771 : : // If the minimums or maximums should not be recalculated and
1772 : : // - the table's width never needs to be recalculated, or
1773 : : // - the table was already calculated for the passed width, or
1774 : : // - the available space is less or equal to the minimum width
1775 : : // and the table already has the minimum width, or
1776 : : // - the available space is larger than the maximum width and
1777 : : // the table already has the maximum width
1778 : : // nothing will happen to the table.
1779 [ # # ][ # # ]: 0 : if( !bRecalc && ( !bMustResize ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1780 : : (nLastResizeAbsAvail==nAbsAvail) ||
1781 : : (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
1782 : 0 : (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
1783 : 0 : return sal_False;
1784 : :
1785 [ # # ]: 0 : if( nDelay==HTMLTABLE_RESIZE_NOW )
1786 : : {
1787 [ # # ]: 0 : if( aResizeTimer.IsActive() )
1788 : 0 : aResizeTimer.Stop();
1789 : 0 : _Resize( nAbsAvail, bRecalc );
1790 : : }
1791 [ # # ]: 0 : else if( nDelay > 0 )
1792 : : {
1793 : 0 : nDelayedResizeAbsAvail = nAbsAvail;
1794 : 0 : bDelayedResizeRecalc = bRecalc;
1795 : 0 : aResizeTimer.SetTimeout( nDelay );
1796 : 0 : aResizeTimer.Start();
1797 : : }
1798 : : else
1799 : : {
1800 : 0 : _Resize( nAbsAvail, bRecalc );
1801 : : }
1802 : :
1803 : 0 : return sal_True;
1804 : : }
1805 : :
1806 : 0 : void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc )
1807 : : {
1808 : 0 : bBordersChanged = sal_True;
1809 : :
1810 : 0 : Resize( nAbsAvail, bRecalc );
1811 : 0 : }
1812 : :
1813 : :
1814 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|