| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| #include <hintids.hxx> |
| #include <tools/debug.hxx> |
| #include <editeng/boxitem.hxx> |
| #include <editeng/brshitem.hxx> |
| #include <tools/fract.hxx> |
| #include <wrtswtbl.hxx> |
| #include <swtable.hxx> |
| #include <frmfmt.hxx> |
| #include <fmtfsize.hxx> |
| #include <fmtornt.hxx> |
| #include <frmatr.hxx> |
| #include <htmltbl.hxx> |
| |
| using namespace ::com::sun::star; |
| |
| SV_IMPL_PTRARR( SwWriteTableCells, SwWriteTableCellPtr ) |
| SV_IMPL_OP_PTRARR_SORT( SwWriteTableRows, SwWriteTableRowPtr ) |
| SV_IMPL_OP_PTRARR_SORT( SwWriteTableCols, SwWriteTableColPtr ) |
| |
| //----------------------------------------------------------------------- |
| |
| sal_Int16 SwWriteTableCell::GetVertOri() const |
| { |
| sal_Int16 eCellVertOri = text::VertOrientation::TOP; |
| if( pBox->GetSttNd() ) |
| { |
| const SfxItemSet& rItemSet = pBox->GetFrmFmt()->GetAttrSet(); |
| const SfxPoolItem *pItem; |
| if( SFX_ITEM_SET == rItemSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem ) ) |
| { |
| sal_Int16 eBoxVertOri = |
| ((const SwFmtVertOrient *)pItem)->GetVertOrient(); |
| if( text::VertOrientation::CENTER==eBoxVertOri || text::VertOrientation::BOTTOM==eBoxVertOri) |
| eCellVertOri = eBoxVertOri; |
| } |
| } |
| |
| return eCellVertOri; |
| } |
| |
| //----------------------------------------------------------------------- |
| |
| SwWriteTableRow::SwWriteTableRow( long nPosition, sal_Bool bUseLayoutHeights ) |
| : pBackground(0), nPos(nPosition), mbUseLayoutHeights(bUseLayoutHeights), |
| nTopBorder(USHRT_MAX), nBottomBorder(USHRT_MAX), bTopBorder(true), |
| bBottomBorder(true) |
| { |
| } |
| |
| SwWriteTableCell *SwWriteTableRow::AddCell( const SwTableBox *pBox, |
| sal_uInt16 nRow, sal_uInt16 nCol, |
| sal_uInt16 nRowSpan, sal_uInt16 nColSpan, |
| long nHeight, |
| const SvxBrushItem *pBackgroundBrush ) |
| { |
| SwWriteTableCell *pCell = |
| new SwWriteTableCell( pBox, nRow, nCol, nRowSpan, nColSpan, |
| nHeight, pBackgroundBrush ); |
| aCells.Insert( pCell, aCells.Count() ); |
| |
| return pCell; |
| } |
| |
| //----------------------------------------------------------------------- |
| |
| SwWriteTableCol::SwWriteTableCol(sal_uInt32 nPosition) |
| : nPos(nPosition), nWidthOpt(0), bRelWidthOpt(false), bOutWidth(true), |
| bLeftBorder(true), bRightBorder(true) |
| { |
| } |
| |
| //----------------------------------------------------------------------- |
| |
| sal_uInt32 SwWriteTable::GetBoxWidth( const SwTableBox *pBox ) |
| { |
| const SwFrmFmt *pFmt = pBox->GetFrmFmt(); |
| const SwFmtFrmSize& aFrmSize= |
| (const SwFmtFrmSize&)pFmt->GetFmtAttr( RES_FRM_SIZE ); |
| |
| return sal::static_int_cast<sal_uInt32>(aFrmSize.GetSize().Width()); |
| } |
| |
| long SwWriteTable::GetLineHeight( const SwTableLine *pLine ) |
| { |
| #ifdef DBG_UTIL |
| sal_Bool bOldGetLineHeightCalled = bGetLineHeightCalled; |
| bGetLineHeightCalled = sal_True; |
| #endif |
| |
| long nHeight = 0; |
| if( bUseLayoutHeights ) |
| { |
| // Erstmal versuchen wir die Hoehe ueber das Layout zu bekommen |
| bool bLayoutAvailable = false; |
| nHeight = pLine->GetTableLineHeight(bLayoutAvailable); |
| if( nHeight > 0 ) |
| return nHeight; |
| |
| // Wenn kein Layout gefunden wurde, gehen wir von festen Hoehen aus. |
| // --> FME 2007-3-26 #i60390# in some cases we still want to continue |
| // to use the layout heights even if one of the rows has a height of 0 |
| // ('hidden' rows) |
| // <-- |
| bUseLayoutHeights = bLayoutAvailable; /*sal_False;*/ |
| |
| #ifdef DBG_UTIL |
| ASSERT( bLayoutAvailable || !bOldGetLineHeightCalled, "Layout ungueltig?" ); |
| #endif |
| } |
| |
| const SwTableBoxes& rBoxes = pLine->GetTabBoxes(); |
| sal_uInt16 nBoxes = rBoxes.Count(); |
| |
| for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ ) |
| { |
| const SwTableBox* pBox = rBoxes[nBox]; |
| if( pBox->GetSttNd() ) |
| { |
| if( nHeight < ROW_DFLT_HEIGHT ) |
| nHeight = ROW_DFLT_HEIGHT; |
| } |
| else |
| { |
| long nTmp = 0; |
| const SwTableLines &rLines = pBox->GetTabLines(); |
| for( sal_uInt16 nLine=0; nLine<rLines.Count(); nLine++ ) |
| { |
| nTmp += GetLineHeight( rLines[nLine] ); |
| } |
| if( nHeight < nTmp ) |
| nHeight = nTmp; |
| } |
| } |
| |
| return nHeight; |
| } |
| |
| long SwWriteTable::GetLineHeight( const SwTableBox *pBox ) const |
| { |
| const SwTableLine *pLine = pBox->GetUpper(); |
| |
| if( !pLine ) |
| return 0; |
| |
| const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt(); |
| const SfxPoolItem* pItem; |
| const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet(); |
| |
| long nHeight = 0; |
| if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem )) |
| nHeight = ((SwFmtFrmSize*)pItem)->GetHeight(); |
| |
| return nHeight; |
| } |
| |
| const SvxBrushItem *SwWriteTable::GetLineBrush( const SwTableBox *pBox, |
| SwWriteTableRow *pRow ) |
| { |
| const SwTableLine *pLine = pBox->GetUpper(); |
| |
| while( pLine ) |
| { |
| const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt(); |
| const SfxPoolItem* pItem; |
| const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet(); |
| |
| if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, |
| &pItem ) ) |
| { |
| if( !pLine->GetUpper() ) |
| { |
| if( !pRow->GetBackground() ) |
| pRow->SetBackground( (const SvxBrushItem *)pItem ); |
| pItem = 0; |
| } |
| |
| return (const SvxBrushItem *)pItem; |
| } |
| |
| pBox = pLine->GetUpper(); |
| pLine = pBox ? pBox->GetUpper() : 0; |
| } |
| |
| return 0; |
| } |
| |
| |
| void SwWriteTable::MergeBorders( const SvxBorderLine* pBorderLine, |
| sal_Bool bTable ) |
| { |
| if( (sal_uInt32)-1 == nBorderColor ) |
| { |
| Color aGrayColor( COL_GRAY ); |
| if( !pBorderLine->GetColor().IsRGBEqual( aGrayColor ) ) |
| nBorderColor = pBorderLine->GetColor().GetColor(); |
| } |
| |
| if( !bCollectBorderWidth ) |
| return; |
| |
| sal_uInt16 nOutWidth = pBorderLine->GetOutWidth(); |
| if( bTable ) |
| { |
| if( nOutWidth && (!nBorder || nOutWidth < nBorder) ) |
| nBorder = nOutWidth; |
| } |
| else |
| { |
| if( nOutWidth && (!nInnerBorder || nOutWidth < nInnerBorder) ) |
| nInnerBorder = nOutWidth; |
| } |
| |
| sal_uInt16 nDist = pBorderLine->GetInWidth() ? pBorderLine->GetDistance() |
| : 0; |
| if( nDist && (!nCellSpacing || nDist < nCellSpacing) ) |
| nCellSpacing = nDist; |
| } |
| |
| |
| sal_uInt16 SwWriteTable::MergeBoxBorders( const SwTableBox *pBox, |
| sal_uInt16 nRow, sal_uInt16 nCol, |
| sal_uInt16 nRowSpan, sal_uInt16 nColSpan, |
| sal_uInt16& rTopBorder, |
| sal_uInt16 &rBottomBorder ) |
| { |
| sal_uInt16 nBorderMask = 0; |
| |
| const SwFrmFmt *pFrmFmt = pBox->GetFrmFmt(); |
| const SvxBoxItem& rBoxItem = (const SvxBoxItem&)pFrmFmt->GetFmtAttr( RES_BOX ); |
| |
| if( rBoxItem.GetTop() ) |
| { |
| nBorderMask |= 1; |
| MergeBorders( rBoxItem.GetTop(), nRow==0 ); |
| rTopBorder = rBoxItem.GetTop()->GetOutWidth(); |
| } |
| |
| if( rBoxItem.GetLeft() ) |
| { |
| nBorderMask |= 4; |
| MergeBorders( rBoxItem.GetLeft(), nCol==0 ); |
| } |
| |
| if( rBoxItem.GetBottom() ) |
| { |
| nBorderMask |= 2; |
| MergeBorders( rBoxItem.GetBottom(), nRow+nRowSpan==aRows.Count() ); |
| rBottomBorder = rBoxItem.GetBottom()->GetOutWidth(); |
| } |
| |
| if( rBoxItem.GetRight() ) |
| { |
| nBorderMask |= 8; |
| MergeBorders( rBoxItem.GetRight(), nCol+nColSpan==aCols.Count() ); |
| } |
| |
| // If any distance is set, the smallest one is used. This holds for |
| // the four distance of a box as well as for the distances of different |
| // boxes. |
| if( bCollectBorderWidth ) |
| { |
| sal_uInt16 nDist = rBoxItem.GetDistance( BOX_LINE_TOP ); |
| if( nDist && (!nCellPadding || nDist < nCellPadding) ) |
| nCellPadding = nDist; |
| nDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM ); |
| if( nDist && (!nCellPadding || nDist < nCellPadding) ) |
| nCellPadding = nDist; |
| nDist = rBoxItem.GetDistance( BOX_LINE_LEFT ); |
| if( nDist && (!nCellPadding || nDist < nCellPadding) ) |
| nCellPadding = nDist; |
| nDist = rBoxItem.GetDistance( BOX_LINE_RIGHT ); |
| if( nDist && (!nCellPadding || nDist < nCellPadding) ) |
| nCellPadding = nDist; |
| } |
| |
| return nBorderMask; |
| } |
| |
| |
| sal_uInt32 SwWriteTable::GetRawWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const |
| { |
| sal_uInt32 nWidth = aCols[nCol+nColSpan-1]->GetPos(); |
| if( nCol > 0 ) |
| nWidth = nWidth - aCols[nCol-1]->GetPos(); |
| |
| return nWidth; |
| } |
| |
| sal_uInt16 SwWriteTable::GetLeftSpace( sal_uInt16 nCol ) const |
| { |
| sal_uInt16 nSpace = nCellPadding + nCellSpacing; |
| |
| // In der ersten Spalte auch noch die Liniendicke abziehen |
| if( nCol==0 ) |
| { |
| nSpace = nSpace + nLeftSub; |
| |
| const SwWriteTableCol *pCol = aCols[nCol]; |
| if( pCol->HasLeftBorder() ) |
| nSpace = nSpace + nBorder; |
| } |
| |
| return nSpace; |
| } |
| |
| sal_uInt16 SwWriteTable::GetRightSpace( sal_uInt16 nCol, sal_uInt16 nColSpan ) const |
| { |
| sal_uInt16 nSpace = nCellPadding; |
| |
| // In der letzten Spalte noch einmal zusaetzlich CELLSPACING und |
| // und die Liniendicke abziehen |
| if( nCol+nColSpan==aCols.Count() ) |
| { |
| nSpace += (nCellSpacing + nRightSub); |
| |
| const SwWriteTableCol *pCol = aCols[nCol+nColSpan-1]; |
| if( pCol->HasRightBorder() ) |
| nSpace = nSpace + nBorder; |
| } |
| |
| return nSpace; |
| } |
| |
| sal_uInt16 SwWriteTable::GetAbsWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const |
| { |
| sal_uInt32 nWidth = GetRawWidth( nCol, nColSpan ); |
| if( nBaseWidth != nTabWidth ) |
| { |
| nWidth *= nTabWidth; |
| nWidth /= nBaseWidth; |
| } |
| |
| nWidth -= GetLeftSpace( nCol ) + GetRightSpace( nCol, nColSpan ); |
| |
| ASSERT( nWidth > 0, "Spaltenbreite <= 0. OK?" ); |
| return nWidth > 0 ? (sal_uInt16)nWidth : 0; |
| } |
| |
| sal_uInt16 SwWriteTable::GetRelWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const |
| { |
| long nWidth = GetRawWidth( nCol, nColSpan ); |
| |
| return (sal_uInt16)(long)Fraction( nWidth*256 + GetBaseWidth()/2, |
| GetBaseWidth() ); |
| } |
| |
| sal_uInt16 SwWriteTable::GetPrcWidth( sal_uInt16 nCol, sal_uInt16 nColSpan ) const |
| { |
| long nWidth = GetRawWidth( nCol, nColSpan ); |
| |
| // sieht komisch aus, ist aber nichts anderes als |
| // [(100 * nWidth) + .5] ohne Rundungsfehler |
| return (sal_uInt16)(long)Fraction( nWidth*100 + GetBaseWidth()/2, |
| GetBaseWidth() ); |
| } |
| |
| long SwWriteTable::GetAbsHeight( long nRawHeight, sal_uInt16 nRow, |
| sal_uInt16 nRowSpan ) const |
| { |
| nRawHeight -= (2*nCellPadding + nCellSpacing); |
| |
| // In der ersten Zeile noch einmal zusaetzlich CELLSPACING und |
| // und die Liniendicke abziehen |
| const SwWriteTableRow *pRow = 0; |
| if( nRow==0 ) |
| { |
| nRawHeight -= nCellSpacing; |
| pRow = aRows[nRow]; |
| if( pRow->HasTopBorder() ) |
| nRawHeight -= nBorder; |
| } |
| |
| // In der letzten Zeile noch die Liniendicke abziehen |
| if( nRow+nRowSpan==aRows.Count() ) |
| { |
| if( !pRow || nRowSpan > 1 ) |
| pRow = aRows[nRow+nRowSpan-1]; |
| if( pRow->HasBottomBorder() ) |
| nRawHeight -= nBorder; |
| } |
| |
| ASSERT( nRawHeight > 0, "Zeilenheohe <= 0. OK?" ); |
| return nRawHeight > 0 ? nRawHeight : 0; |
| } |
| |
| sal_Bool SwWriteTable::ShouldExpandSub(const SwTableBox *pBox, sal_Bool /*bExpandedBefore*/, |
| sal_uInt16 nDepth) const |
| { |
| return !pBox->GetSttNd() && nDepth > 0; |
| } |
| |
| void SwWriteTable::CollectTableRowsCols( long nStartRPos, |
| sal_uInt32 nStartCPos, |
| long nParentLineHeight, |
| sal_uInt32 nParentLineWidth, |
| const SwTableLines& rLines, |
| sal_uInt16 nDepth ) |
| { |
| sal_Bool bSubExpanded = sal_False; |
| sal_uInt16 nLines = rLines.Count(); |
| |
| #ifdef DBG_UTIL |
| sal_uInt32 nEndCPos = 0; |
| #endif |
| |
| long nRPos = nStartRPos; |
| for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) |
| { |
| /*const*/ SwTableLine *pLine = rLines[nLine]; |
| |
| long nOldRPos = nRPos; |
| |
| if( nLine < nLines-1 || nParentLineHeight==0 ) |
| { |
| long nLineHeight = GetLineHeight( pLine ); |
| nRPos += nLineHeight; |
| if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos ) |
| { |
| /* If you have corrupt line height information, e.g. breaking rows in complex table |
| layout, you may run into this robust code. |
| It's not allowed that subrows leaves their parentrow. If this would happen the line |
| height of subrow is reduced to a part of the remaining height */ |
| ASSERT( sal_False, "Corrupt line height I" ); |
| nRPos -= nLineHeight; |
| nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height |
| nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows |
| nRPos += nLineHeight; |
| } |
| SwWriteTableRow *pRow = new SwWriteTableRow( nRPos, bUseLayoutHeights); |
| sal_uInt16 nRow; |
| if( aRows.Seek_Entry( pRow, &nRow ) ) |
| delete pRow; |
| else |
| aRows.Insert( pRow ); |
| } |
| else |
| { |
| #ifdef DBG_UTIL |
| long nCheckPos = nRPos + GetLineHeight( pLine ); |
| #endif |
| nRPos = nStartRPos + nParentLineHeight; |
| #ifdef DBG_UTIL |
| SwWriteTableRow aRow( nStartRPos + nParentLineHeight, bUseLayoutHeights ); |
| ASSERT( aRows.Seek_Entry(&aRow), |
| "Parent-Zeile nicht gefunden" ); |
| SwWriteTableRow aRowCheckPos(nCheckPos,bUseLayoutHeights); |
| SwWriteTableRow aRowRPos(nRPos,bUseLayoutHeights); |
| ASSERT( !bUseLayoutHeights || |
| aRowCheckPos == aRowRPos, |
| "Hoehe der Zeilen stimmt nicht mit Parent ueberein" ); |
| #endif |
| } |
| |
| // Fuer alle Boxen der Zeile ggf. eine Spalte einfuegen |
| const SwTableBoxes& rBoxes = pLine->GetTabBoxes(); |
| sal_uInt16 nBoxes = rBoxes.Count(); |
| |
| sal_uInt32 nCPos = nStartCPos; |
| for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ ) |
| { |
| const SwTableBox *pBox = rBoxes[nBox]; |
| |
| sal_uInt32 nOldCPos = nCPos; |
| |
| if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) ) |
| { |
| nCPos = nCPos + GetBoxWidth( pBox ); |
| SwWriteTableCol *pCol = new SwWriteTableCol( nCPos ); |
| |
| sal_uInt16 nCol; |
| if( aCols.Seek_Entry( pCol, &nCol ) ) |
| delete pCol; |
| else |
| aCols.Insert( pCol ); |
| |
| if( nBox==nBoxes-1 ) |
| { |
| ASSERT( nLine==0 && nParentLineWidth==0, |
| "Jetzt wird die Parent-Breite plattgemacht!" ); |
| nParentLineWidth = nCPos-nStartCPos; |
| } |
| } |
| else |
| { |
| #ifdef DBG_UTIL |
| sal_uInt32 nCheckPos = nCPos + GetBoxWidth( pBox ); |
| if( !nEndCPos ) |
| { |
| nEndCPos = nCheckPos; |
| } |
| else |
| { |
| ASSERT( SwWriteTableCol(nCheckPos) == |
| SwWriteTableCol(nEndCPos), |
| "Zelle enthaelt unterschiedlich breite Zeilen" ); |
| } |
| #endif |
| nCPos = nStartCPos + nParentLineWidth; |
| #ifdef DBG_UTIL |
| SwWriteTableCol aCol( nStartCPos + nParentLineWidth ); |
| ASSERT( aCols.Seek_Entry(&aCol), |
| "Parent-Zelle nicht gefunden" ); |
| ASSERT( SwWriteTableCol(nCheckPos) == |
| SwWriteTableCol(nCPos), |
| "Breite der Zellen stimmt nicht mit Parent ueberein" ); |
| #endif |
| } |
| |
| if( ShouldExpandSub( pBox, bSubExpanded, nDepth ) ) |
| { |
| CollectTableRowsCols( nOldRPos, nOldCPos, |
| nRPos - nOldRPos, |
| nCPos - nOldCPos, |
| pBox->GetTabLines(), |
| nDepth-1 ); |
| bSubExpanded = sal_True; |
| } |
| } |
| } |
| } |
| |
| |
| void SwWriteTable::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 ) |
| { |
| sal_uInt16 nLines = rLines.Count(); |
| sal_Bool bSubExpanded = sal_False; |
| |
| // Festlegen der Umrandung |
| long nRPos = nStartRPos; |
| sal_uInt16 nRow = nStartRow; |
| |
| for( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) |
| { |
| const SwTableLine *pLine = rLines[nLine]; |
| |
| // Position der letzten ueberdeckten Zeile ermitteln |
| long nOldRPos = nRPos; |
| if( nLine < nLines-1 || nParentLineHeight==0 ) |
| { |
| long nLineHeight = GetLineHeight( pLine ); |
| nRPos += nLineHeight; |
| if( nParentLineHeight && nStartRPos + nParentLineHeight <= nRPos ) |
| { |
| /* See comment in CollectTableRowCols */ |
| ASSERT( sal_False, "Corrupt line height II" ); |
| nRPos -= nLineHeight; |
| nLineHeight = nStartRPos + nParentLineHeight - nRPos; // remaining parent height |
| nLineHeight /= nLines - nLine; // divided through the number of remaining sub rows |
| nRPos += nLineHeight; |
| } |
| } |
| else |
| nRPos = nStartRPos + nParentLineHeight; |
| |
| // Und ihren Index |
| sal_uInt16 nOldRow = nRow; |
| SwWriteTableRow aRow( nRPos,bUseLayoutHeights ); |
| #ifdef DBG_UTIL |
| sal_Bool bFound = |
| #endif |
| aRows.Seek_Entry( &aRow, &nRow ); |
| ASSERT( bFound, "Wo ist die Zeile geblieben?" ); |
| |
| ASSERT( nOldRow <= nRow, "Don't look back!" ); |
| if( nOldRow > nRow ) |
| { |
| nOldRow = nRow; |
| if( nOldRow ) |
| --nOldRow; |
| } |
| |
| |
| SwWriteTableRow *pRow = aRows[nOldRow]; |
| SwWriteTableRow *pEndRow = aRows[nRow]; |
| // if( nLine==0 && nParentLineHeight==0 ) |
| if( nLine+1==nNumOfHeaderRows && nParentLineHeight==0 ) |
| nHeadEndRow = nRow; |
| |
| const SwTableBoxes& rBoxes = pLine->GetTabBoxes(); |
| |
| const SwFrmFmt *pLineFrmFmt = pLine->GetFrmFmt(); |
| const SfxPoolItem* pItem; |
| const SfxItemSet& rItemSet = pLineFrmFmt->GetAttrSet(); |
| |
| long nHeight = 0; |
| if( SFX_ITEM_SET == rItemSet.GetItemState( RES_FRM_SIZE, sal_True, &pItem )) |
| nHeight = ((SwFmtFrmSize*)pItem)->GetHeight(); |
| |
| |
| const SvxBrushItem *pBrushItem, *pLineBrush = pParentBrush; |
| if( SFX_ITEM_SET == rItemSet.GetItemState( RES_BACKGROUND, sal_False, |
| &pItem ) ) |
| { |
| pLineBrush = (const SvxBrushItem *)pItem; |
| |
| // Wenn die Zeile die gesamte Tabelle umspannt, koennen |
| // Wir den Hintergrund an der Zeile ausgeben. Sonst muessen |
| // wir in an den Zelle ausgeben. |
| sal_Bool bOutAtRow = !nParentLineWidth; |
| if( !bOutAtRow && nStartCPos==0 ) |
| { |
| sal_uInt16 nEndCol; |
| SwWriteTableCol aCol( nParentLineWidth ); |
| bOutAtRow = aCols.Seek_Entry(&aCol,&nEndCol) && |
| nEndCol == aCols.Count()-1; |
| } |
| if( bOutAtRow ) |
| { |
| pRow->SetBackground( pLineBrush ); |
| pBrushItem = 0; |
| } |
| else |
| pBrushItem = pLineBrush; |
| } |
| else |
| { |
| pRow->SetBackground( pLineBrush ); |
| pBrushItem = 0; |
| } |
| |
| sal_uInt16 nBoxes = rBoxes.Count(); |
| sal_uInt32 nCPos = nStartCPos; |
| sal_uInt16 nCol = nStartCol; |
| |
| for( sal_uInt16 nBox=0; nBox<nBoxes; nBox++ ) |
| { |
| const SwTableBox *pBox = rBoxes[nBox]; |
| |
| // Position der letzten ueberdeckten Spalte ermitteln |
| sal_uInt32 nOldCPos = nCPos; |
| if( nBox < nBoxes-1 || (nParentLineWidth==0 && nLine==0) ) |
| { |
| nCPos = nCPos + GetBoxWidth( pBox ); |
| if( nBox==nBoxes-1 ) |
| nParentLineWidth = nCPos - nStartCPos; |
| } |
| else |
| nCPos = nStartCPos + nParentLineWidth; |
| |
| // Und ihren Index |
| sal_uInt16 nOldCol = nCol; |
| SwWriteTableCol aCol( nCPos ); |
| #ifdef DBG_UTIL |
| sal_Bool bFound2 = |
| #endif |
| aCols.Seek_Entry( &aCol, &nCol ); |
| ASSERT( bFound2, "Wo ist die Spalte geblieben?" ); |
| |
| if( !ShouldExpandSub( pBox, bSubExpanded, nDepth ) ) |
| { |
| sal_uInt16 nRowSpan = nRow - nOldRow + 1; |
| |
| // The new table model may have true row span attributes |
| const long nAttrRowSpan = pBox->getRowSpan(); |
| if ( 1 < nAttrRowSpan ) |
| nRowSpan = (sal_uInt16)nAttrRowSpan; |
| else if ( nAttrRowSpan < 1 ) |
| nRowSpan = 0; |
| |
| sal_uInt16 nColSpan = nCol - nOldCol + 1; |
| pRow->AddCell( pBox, nOldRow, nOldCol, |
| nRowSpan, nColSpan, nHeight, |
| pBrushItem ); |
| nHeight = 0; // Die Hoehe braucht nur einmal geschieben werden |
| |
| if( pBox->GetSttNd() ) |
| { |
| sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX; |
| sal_uInt16 nBorderMask = MergeBoxBorders(pBox, nOldRow, nOldCol, |
| nRowSpan, nColSpan, nTopBorder, nBottomBorder); |
| |
| // #i30094# add a sanity check here to ensure that |
| // we don't access an invalid aCols[] as &nCol |
| // above can be changed. |
| if (!(nBorderMask & 4) && nOldCol < aCols.Count()) |
| { |
| SwWriteTableCol *pCol = aCols[nOldCol]; |
| ASSERT(pCol, "No TableCol found, panic!"); |
| if (pCol) |
| pCol->bLeftBorder = sal_False; |
| } |
| |
| if (!(nBorderMask & 8)) |
| { |
| SwWriteTableCol *pCol = aCols[nCol]; |
| ASSERT(pCol, "No TableCol found, panic!"); |
| if (pCol) |
| pCol->bRightBorder = sal_False; |
| } |
| |
| if (!(nBorderMask & 1)) |
| pRow->bTopBorder = sal_False; |
| else if (!pRow->nTopBorder || nTopBorder < pRow->nTopBorder) |
| pRow->nTopBorder = nTopBorder; |
| |
| if (!(nBorderMask & 2)) |
| pEndRow->bBottomBorder = sal_False; |
| else if ( |
| !pEndRow->nBottomBorder || |
| nBottomBorder < pEndRow->nBottomBorder |
| ) |
| { |
| pEndRow->nBottomBorder = nBottomBorder; |
| } |
| } |
| // MIB: 13.12.2000: Why should a cell that contains a subtable |
| // not have borders? Moreover, switching them, off switches off |
| // the fill border lines between the columns and rows. (#74222#) |
| // else |
| // { |
| // aCols[nOldCol]->bLeftBorder = sal_False; |
| // aCols[nCol]->bRightBorder = sal_False; |
| // pRow->bTopBorder = sal_False; |
| // pEndRow->bBottomBorder = sal_False; |
| // } |
| } |
| else |
| { |
| FillTableRowsCols( nOldRPos, nOldRow, nOldCPos, nOldCol, |
| nRPos-nOldRPos, nCPos-nOldCPos, |
| pBox->GetTabLines(), |
| pLineBrush, nDepth-1, |
| nNumOfHeaderRows ); |
| bSubExpanded = sal_True; |
| } |
| |
| nCol++; // Die naechste Zelle faengt in der nachten Spalte an |
| } |
| |
| nRow++; |
| } |
| } |
| |
| SwWriteTable::SwWriteTable(const SwTableLines& rLines, long nWidth, |
| sal_uInt32 nBWidth, sal_Bool bRel, sal_uInt16 nMaxDepth, sal_uInt16 nLSub, sal_uInt16 nRSub, sal_uInt32 nNumOfRowsToRepeat) |
| : nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0), |
| nInnerBorder(0), nBaseWidth(nBWidth), nHeadEndRow(USHRT_MAX), |
| nLeftSub(nLSub), nRightSub(nRSub), nTabWidth(nWidth), bRelWidths(bRel), |
| bUseLayoutHeights(true), |
| #ifdef DBG_UTIL |
| bGetLineHeightCalled(false), |
| #endif |
| bColsOption(false), bColTags(true), bLayoutExport(false), |
| bCollectBorderWidth(true) |
| { |
| sal_uInt32 nParentWidth = nBaseWidth + nLeftSub + nRightSub; |
| |
| // Erstmal die Tabellen-Struktur festlegen. Hinter der Tabelle ist in |
| // jedem Fall eine Spalte zu Ende |
| SwWriteTableCol *pCol = new SwWriteTableCol( nParentWidth ); |
| aCols.Insert( pCol ); |
| CollectTableRowsCols( 0, 0, 0, nParentWidth, rLines, nMaxDepth - 1 ); |
| |
| // Und jetzt mit leben fuellen |
| FillTableRowsCols( 0, 0, 0, 0, 0, nParentWidth, rLines, 0, nMaxDepth - 1, static_cast< sal_uInt16 >(nNumOfRowsToRepeat) ); |
| |
| // Einige Twip-Werte an Pixel-Grenzen anpassen |
| if( !nBorder ) |
| nBorder = nInnerBorder; |
| } |
| |
| SwWriteTable::SwWriteTable( const SwHTMLTableLayout *pLayoutInfo ) |
| : nBorderColor((sal_uInt32)-1), nCellSpacing(0), nCellPadding(0), nBorder(0), |
| nInnerBorder(0), nBaseWidth(pLayoutInfo->GetWidthOption()), nHeadEndRow(0), |
| nLeftSub(0), nRightSub(0), nTabWidth(pLayoutInfo->GetWidthOption()), |
| bRelWidths(pLayoutInfo->HasPrcWidthOption()), bUseLayoutHeights(false), |
| #ifdef DBG_UTIL |
| bGetLineHeightCalled(false), |
| #endif |
| bColsOption(pLayoutInfo->HasColsOption()), |
| bColTags(pLayoutInfo->HasColTags()), bLayoutExport(true), |
| bCollectBorderWidth(pLayoutInfo->HaveBordersChanged()) |
| { |
| if( !bCollectBorderWidth ) |
| { |
| nBorder = pLayoutInfo->GetBorder(); |
| nCellPadding = pLayoutInfo->GetCellPadding(); |
| nCellSpacing = pLayoutInfo->GetCellSpacing(); |
| } |
| |
| sal_uInt16 nRow, nCol; |
| sal_uInt16 nCols = pLayoutInfo->GetColCount(); |
| sal_uInt16 nRows = pLayoutInfo->GetRowCount(); |
| |
| // Erstmal die Tabellen-Struktur festlegen. |
| for( nCol=0; nCol<nCols; nCol++ ) |
| { |
| SwWriteTableCol *pCol = |
| new SwWriteTableCol( (nCol+1)*COL_DFLT_WIDTH ); |
| |
| if( bColTags ) |
| { |
| const SwHTMLTableLayoutColumn *pLayoutCol = |
| pLayoutInfo->GetColumn( nCol ); |
| pCol->SetWidthOpt( pLayoutCol->GetWidthOption(), |
| pLayoutCol->IsRelWidthOption() ); |
| } |
| |
| aCols.Insert( pCol ); |
| } |
| |
| for( nRow=0; nRow<nRows; nRow++ ) |
| { |
| SwWriteTableRow *pRow = |
| new SwWriteTableRow( (nRow+1)*ROW_DFLT_HEIGHT, bUseLayoutHeights ); |
| pRow->nTopBorder = 0; |
| pRow->nBottomBorder = 0; |
| aRows.Insert( pRow ); |
| } |
| |
| // Und jetzt mit leben fuellen |
| for( nRow=0; nRow<nRows; nRow++ ) |
| { |
| SwWriteTableRow *pRow = aRows[nRow]; |
| |
| sal_Bool bHeightExported = sal_False; |
| for( nCol=0; nCol<nCols; nCol++ ) |
| { |
| const SwHTMLTableLayoutCell *pLayoutCell = |
| pLayoutInfo->GetCell( nRow, nCol ); |
| |
| const SwHTMLTableLayoutCnts *pLayoutCnts = |
| pLayoutCell->GetContents(); |
| |
| // Beginnt die Zelle eigentlich eine Zeile weiter oben oder |
| // weiter vorne? |
| if( ( nRow>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow-1,nCol) |
| ->GetContents() ) || |
| ( nCol>0 && pLayoutCnts == pLayoutInfo->GetCell(nRow,nCol-1) |
| ->GetContents() ) ) |
| { |
| continue; |
| } |
| |
| sal_uInt16 nRowSpan = pLayoutCell->GetRowSpan(); |
| sal_uInt16 nColSpan = pLayoutCell->GetColSpan(); |
| const SwTableBox *pBox = pLayoutCnts->GetTableBox(); |
| ASSERT( pBox, |
| "Tabelle in Tabelle kann nicht ueber Layout exportiert werden" ); |
| |
| long nHeight = bHeightExported ? 0 : GetLineHeight( pBox ); |
| const SvxBrushItem *pBrushItem = GetLineBrush( pBox, pRow ); |
| |
| SwWriteTableCell *pCell = |
| pRow->AddCell( pBox, nRow, nCol, nRowSpan, nColSpan, |
| nHeight, pBrushItem ); |
| pCell->SetWidthOpt( pLayoutCell->GetWidthOption(), |
| pLayoutCell->IsPrcWidthOption() ); |
| |
| sal_uInt16 nTopBorder = USHRT_MAX, nBottomBorder = USHRT_MAX; |
| sal_uInt16 nBorderMask = |
| MergeBoxBorders( pBox, nRow, nCol, nRowSpan, nColSpan, |
| nTopBorder, nBottomBorder ); |
| |
| SwWriteTableCol *pCol = aCols[nCol]; |
| if( !(nBorderMask & 4) ) |
| pCol->bLeftBorder = sal_False; |
| |
| pCol = aCols[nCol+nColSpan-1]; |
| if( !(nBorderMask & 8) ) |
| pCol->bRightBorder = sal_False; |
| |
| if( !(nBorderMask & 1) ) |
| pRow->bTopBorder = sal_False; |
| |
| SwWriteTableRow *pEndRow = aRows[nRow+nRowSpan-1]; |
| if( !(nBorderMask & 2) ) |
| pEndRow->bBottomBorder = sal_False; |
| |
| // Die Hoehe braucht nur einmal geschieben werden |
| if( nHeight ) |
| bHeightExported = sal_True; |
| } |
| } |
| |
| // Einige Twip-Werte an Pixel-Grenzen anpassen |
| if( bCollectBorderWidth && !nBorder ) |
| nBorder = nInnerBorder; |
| } |
| |
| SwWriteTable::~SwWriteTable() |
| { |
| } |