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