Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <editeng/boxitem.hxx>
22 : #include <editeng/brshitem.hxx>
23 : #include <tools/fract.hxx>
24 : #include <wrtswtbl.hxx>
25 : #include <swtable.hxx>
26 : #include <frmfmt.hxx>
27 : #include <fmtfsize.hxx>
28 : #include <fmtornt.hxx>
29 : #include <frmatr.hxx>
30 : #include <htmltbl.hxx>
31 :
32 : using ::editeng::SvxBorderLine;
33 : using namespace ::com::sun::star;
34 :
35 : //-----------------------------------------------------------------------
36 :
37 38 : sal_Int16 SwWriteTableCell::GetVertOri() const
38 : {
39 38 : sal_Int16 eCellVertOri = text::VertOrientation::TOP;
40 38 : if( pBox->GetSttNd() )
41 : {
42 38 : const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet();
43 : const SfxPoolItem *pItem;
44 38 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem ) )
45 : {
46 : sal_Int16 eBoxVertOri =
47 0 : ((const SwFmtVertOrient *)pItem)->GetVertOrient();
48 0 : if( text::VertOrientation::CENTER==eBoxVertOri || text::VertOrientation::BOTTOM==eBoxVertOri)
49 0 : eCellVertOri = eBoxVertOri;
50 : }
51 : }
52 :
53 38 : return eCellVertOri;
54 : }
55 :
56 : //-----------------------------------------------------------------------
57 :
58 24 : SwWriteTableRow::SwWriteTableRow( long nPosition, sal_Bool bUseLayoutHeights )
59 : : pBackground(0), nPos(nPosition), mbUseLayoutHeights(bUseLayoutHeights),
60 : nTopBorder(USHRT_MAX), nBottomBorder(USHRT_MAX), bTopBorder(true),
61 24 : bBottomBorder(true)
62 : {
63 24 : }
64 :
65 38 : SwWriteTableCell *SwWriteTableRow::AddCell( const SwTableBox *pBox,
66 : sal_uInt16 nRow, sal_uInt16 nCol,
67 : sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
68 : long nHeight,
69 : const SvxBrushItem *pBackgroundBrush )
70 : {
71 : SwWriteTableCell *pCell =
72 : new SwWriteTableCell( pBox, nRow, nCol, nRowSpan, nColSpan,
73 38 : nHeight, pBackgroundBrush );
74 38 : aCells.push_back( pCell );
75 :
76 38 : return pCell;
77 : }
78 :
79 : //-----------------------------------------------------------------------
80 :
81 69 : SwWriteTableCol::SwWriteTableCol(sal_uInt32 nPosition)
82 : : nPos(nPosition), nWidthOpt(0), bRelWidthOpt(false), bOutWidth(true),
83 69 : bLeftBorder(true), bRightBorder(true)
84 : {
85 69 : }
86 :
87 : //-----------------------------------------------------------------------
88 :
89 52 : sal_uInt32 SwWriteTable::GetBoxWidth( const SwTableBox *pBox )
90 : {
91 52 : const SwFrmFmt *pFmt = pBox->GetFrmFmt();
92 : const SwFmtFrmSize& aFrmSize=
93 52 : (const SwFmtFrmSize&)pFmt->GetFmtAttr( RES_FRM_SIZE );
94 :
95 52 : return sal::static_int_cast<sal_uInt32>(aFrmSize.GetSize().Width());
96 : }
97 :
98 24 : long SwWriteTable::GetLineHeight( const SwTableLine *pLine )
99 : {
100 : #ifdef DBG_UTIL
101 : sal_Bool bOldGetLineHeightCalled = m_bGetLineHeightCalled;
102 : m_bGetLineHeightCalled = sal_True;
103 : #endif
104 :
105 24 : long nHeight = 0;
106 24 : if( bUseLayoutHeights )
107 : {
108 : // Erstmal versuchen wir die Hoehe ueber das Layout zu bekommen
109 24 : bool bLayoutAvailable = false;
110 24 : nHeight = pLine->GetTableLineHeight(bLayoutAvailable);
111 24 : if( nHeight > 0 )
112 24 : return nHeight;
113 :
114 : // Wenn kein Layout gefunden wurde, gehen wir von festen Hoehen aus.
115 : // #i60390# - in some cases we still want to continue
116 : // to use the layout heights even if one of the rows has a height of 0
117 : // ('hidden' rows)
118 0 : bUseLayoutHeights = bLayoutAvailable; /*sal_False;*/
119 :
120 : #ifdef DBG_UTIL
121 : SAL_WARN_IF( !bLayoutAvailable && bOldGetLineHeightCalled, "sw", "Layout ungueltig?" );
122 : #endif
123 : }
124 :
125 0 : const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
126 0 : sal_uInt16 nBoxes = rBoxes.size();
127 :
128 0 : for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
129 : {
130 0 : const SwTableBox* pBox = rBoxes[nBox];
131 0 : if( pBox->GetSttNd() )
132 : {
133 0 : if( nHeight < ROW_DFLT_HEIGHT )
134 0 : nHeight = ROW_DFLT_HEIGHT;
135 : }
136 : else
137 : {
138 0 : long nTmp = 0;
139 0 : const SwTableLines &rLines = pBox->GetTabLines();
140 0 : for( sal_uInt16 nLine=0; nLine<rLines.size(); nLine++ )
141 : {
142 0 : nTmp += GetLineHeight( rLines[nLine] );
143 : }
144 0 : if( nHeight < nTmp )
145 0 : nHeight = nTmp;
146 : }
147 : }
148 :
149 0 : return nHeight;
150 : }
151 :
152 0 : long SwWriteTable::GetLineHeight( const SwTableBox *pBox ) const
153 : {
154 0 : const SwTableLine *pLine = pBox->GetUpper();
155 :
156 0 : if( !pLine )
157 0 : return 0;
158 :
159 0 : const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
160 : const SfxPoolItem* pItem;
161 0 : const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
162 :
163 0 : long nHeight = 0;
164 0 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem ))
165 0 : nHeight = ((SwFmtFrmSize*)pItem)->GetHeight();
166 :
167 0 : return nHeight;
168 : }
169 :
170 0 : const SvxBrushItem *SwWriteTable::GetLineBrush( const SwTableBox *pBox,
171 : SwWriteTableRow *pRow )
172 : {
173 0 : const SwTableLine *pLine = pBox->GetUpper();
174 :
175 0 : while( pLine )
176 : {
177 0 : const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
178 : const SfxPoolItem* pItem;
179 0 : const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
180 :
181 0 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
182 0 : &pItem ) )
183 : {
184 0 : if( !pLine->GetUpper() )
185 : {
186 0 : if( !pRow->GetBackground() )
187 0 : pRow->SetBackground( (const SvxBrushItem *)pItem );
188 0 : pItem = 0;
189 : }
190 :
191 0 : return (const SvxBrushItem *)pItem;
192 : }
193 :
194 0 : pBox = pLine->GetUpper();
195 0 : pLine = pBox ? pBox->GetUpper() : 0;
196 : }
197 :
198 0 : return 0;
199 : }
200 :
201 :
202 72 : void SwWriteTable::MergeBorders( const SvxBorderLine* pBorderLine,
203 : bool bTable )
204 : {
205 72 : if( (sal_uInt32)-1 == nBorderColor )
206 : {
207 2 : Color aGrayColor( COL_GRAY );
208 2 : if( !pBorderLine->GetColor().IsRGBEqual( aGrayColor ) )
209 2 : nBorderColor = pBorderLine->GetColor().GetColor();
210 : }
211 :
212 72 : if( !bCollectBorderWidth )
213 72 : return;
214 :
215 72 : sal_uInt16 nOutWidth = pBorderLine->GetOutWidth();
216 72 : if( bTable )
217 : {
218 26 : if( nOutWidth && (!nBorder || nOutWidth < nBorder) )
219 2 : nBorder = nOutWidth;
220 : }
221 : else
222 : {
223 46 : if( nOutWidth && (!nInnerBorder || nOutWidth < nInnerBorder) )
224 3 : nInnerBorder = nOutWidth;
225 : }
226 :
227 72 : sal_uInt16 nDist = pBorderLine->GetInWidth() ? pBorderLine->GetDistance()
228 72 : : 0;
229 72 : if( nDist && (!nCellSpacing || nDist < nCellSpacing) )
230 0 : nCellSpacing = nDist;
231 : }
232 :
233 :
234 38 : sal_uInt16 SwWriteTable::MergeBoxBorders( const SwTableBox *pBox,
235 : size_t const nRow, size_t const nCol,
236 : sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
237 : sal_uInt16& rTopBorder,
238 : sal_uInt16 &rBottomBorder )
239 : {
240 38 : sal_uInt16 nBorderMask = 0;
241 :
242 38 : const SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
243 38 : const SvxBoxItem& rBoxItem = (const SvxBoxItem&)pFrmFmt->GetFmtAttr( RES_BOX );
244 :
245 38 : if( rBoxItem.GetTop() )
246 : {
247 18 : nBorderMask |= 1;
248 18 : MergeBorders( rBoxItem.GetTop(), nRow==0 );
249 18 : rTopBorder = rBoxItem.GetTop()->GetOutWidth();
250 : }
251 :
252 38 : if( rBoxItem.GetLeft() )
253 : {
254 18 : nBorderMask |= 4;
255 18 : MergeBorders( rBoxItem.GetLeft(), nCol==0 );
256 : }
257 :
258 38 : if( rBoxItem.GetBottom() )
259 : {
260 18 : nBorderMask |= 2;
261 18 : MergeBorders( rBoxItem.GetBottom(), nRow+nRowSpan==aRows.size() );
262 18 : rBottomBorder = rBoxItem.GetBottom()->GetOutWidth();
263 : }
264 :
265 38 : if( rBoxItem.GetRight() )
266 : {
267 18 : nBorderMask |= 8;
268 18 : MergeBorders( rBoxItem.GetRight(), nCol+nColSpan==aCols.size() );
269 : }
270 :
271 : // If any distance is set, the smallest one is used. This holds for
272 : // the four distance of a box as well as for the distances of different
273 : // boxes.
274 38 : if( bCollectBorderWidth )
275 : {
276 38 : sal_uInt16 nDist = rBoxItem.GetDistance( BOX_LINE_TOP );
277 38 : if( nDist && (!nCellPadding || nDist < nCellPadding) )
278 0 : nCellPadding = nDist;
279 38 : nDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM );
280 38 : if( nDist && (!nCellPadding || nDist < nCellPadding) )
281 0 : nCellPadding = nDist;
282 38 : nDist = rBoxItem.GetDistance( BOX_LINE_LEFT );
283 38 : if( nDist && (!nCellPadding || nDist < nCellPadding) )
284 4 : nCellPadding = nDist;
285 38 : nDist = rBoxItem.GetDistance( BOX_LINE_RIGHT );
286 38 : if( nDist && (!nCellPadding || nDist < nCellPadding) )
287 3 : nCellPadding = nDist;
288 : }
289 :
290 38 : return nBorderMask;
291 : }
292 :
293 :
294 0 : sal_uInt32 SwWriteTable::GetRawWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
295 : {
296 0 : sal_uInt32 nWidth = aCols[nCol+nColSpan-1]->GetPos();
297 0 : if( nCol > 0 )
298 0 : nWidth = nWidth - aCols[nCol-1]->GetPos();
299 :
300 0 : return nWidth;
301 : }
302 :
303 0 : sal_uInt16 SwWriteTable::GetLeftSpace( sal_uInt16 nCol ) const
304 : {
305 0 : sal_uInt16 nSpace = nCellPadding + nCellSpacing;
306 :
307 : // In der ersten Spalte auch noch die Liniendicke abziehen
308 0 : if( nCol==0 )
309 : {
310 0 : nSpace = nSpace + nLeftSub;
311 :
312 0 : const SwWriteTableCol *pCol = aCols[nCol];
313 0 : if( pCol->HasLeftBorder() )
314 0 : nSpace = nSpace + nBorder;
315 : }
316 :
317 0 : return nSpace;
318 : }
319 :
320 : sal_uInt16
321 0 : SwWriteTable::GetRightSpace(size_t const nCol, sal_uInt16 nColSpan) const
322 : {
323 0 : sal_uInt16 nSpace = nCellPadding;
324 :
325 : // In der letzten Spalte noch einmal zusaetzlich CELLSPACING und
326 : // und die Liniendicke abziehen
327 0 : if( nCol+nColSpan==aCols.size() )
328 : {
329 0 : nSpace += (nCellSpacing + nRightSub);
330 :
331 0 : const SwWriteTableCol *pCol = aCols[nCol+nColSpan-1];
332 0 : if( pCol->HasRightBorder() )
333 0 : nSpace = nSpace + nBorder;
334 : }
335 :
336 0 : return nSpace;
337 : }
338 :
339 0 : sal_uInt16 SwWriteTable::GetAbsWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
340 : {
341 0 : sal_uInt32 nWidth = GetRawWidth( nCol, nColSpan );
342 0 : if( nBaseWidth != nTabWidth )
343 : {
344 0 : nWidth *= nTabWidth;
345 0 : nWidth /= nBaseWidth;
346 : }
347 :
348 0 : nWidth -= GetLeftSpace( nCol ) + GetRightSpace( nCol, nColSpan );
349 :
350 : OSL_ENSURE( nWidth > 0, "Spaltenbreite <= 0. OK?" );
351 0 : return nWidth > 0 ? (sal_uInt16)nWidth : 0;
352 : }
353 :
354 0 : sal_uInt16 SwWriteTable::GetRelWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
355 : {
356 0 : long nWidth = GetRawWidth( nCol, nColSpan );
357 :
358 0 : return (sal_uInt16)(long)Fraction( nWidth*256 + GetBaseWidth()/2,
359 0 : GetBaseWidth() );
360 : }
361 :
362 0 : sal_uInt16 SwWriteTable::GetPrcWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const
363 : {
364 0 : long nWidth = GetRawWidth( nCol, nColSpan );
365 :
366 : // sieht komisch aus, ist aber nichts anderes als
367 : // [(100 * nWidth) + .5] ohne Rundungsfehler
368 0 : return (sal_uInt16)(long)Fraction( nWidth*100 + GetBaseWidth()/2,
369 0 : GetBaseWidth() );
370 : }
371 :
372 0 : long SwWriteTable::GetAbsHeight(long nRawHeight, size_t const nRow,
373 : sal_uInt16 nRowSpan ) const
374 : {
375 0 : nRawHeight -= (2*nCellPadding + nCellSpacing);
376 :
377 : // In der ersten Zeile noch einmal zusaetzlich CELLSPACING und
378 : // und die Liniendicke abziehen
379 0 : const SwWriteTableRow *pRow = 0;
380 0 : if( nRow==0 )
381 : {
382 0 : nRawHeight -= nCellSpacing;
383 0 : pRow = aRows[nRow];
384 0 : if( pRow->HasTopBorder() )
385 0 : nRawHeight -= nBorder;
386 : }
387 :
388 : // In der letzten Zeile noch die Liniendicke abziehen
389 0 : if( nRow+nRowSpan==aRows.size() )
390 : {
391 0 : if( !pRow || nRowSpan > 1 )
392 0 : pRow = aRows[nRow+nRowSpan-1];
393 0 : if( pRow->HasBottomBorder() )
394 0 : nRawHeight -= nBorder;
395 : }
396 :
397 : OSL_ENSURE( nRawHeight > 0, "Zeilenheohe <= 0. OK?" );
398 0 : return nRawHeight > 0 ? nRawHeight : 0;
399 : }
400 :
401 76 : sal_Bool SwWriteTable::ShouldExpandSub(const SwTableBox *pBox, sal_Bool /*bExpandedBefore*/,
402 : sal_uInt16 nDepth) const
403 : {
404 76 : return !pBox->GetSttNd() && nDepth > 0;
405 : }
406 :
407 5 : void SwWriteTable::CollectTableRowsCols( long nStartRPos,
408 : sal_uInt32 nStartCPos,
409 : long nParentLineHeight,
410 : sal_uInt32 nParentLineWidth,
411 : const SwTableLines& rLines,
412 : sal_uInt16 nDepth )
413 : {
414 5 : sal_Bool bSubExpanded = sal_False;
415 5 : sal_uInt16 nLines = rLines.size();
416 :
417 : #if OSL_DEBUG_LEVEL > 0
418 : sal_uInt32 nEndCPos = 0;
419 : #endif
420 :
421 5 : long nRPos = nStartRPos;
422 17 : for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
423 : {
424 12 : /*const*/ SwTableLine *pLine = rLines[nLine];
425 :
426 12 : long nOldRPos = nRPos;
427 :
428 12 : if( nLine < nLines-1 || nParentLineHeight==0 )
429 : {
430 12 : long nLineHeight = GetLineHeight( pLine );
431 12 : nRPos += nLineHeight;
432 12 : if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
433 : {
434 : /* If you have corrupt line height information, e.g. breaking rows in complex table
435 : layout, you may run into this robust code.
436 : It's not allowed that subrows leaves their parentrow. If this would happen the line
437 : height of subrow is reduced to a part of the remaining height */
438 : OSL_FAIL( "Corrupt line height I" );
439 0 : nRPos -= nLineHeight;
440 0 : nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
441 0 : nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
442 0 : nRPos += nLineHeight;
443 : }
444 12 : SwWriteTableRow *pRow = new SwWriteTableRow( nRPos, bUseLayoutHeights);
445 12 : if( !aRows.insert( pRow ).second )
446 0 : delete pRow;
447 : }
448 : else
449 : {
450 : #if OSL_DEBUG_LEVEL > 0
451 : long nCheckPos = nRPos + GetLineHeight( pLine );
452 : #endif
453 0 : nRPos = nStartRPos + nParentLineHeight;
454 : #if OSL_DEBUG_LEVEL > 0
455 : SwWriteTableRow aSrchRow( nRPos, bUseLayoutHeights );
456 : OSL_ENSURE( aRows.find( &aSrchRow ) != aRows.end(), "Parent-Zeile nicht gefunden" );
457 : SwWriteTableRow aRowCheckPos(nCheckPos,bUseLayoutHeights);
458 : SwWriteTableRow aRowRPos(nRPos,bUseLayoutHeights);
459 : OSL_ENSURE( !bUseLayoutHeights ||
460 : aRowCheckPos == aRowRPos,
461 : "Hoehe der Zeilen stimmt nicht mit Parent ueberein" );
462 : #endif
463 : }
464 :
465 : // Fuer alle Boxen der Zeile ggf. eine Spalte einfuegen
466 12 : const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
467 12 : sal_uInt16 nBoxes = rBoxes.size();
468 :
469 12 : sal_uInt32 nCPos = nStartCPos;
470 50 : for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
471 : {
472 38 : const SwTableBox *pBox = rBoxes[nBox];
473 :
474 38 : sal_uInt32 nOldCPos = nCPos;
475 :
476 38 : if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
477 : {
478 26 : nCPos = nCPos + GetBoxWidth( pBox );
479 26 : SwWriteTableCol *pCol = new SwWriteTableCol( nCPos );
480 :
481 26 : if( !aCols.insert( pCol ).second )
482 15 : delete pCol;
483 :
484 26 : if( nBox==nBoxes-1 )
485 : {
486 : OSL_ENSURE( nLine==0 && nParentLineWidth==0,
487 : "Jetzt wird die Parent-Breite plattgemacht!" );
488 0 : nParentLineWidth = nCPos-nStartCPos;
489 26 : }
490 : }
491 : else
492 : {
493 : #if OSL_DEBUG_LEVEL > 0
494 : sal_uInt32 nCheckPos = nCPos + GetBoxWidth( pBox );
495 : if( !nEndCPos )
496 : {
497 : nEndCPos = nCheckPos;
498 : }
499 : else
500 : {
501 : OSL_ENSURE( SwWriteTableCol(nCheckPos) ==
502 : SwWriteTableCol(nEndCPos),
503 : "Zelle enthaelt unterschiedlich breite Zeilen" );
504 : }
505 : #endif
506 12 : nCPos = nStartCPos + nParentLineWidth;
507 :
508 : #if OSL_DEBUG_LEVEL > 0
509 : SwWriteTableCol aSrchCol( nCPos );
510 : OSL_ENSURE( aCols.find( &aSrchCol ) != aCols.end(),
511 : "Parent-Zelle nicht gefunden" );
512 : OSL_ENSURE( SwWriteTableCol(nCheckPos) ==
513 : SwWriteTableCol(nCPos),
514 : "Breite der Zellen stimmt nicht mit Parent ueberein" );
515 : #endif
516 : }
517 :
518 38 : if( ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
519 : {
520 : CollectTableRowsCols( nOldRPos, nOldCPos,
521 : nRPos - nOldRPos,
522 : nCPos - nOldCPos,
523 0 : pBox->GetTabLines(),
524 0 : nDepth-1 );
525 0 : bSubExpanded = sal_True;
526 : }
527 : }
528 : }
529 5 : }
530 :
531 :
532 5 : void SwWriteTable::FillTableRowsCols( long nStartRPos, sal_uInt16 nStartRow,
533 : sal_uInt32 nStartCPos, sal_uInt16 nStartCol,
534 : long nParentLineHeight,
535 : sal_uInt32 nParentLineWidth,
536 : const SwTableLines& rLines,
537 : const SvxBrushItem* pParentBrush,
538 : sal_uInt16 nDepth,
539 : sal_uInt16 nNumOfHeaderRows )
540 : {
541 5 : sal_uInt16 nLines = rLines.size();
542 5 : sal_Bool bSubExpanded = sal_False;
543 :
544 : // Festlegen der Umrandung
545 5 : long nRPos = nStartRPos;
546 5 : sal_uInt16 nRow = nStartRow;
547 :
548 17 : for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
549 : {
550 12 : const SwTableLine *pLine = rLines[nLine];
551 :
552 : // Position der letzten ueberdeckten Zeile ermitteln
553 12 : long nOldRPos = nRPos;
554 12 : if( nLine < nLines-1 || nParentLineHeight==0 )
555 : {
556 12 : long nLineHeight = GetLineHeight( pLine );
557 12 : nRPos += nLineHeight;
558 12 : if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos )
559 : {
560 : /* See comment in CollectTableRowCols */
561 : OSL_FAIL( "Corrupt line height II" );
562 0 : nRPos -= nLineHeight;
563 0 : nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height
564 0 : nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows
565 0 : nRPos += nLineHeight;
566 12 : }
567 : }
568 : else
569 0 : nRPos = nStartRPos + nParentLineHeight;
570 :
571 : // Und ihren Index
572 12 : sal_uInt16 nOldRow = nRow;
573 12 : SwWriteTableRow aSrchRow( nRPos,bUseLayoutHeights );
574 12 : SwWriteTableRows::const_iterator it2 = aRows.find( &aSrchRow );
575 : OSL_ENSURE( it2 != aRows.end(), "missing row" );
576 12 : nRow = it2 - aRows.begin();
577 :
578 : OSL_ENSURE( nOldRow <= nRow, "Don't look back!" );
579 12 : if( nOldRow > nRow )
580 : {
581 0 : nOldRow = nRow;
582 0 : if( nOldRow )
583 0 : --nOldRow;
584 : }
585 :
586 :
587 12 : SwWriteTableRow *pRow = aRows[nOldRow];
588 12 : SwWriteTableRow *pEndRow = aRows[nRow];
589 12 : if( nLine+1==nNumOfHeaderRows && nParentLineHeight==0 )
590 0 : nHeadEndRow = nRow;
591 :
592 12 : const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
593 :
594 12 : const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt();
595 : const SfxPoolItem* pItem;
596 12 : const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet();
597 :
598 12 : long nHeight = 0;
599 12 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem ))
600 0 : nHeight = ((SwFmtFrmSize*)pItem)->GetHeight();
601 :
602 :
603 12 : const SvxBrushItem *pBrushItem, *pLineBrush = pParentBrush;
604 12 : if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False,
605 12 : &pItem ) )
606 : {
607 0 : pLineBrush = (const SvxBrushItem *)pItem;
608 :
609 : // Wenn die Zeile die gesamte Tabelle umspannt, koennen
610 : // Wir den Hintergrund an der Zeile ausgeben. Sonst muessen
611 : // wir in an den Zelle ausgeben.
612 0 : sal_Bool bOutAtRow = !nParentLineWidth;
613 0 : if( !bOutAtRow && nStartCPos==0 )
614 : {
615 0 : SwWriteTableCol aCol( nParentLineWidth );
616 0 : bOutAtRow = aCols.find( &aCol ) == (aCols.end() - 1);
617 : }
618 0 : if( bOutAtRow )
619 : {
620 0 : pRow->SetBackground( pLineBrush );
621 0 : pBrushItem = 0;
622 : }
623 : else
624 0 : pBrushItem = pLineBrush;
625 : }
626 : else
627 : {
628 12 : pRow->SetBackground( pLineBrush );
629 12 : pBrushItem = 0;
630 : }
631 :
632 12 : sal_uInt16 nBoxes = rBoxes.size();
633 12 : sal_uInt32 nCPos = nStartCPos;
634 12 : sal_uInt16 nCol = nStartCol;
635 :
636 50 : for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ )
637 : {
638 38 : const SwTableBox *pBox = rBoxes[nBox];
639 :
640 : // Position der letzten ueberdeckten Spalte ermitteln
641 38 : sal_uInt32 nOldCPos = nCPos;
642 38 : if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) )
643 : {
644 26 : nCPos = nCPos + GetBoxWidth( pBox );
645 52 : if( nBox==nBoxes-1 )
646 0 : nParentLineWidth = nCPos - nStartCPos;
647 : }
648 : else
649 12 : nCPos = nStartCPos + nParentLineWidth;
650 :
651 : // Und ihren Index
652 38 : sal_uInt16 nOldCol = nCol;
653 38 : SwWriteTableCol aSrchCol( nCPos );
654 38 : SwWriteTableCols::const_iterator it = aCols.find( &aSrchCol );
655 : OSL_ENSURE( it != aCols.end(), "missing column" );
656 38 : nCol = it - aCols.begin();
657 :
658 38 : if( !ShouldExpandSub( pBox, bSubExpanded, nDepth ) )
659 : {
660 38 : sal_uInt16 nRowSpan = nRow - nOldRow + 1;
661 :
662 : // The new table model may have true row span attributes
663 38 : const long nAttrRowSpan = pBox->getRowSpan();
664 38 : if ( 1 < nAttrRowSpan )
665 0 : nRowSpan = (sal_uInt16)nAttrRowSpan;
666 38 : else if ( nAttrRowSpan < 1 )
667 0 : nRowSpan = 0;
668 :
669 38 : sal_uInt16 nColSpan = nCol - nOldCol + 1;
670 : pRow->AddCell( pBox, nOldRow, nOldCol,
671 : nRowSpan, nColSpan, nHeight,
672 38 : pBrushItem );
673 38 : nHeight = 0; // Die Hoehe braucht nur einmal geschieben werden
674 :
675 38 : if( pBox->GetSttNd() )
676 : {
677 38 : sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
678 : sal_uInt16 nBorderMask = MergeBoxBorders(pBox, nOldRow, nOldCol,
679 38 : nRowSpan, nColSpan, nTopBorder, nBottomBorder);
680 :
681 : // #i30094# add a sanity check here to ensure that
682 : // we don't access an invalid aCols[] as &nCol
683 : // above can be changed.
684 38 : if (!(nBorderMask & 4) && nOldCol < aCols.size())
685 : {
686 20 : SwWriteTableCol *pCol = aCols[nOldCol];
687 : OSL_ENSURE(pCol, "No TableCol found, panic!");
688 20 : if (pCol)
689 20 : pCol->bLeftBorder = false;
690 : }
691 :
692 38 : if (!(nBorderMask & 8))
693 : {
694 20 : SwWriteTableCol *pCol = aCols[nCol];
695 : OSL_ENSURE(pCol, "No TableCol found, panic!");
696 20 : if (pCol)
697 20 : pCol->bRightBorder = false;
698 : }
699 :
700 38 : if (!(nBorderMask & 1))
701 20 : pRow->bTopBorder = false;
702 18 : else if (!pRow->nTopBorder || nTopBorder < pRow->nTopBorder)
703 6 : pRow->nTopBorder = nTopBorder;
704 :
705 38 : if (!(nBorderMask & 2))
706 20 : pEndRow->bBottomBorder = false;
707 18 : else if (
708 18 : !pEndRow->nBottomBorder ||
709 : nBottomBorder < pEndRow->nBottomBorder
710 : )
711 : {
712 6 : pEndRow->nBottomBorder = nBottomBorder;
713 : }
714 : }
715 : }
716 : else
717 : {
718 : FillTableRowsCols( nOldRPos, nOldRow, nOldCPos, nOldCol,
719 : nRPos-nOldRPos, nCPos-nOldCPos,
720 0 : pBox->GetTabLines(),
721 : pLineBrush, nDepth-1,
722 0 : nNumOfHeaderRows );
723 0 : bSubExpanded = sal_True;
724 : }
725 :
726 38 : nCol++; // Die naechste Zelle faengt in der nachten Spalte an
727 : }
728 :
729 12 : nRow++;
730 12 : }
731 5 : }
732 :
733 5 : SwWriteTable::SwWriteTable(const SwTableLines& rLines, long nWidth,
734 : sal_uInt32 nBWidth, bool bRel, sal_uInt16 nMaxDepth, sal_uInt16 nLSub, sal_uInt16 nRSub, sal_uInt32 nNumOfRowsToRepeat)
735 : : nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0),
736 : nInnerBorder(0), nBaseWidth(nBWidth), nHeadEndRow(USHRT_MAX),
737 : nLeftSub(nLSub), nRightSub(nRSub), nTabWidth(nWidth), bRelWidths(bRel),
738 : bUseLayoutHeights(true),
739 : #ifdef DBG_UTIL
740 : m_bGetLineHeightCalled(false),
741 : #endif
742 : bColsOption(false), bColTags(true), bLayoutExport(false),
743 5 : bCollectBorderWidth(true)
744 : {
745 5 : sal_uInt32 nParentWidth = nBaseWidth + nLeftSub + nRightSub;
746 :
747 : // Erstmal die Tabellen-Struktur festlegen. Hinter der Tabelle ist in
748 : // jedem Fall eine Spalte zu Ende
749 5 : SwWriteTableCol *pCol = new SwWriteTableCol( nParentWidth );
750 5 : aCols.insert( pCol );
751 5 : CollectTableRowsCols( 0, 0, 0, nParentWidth, rLines, nMaxDepth - 1 );
752 :
753 : // Und jetzt mit leben fuellen
754 5 : FillTableRowsCols( 0, 0, 0, 0, 0, nParentWidth, rLines, 0, nMaxDepth - 1, static_cast< sal_uInt16 >(nNumOfRowsToRepeat) );
755 :
756 : // Einige Twip-Werte an Pixel-Grenzen anpassen
757 5 : if( !nBorder )
758 3 : nBorder = nInnerBorder;
759 5 : }
760 :
761 0 : SwWriteTable::SwWriteTable( const SwHTMLTableLayout *pLayoutInfo )
762 : : nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0),
763 0 : nInnerBorder(0), nBaseWidth(pLayoutInfo->GetWidthOption()), nHeadEndRow(0),
764 0 : nLeftSub(0), nRightSub(0), nTabWidth(pLayoutInfo->GetWidthOption()),
765 0 : bRelWidths(pLayoutInfo->HasPrcWidthOption()), bUseLayoutHeights(false),
766 : #ifdef DBG_UTIL
767 : m_bGetLineHeightCalled(false),
768 : #endif
769 0 : bColsOption(pLayoutInfo->HasColsOption()),
770 0 : bColTags(pLayoutInfo->HasColTags()), bLayoutExport(true),
771 0 : bCollectBorderWidth(pLayoutInfo->HaveBordersChanged())
772 : {
773 0 : if( !bCollectBorderWidth )
774 : {
775 0 : nBorder = pLayoutInfo->GetBorder();
776 0 : nCellPadding = pLayoutInfo->GetCellPadding();
777 0 : nCellSpacing = pLayoutInfo->GetCellSpacing();
778 : }
779 :
780 : sal_uInt16 nRow, nCol;
781 0 : sal_uInt16 nCols = pLayoutInfo->GetColCount();
782 0 : sal_uInt16 nRows = pLayoutInfo->GetRowCount();
783 :
784 : // Erstmal die Tabellen-Struktur festlegen.
785 0 : for( nCol=0; nCol<nCols; nCol++ )
786 : {
787 : SwWriteTableCol *pCol =
788 0 : new SwWriteTableCol( (nCol+1)*COL_DFLT_WIDTH );
789 :
790 0 : if( bColTags )
791 : {
792 : const SwHTMLTableLayoutColumn *pLayoutCol =
793 0 : pLayoutInfo->GetColumn( nCol );
794 0 : pCol->SetWidthOpt( pLayoutCol->GetWidthOption(),
795 0 : pLayoutCol->IsRelWidthOption() );
796 : }
797 :
798 0 : aCols.insert( pCol );
799 : }
800 :
801 0 : for( nRow=0; nRow<nRows; nRow++ )
802 : {
803 : SwWriteTableRow *pRow =
804 0 : new SwWriteTableRow( (nRow+1)*ROW_DFLT_HEIGHT, bUseLayoutHeights );
805 0 : pRow->nTopBorder = 0;
806 0 : pRow->nBottomBorder = 0;
807 0 : aRows.insert( pRow );
808 : }
809 :
810 : // Und jetzt mit leben fuellen
811 0 : for( nRow=0; nRow<nRows; nRow++ )
812 : {
813 0 : SwWriteTableRow *pRow = aRows[nRow];
814 :
815 0 : sal_Bool bHeightExported = sal_False;
816 0 : for( nCol=0; nCol<nCols; nCol++ )
817 : {
818 : const SwHTMLTableLayoutCell *pLayoutCell =
819 0 : pLayoutInfo->GetCell( nRow, nCol );
820 :
821 : const SwHTMLTableLayoutCnts *pLayoutCnts =
822 0 : pLayoutCell->GetContents();
823 :
824 : // Beginnt die Zelle eigentlich eine Zeile weiter oben oder
825 : // weiter vorne?
826 0 : if( ( nRow>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow-1,nCol)
827 0 : ->GetContents() ) ||
828 : ( nCol>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow,nCol-1)
829 0 : ->GetContents() ) )
830 : {
831 0 : continue;
832 : }
833 :
834 0 : sal_uInt16 nRowSpan = pLayoutCell->GetRowSpan();
835 0 : sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
836 0 : const SwTableBox *pBox = pLayoutCnts->GetTableBox();
837 : OSL_ENSURE( pBox,
838 : "Tabelle in Tabelle kann nicht ueber Layout exportiert werden" );
839 :
840 0 : long nHeight = bHeightExported ? 0 : GetLineHeight( pBox );
841 0 : const SvxBrushItem *pBrushItem = GetLineBrush( pBox, pRow );
842 :
843 : SwWriteTableCell *pCell =
844 : pRow->AddCell( pBox, nRow, nCol, nRowSpan, nColSpan,
845 0 : nHeight, pBrushItem );
846 0 : pCell->SetWidthOpt( pLayoutCell->GetWidthOption(),
847 0 : pLayoutCell->IsPrcWidthOption() );
848 :
849 0 : sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX;
850 : sal_uInt16 nBorderMask =
851 : MergeBoxBorders( pBox, nRow, nCol, nRowSpan, nColSpan,
852 0 : nTopBorder, nBottomBorder );
853 :
854 0 : SwWriteTableCol *pCol = aCols[nCol];
855 0 : if( !(nBorderMask & 4) )
856 0 : pCol->bLeftBorder = false;
857 :
858 0 : pCol = aCols[nCol+nColSpan-1];
859 0 : if( !(nBorderMask & 8) )
860 0 : pCol->bRightBorder = false;
861 :
862 0 : if( !(nBorderMask & 1) )
863 0 : pRow->bTopBorder = false;
864 :
865 0 : SwWriteTableRow *pEndRow = aRows[nRow+nRowSpan-1];
866 0 : if( !(nBorderMask & 2) )
867 0 : pEndRow->bBottomBorder = false;
868 :
869 : // Die Hoehe braucht nur einmal geschieben werden
870 0 : if( nHeight )
871 0 : bHeightExported = sal_True;
872 : }
873 : }
874 :
875 : // Einige Twip-Werte an Pixel-Grenzen anpassen
876 0 : if( bCollectBorderWidth && !nBorder )
877 0 : nBorder = nInnerBorder;
878 0 : }
879 :
880 10 : SwWriteTable::~SwWriteTable()
881 : {
882 10 : }
883 :
884 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|