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