1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <com/sun/star/table/XMergeableCell.hpp>
22 #include <com/sun/star/awt/XLayoutConstrains.hpp>
24 #include <tools/gen.hxx>
27 #include "cellrange.hxx"
28 #include "tablemodel.hxx"
29 #include "tablerow.hxx"
30 #include "tablerows.hxx"
31 #include "tablecolumn.hxx"
32 #include "tablecolumns.hxx"
33 #include "tablelayouter.hxx"
34 #include "svx/svdotable.hxx"
35 #include "editeng/borderline.hxx"
36 #include "editeng/boxitem.hxx"
37 #include "svx/svdmodel.hxx"
38 #include "svx/svdstr.hrc"
39 #include "svx/svdglob.hxx"
41 using ::editeng::SvxBorderLine
;
42 using ::com::sun::star::awt::XLayoutConstrains
;
43 using namespace ::com::sun::star::uno
;
44 using namespace ::com::sun::star::lang
;
45 using namespace ::com::sun::star::container
;
46 using namespace ::com::sun::star::beans
;
47 using namespace ::com::sun::star::table
;
48 using namespace ::com::sun::star::text
;
50 // -----------------------------------------------------------------------------
52 namespace sdr
{ namespace table
{
54 // -----------------------------------------------------------------------------
56 static SvxBorderLine gEmptyBorder
;
58 // -----------------------------------------------------------------------------
60 TableLayouter::TableLayouter( const TableModelRef
& xTableModel
)
61 : mxTable( xTableModel
)
62 , meWritingMode( WritingMode_LR_TB
)
67 // -----------------------------------------------------------------------------
69 TableLayouter::~TableLayouter()
74 // -----------------------------------------------------------------------------
76 basegfx::B2ITuple
TableLayouter::getCellSize( const CellPos
& rPos
) const
83 CellRef
xCell( getCell( rPos
) );
84 if( xCell
.is() && !xCell
->isMerged() )
88 sal_Int32 nRowCount
= getRowCount();
89 sal_Int32 nRowSpan
= std::max( xCell
->getRowSpan(), (sal_Int32
)1 );
90 while( nRowSpan
&& (aPos
.mnRow
< nRowCount
) )
92 if( ((sal_Int32
)maRows
.size()) <= aPos
.mnRow
)
95 height
+= maRows
[aPos
.mnRow
++].mnSize
;
99 sal_Int32 nColCount
= getColumnCount();
100 sal_Int32 nColSpan
= std::max( xCell
->getColumnSpan(), (sal_Int32
)1 );
101 while( nColSpan
&& (aPos
.mnCol
< nColCount
) )
103 if( ((sal_Int32
)maColumns
.size()) <= aPos
.mnCol
)
106 width
+= maColumns
[aPos
.mnCol
++].mnSize
;
113 OSL_FAIL( "TableLayouter::getCellSize(), exception caught!" );
116 return basegfx::B2ITuple( width
, height
);
119 // -----------------------------------------------------------------------------
121 bool TableLayouter::getCellArea( const CellPos
& rPos
, basegfx::B2IRectangle
& rArea
) const
125 CellRef
xCell( getCell( rPos
) );
126 if( xCell
.is() && !xCell
->isMerged() && isValid(rPos
) )
128 const basegfx::B2ITuple
aCellSize( getCellSize( rPos
) );
129 const bool bRTL
= meWritingMode
== WritingMode_RL_TB
;
131 if( (rPos
.mnCol
< ((sal_Int32
)maColumns
.size()) && (rPos
.mnRow
< ((sal_Int32
)maRows
.size()) ) ) )
133 const sal_Int32 y
= maRows
[rPos
.mnRow
].mnPos
;
137 ///For RTL Table Calculate the Right End of cell instead of Left
138 const sal_Int32 x
= maColumns
[rPos
.mnCol
].mnPos
+ maColumns
[rPos
.mnCol
].mnSize
;
139 rArea
= basegfx::B2IRectangle( x
-aCellSize
.getX(), y
, x
, y
+ aCellSize
.getY() );
143 const sal_Int32 x
= maColumns
[rPos
.mnCol
].mnPos
;
144 rArea
= basegfx::B2IRectangle( x
, y
, x
+ aCellSize
.getX(), y
+ aCellSize
.getY() );
152 OSL_FAIL( "TableLayouter::getCellSize(), exception caught!" );
157 // -----------------------------------------------------------------------------
158 sal_Int32
TableLayouter::getRowHeight( sal_Int32 nRow
) const
160 if( isValidRow(nRow
) )
161 return maRows
[nRow
].mnSize
;
166 // -----------------------------------------------------------------------------
167 sal_Int32
TableLayouter::getColumnWidth( sal_Int32 nColumn
) const
169 if( isValidColumn(nColumn
) )
170 return maColumns
[nColumn
].mnSize
;
175 // -----------------------------------------------------------------------------
177 bool TableLayouter::isEdgeVisible( sal_Int32 nEdgeX
, sal_Int32 nEdgeY
, bool bHorizontal
) const
179 const BorderLineMap
& rMap
= bHorizontal
? maHorizontalBorders
: maVerticalBorders
;
181 if( (nEdgeX
>= 0) && (nEdgeX
< sal::static_int_cast
<sal_Int32
>(rMap
.size())) &&
182 (nEdgeY
>= 0) && (nEdgeY
< sal::static_int_cast
<sal_Int32
>(rMap
[nEdgeX
].size())) )
184 return rMap
[nEdgeX
][nEdgeY
] != 0;
188 OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
194 // -----------------------------------------------------------------------------
196 /** returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge */
197 SvxBorderLine
* TableLayouter::getBorderLine( sal_Int32 nEdgeX
, sal_Int32 nEdgeY
, bool bHorizontal
)const
199 SvxBorderLine
* pLine
= 0;
201 const BorderLineMap
& rMap
= bHorizontal
? maHorizontalBorders
: maVerticalBorders
;
203 if( (nEdgeX
>= 0) && (nEdgeX
< sal::static_int_cast
<sal_Int32
>(rMap
.size())) &&
204 (nEdgeY
>= 0) && (nEdgeY
< sal::static_int_cast
<sal_Int32
>(rMap
[nEdgeX
].size())) )
206 pLine
= rMap
[nEdgeX
][nEdgeY
];
207 if( pLine
== &gEmptyBorder
)
212 OSL_FAIL( "sdr::table::TableLayouter::getBorderLine(), invalid edge!" );
218 // -----------------------------------------------------------------------------
220 sal_Int32
TableLayouter::getHorizontalEdge( int nEdgeY
, sal_Int32
* pnMin
/*= 0*/, sal_Int32
* pnMax
/*= 0*/ )
223 const sal_Int32 nRowCount
= getRowCount();
224 if( (nEdgeY
>= 0) && (nEdgeY
<= nRowCount
) )
225 nRet
= maRows
[std::min((sal_Int32
)nEdgeY
,nRowCount
-1)].mnPos
;
227 if( nEdgeY
== nRowCount
)
228 nRet
+= maRows
[nEdgeY
- 1].mnSize
;
232 if( (nEdgeY
> 0) && (nEdgeY
<= nRowCount
) )
234 *pnMin
= maRows
[nEdgeY
-1].mnPos
+ 600; // todo
249 // -----------------------------------------------------------------------------
251 sal_Int32
TableLayouter::getVerticalEdge( int nEdgeX
, sal_Int32
* pnMin
/*= 0*/, sal_Int32
* pnMax
/*= 0*/ )
255 const sal_Int32 nColCount
= getColumnCount();
256 if( (nEdgeX
>= 0) && (nEdgeX
<= nColCount
) )
257 nRet
= maColumns
[std::min((sal_Int32
)nEdgeX
,nColCount
-1)].mnPos
;
259 const bool bRTL
= meWritingMode
== WritingMode_RL_TB
;
262 if( (nEdgeX
>= 0) && (nEdgeX
< nColCount
) )
263 nRet
+= maColumns
[nEdgeX
].mnSize
;
267 if( nEdgeX
== nColCount
)
268 nRet
+= maColumns
[nEdgeX
- 1].mnSize
;
276 if( nEdgeX
< nColCount
)
277 *pnMin
= nRet
- maColumns
[nEdgeX
].mnSize
+ getMinimumColumnWidth(nEdgeX
);
281 if( (nEdgeX
> 0) && (nEdgeX
<= nColCount
) )
282 *pnMin
= maColumns
[nEdgeX
-1].mnPos
+ getMinimumColumnWidth( nEdgeX
-1 );
288 *pnMax
= 0x0fffffff; // todo
292 *pnMax
= nRet
+ maColumns
[nEdgeX
-1].mnSize
- getMinimumColumnWidth( nEdgeX
-1 );
296 if( (nEdgeX
>= 0) && (nEdgeX
< nColCount
) )
297 *pnMax
= maColumns
[nEdgeX
].mnPos
+ maColumns
[nEdgeX
].mnSize
- getMinimumColumnWidth( nEdgeX
);
304 // -----------------------------------------------------------------------------
306 static bool checkMergeOrigin( const TableModelRef
& xTable
, sal_Int32 nMergedX
, sal_Int32 nMergedY
, sal_Int32 nCellX
, sal_Int32 nCellY
, bool& bRunning
)
308 Reference
< XMergeableCell
> xCell( xTable
->getCellByPosition( nCellX
, nCellY
), UNO_QUERY
);
309 if( xCell
.is() && !xCell
->isMerged() )
311 const sal_Int32 nRight
= xCell
->getColumnSpan() + nCellX
;
312 const sal_Int32 nBottom
= xCell
->getRowSpan() + nCellY
;
313 if( (nMergedX
< nRight
) && (nMergedY
< nBottom
) )
321 /** returns true if the cell(nMergedX,nMergedY) is merged with other cells.
322 the returned cell( rOriginX, rOriginY ) is the origin( top left cell ) of the merge.
324 bool findMergeOrigin( const TableModelRef
& xTable
, sal_Int32 nMergedX
, sal_Int32 nMergedY
, sal_Int32
& rOriginX
, sal_Int32
& rOriginY
)
329 if( xTable
.is() ) try
331 // check if this cell already the origin or not merged at all
332 Reference
< XMergeableCell
> xCell( xTable
->getCellByPosition( nMergedX
, nMergedY
), UNO_QUERY_THROW
);
333 if( !xCell
.is() || !xCell
->isMerged() )
336 bool bCheckVert
= true;
337 bool bCheckHorz
= true;
339 sal_Int32 nMinCol
= 0;
340 sal_Int32 nMinRow
= 0;
342 sal_Int32 nStep
= 1, i
;
344 sal_Int32 nRow
, nCol
;
349 nRow
= nMergedY
- nStep
;
350 if( nRow
>= nMinRow
)
353 for( i
= 0; (i
<= nStep
) && (nCol
>= nMinCol
); i
++, nCol
-- )
355 if( checkMergeOrigin( xTable
, nMergedX
, nMergedY
, nCol
, nRow
, bCheckVert
) )
357 rOriginX
= nCol
; rOriginY
= nRow
;
363 if( nCol
== nMergedX
)
383 nCol
= nMergedX
- nStep
;
384 if( nCol
>= nMinCol
)
387 for( i
= 0; (i
< nStep
) && (nRow
>= nMinRow
); i
++, nRow
-- )
389 if( checkMergeOrigin( xTable
, nMergedX
, nMergedY
, nCol
, nRow
, bCheckHorz
) )
391 rOriginX
= nCol
; rOriginY
= nRow
;
397 if( nRow
== nMergedY
)
416 while( bCheckVert
|| bCheckHorz
);
420 OSL_FAIL("sdr::table::TableLayouter::findMergeOrigin(), exception caught!");
425 // -----------------------------------------------------------------------------
427 sal_Int32
TableLayouter::getMinimumColumnWidth( sal_Int32 nColumn
)
429 if( isValidColumn( nColumn
) )
431 return maColumns
[nColumn
].mnMinSize
;
435 OSL_FAIL( "TableLayouter::getMinimumColumnWidth(), column out of range!" );
440 // -----------------------------------------------------------------------------
442 sal_Int32
TableLayouter::distribute( LayoutVector
& rLayouts
, sal_Int32 nDistribute
)
444 // break loops after 100 runs to avoid freezing office due to developer error
445 sal_Int32 nSafe
= 100;
447 const sal_Size nCount
= rLayouts
.size();
450 bool bConstrainsBroken
= false;
454 // first enforce minimum size constrains on all entities
455 for( nIndex
= 0; nIndex
< nCount
; ++nIndex
)
457 Layout
& rLayout
= rLayouts
[nIndex
];
458 if( rLayout
.mnSize
< rLayout
.mnMinSize
)
460 nDistribute
-= rLayout
.mnMinSize
- rLayout
.mnSize
;
461 rLayout
.mnSize
= rLayout
.mnMinSize
;
465 // calculate current width
466 // if nDistribute is < 0 (shrinking), entities that are already
467 // at minimum width are not counted
468 sal_Int32 nCurrentWidth
= 0;
469 for( nIndex
= 0; nIndex
< nCount
; ++nIndex
)
471 Layout
& rLayout
= rLayouts
[nIndex
];
472 if( (nDistribute
> 0) || (rLayout
.mnSize
> rLayout
.mnMinSize
) )
473 nCurrentWidth
+= rLayout
.mnSize
;
476 bConstrainsBroken
= false;
478 // now distribute over entities
479 if( (nCurrentWidth
!= 0) && (nDistribute
!= 0) )
481 sal_Int32 nDistributed
= nDistribute
;
482 for( nIndex
= 0; nIndex
< nCount
; ++nIndex
)
484 Layout
& rLayout
= rLayouts
[nIndex
];
485 if( (nDistribute
> 0) || (rLayout
.mnSize
> rLayout
.mnMinSize
) )
488 if( nIndex
== (nCount
-1) )
489 n
= nDistributed
; // for last entitie, use up rest
491 n
= (nDistribute
* rLayout
.mnSize
) / nCurrentWidth
; //
496 if( rLayout
.mnSize
< rLayout
.mnMinSize
)
497 bConstrainsBroken
= true;
501 } while( bConstrainsBroken
&& --nSafe
);
504 for( nIndex
= 0; nIndex
< nCount
; ++nIndex
)
505 nSize
+= rLayouts
[nIndex
].mnSize
;
510 // -----------------------------------------------------------------------------
512 typedef std::vector
< CellRef
> MergeableCellVector
;
513 typedef std::vector
< MergeableCellVector
> MergeVector
;
514 typedef std::vector
< sal_Int32
> Int32Vector
;
516 // -----------------------------------------------------------------------------
518 void TableLayouter::LayoutTableWidth( Rectangle
& rArea
, bool bFit
)
520 const sal_Int32 nColCount
= getColumnCount();
521 const sal_Int32 nRowCount
= getRowCount();
525 MergeVector
aMergedCells( nColCount
);
526 Int32Vector aOptimalColumns
;
528 const OUString
sOptimalSize("OptimalSize");
530 if( sal::static_int_cast
< sal_Int32
>( maColumns
.size() ) != nColCount
)
531 maColumns
.resize( nColCount
);
533 Reference
< XTableColumns
> xCols( mxTable
->getColumns(), UNO_QUERY_THROW
);
535 // first calculate current width and initial minimum width per column,
536 // merged cells will be counted later
537 sal_Int32 nCurrentWidth
= 0;
538 sal_Int32 nCol
= 0, nRow
= 0;
539 for( nCol
= 0; nCol
< nColCount
; nCol
++ )
541 sal_Int32 nMinWidth
= 0;
543 bool bIsEmpty
= true; // check if all cells in this column are merged
545 for( nRow
= 0; nRow
< nRowCount
; ++nRow
)
547 CellRef
xCell( getCell( CellPos( nCol
, nRow
) ) );
548 if( xCell
.is() && !xCell
->isMerged() )
552 sal_Int32 nColSpan
= xCell
->getColumnSpan();
555 // merged cells will be evaluated later
556 aMergedCells
[nCol
+nColSpan
-1].push_back( xCell
);
560 nMinWidth
= std::max( nMinWidth
, xCell
->getMinimumSize().Width
);
565 maColumns
[nCol
].mnMinSize
= nMinWidth
;
569 maColumns
[nCol
].mnSize
= 0;
573 sal_Int32 nColWidth
= 0;
574 Reference
< XPropertySet
> xColSet( xCols
->getByIndex( nCol
), UNO_QUERY_THROW
);
575 sal_Bool bOptimal
= sal_False
;
576 xColSet
->getPropertyValue( sOptimalSize
) >>= bOptimal
;
579 aOptimalColumns
.push_back(nCol
);
583 xColSet
->getPropertyValue( msSize
) >>= nColWidth
;
586 maColumns
[nCol
].mnSize
= nColWidth
;
588 if( maColumns
[nCol
].mnSize
< nMinWidth
)
589 maColumns
[nCol
].mnSize
= nMinWidth
;
591 nCurrentWidth
+= maColumns
[nCol
].mnSize
;
595 // if we have optimal sized rows, distribute what is given (left)
596 if( !bFit
&& !aOptimalColumns
.empty() && (nCurrentWidth
< rArea
.getWidth()) )
598 sal_Int32 nLeft
= rArea
.getWidth() - nCurrentWidth
;
599 sal_Int32 nDistribute
= nLeft
/ aOptimalColumns
.size();
601 Int32Vector::iterator
iter( aOptimalColumns
.begin() );
602 while( iter
!= aOptimalColumns
.end() )
604 sal_Int32 nOptCol
= (*iter
++);
605 if( iter
== aOptimalColumns
.end() )
608 maColumns
[nOptCol
].mnSize
+= nDistribute
;
609 nLeft
-= nDistribute
;
612 DBG_ASSERT( nLeft
== 0, "svx::TableLayouter::LayoutTableWidtht(), layouting failed!" );
615 // now check if merged cells fit
616 for( nCol
= 1; nCol
< nColCount
; ++nCol
)
618 bool bChanges
= false;
619 MergeableCellVector::iterator
iter( aMergedCells
[nCol
].begin() );
621 const sal_Int32 nOldSize
= maColumns
[nCol
].mnSize
;
623 while( iter
!= aMergedCells
[nCol
].end() )
625 CellRef
xCell( (*iter
++) );
626 sal_Int32 nMinWidth
= xCell
->getMinimumSize().Width
;
628 for( sal_Int32 nMCol
= nCol
- xCell
->getColumnSpan() + 1; (nMCol
> 0) && (nMCol
< nCol
); ++nMCol
)
629 nMinWidth
-= maColumns
[nMCol
].mnSize
;
631 if( nMinWidth
> maColumns
[nCol
].mnMinSize
)
632 maColumns
[nCol
].mnMinSize
= nMinWidth
;
634 if( nMinWidth
> maColumns
[nCol
].mnSize
)
636 maColumns
[nCol
].mnSize
= nMinWidth
;
642 nCurrentWidth
+= maColumns
[nCol
].mnSize
- nOldSize
;
645 // now scale if wanted and needed
646 if( bFit
&& (nCurrentWidth
!= rArea
.getWidth()) )
647 distribute( maColumns
, rArea
.getWidth() - nCurrentWidth
);
649 // last step, update left edges
650 sal_Int32 nNewWidth
= 0;
652 const bool bRTL
= meWritingMode
== WritingMode_RL_TB
;
653 RangeIterator
<sal_Int32
> coliter( 0, nColCount
, !bRTL
);
654 while( coliter
.next(nCol
) )
656 maColumns
[nCol
].mnPos
= nNewWidth
;
657 nNewWidth
+= maColumns
[nCol
].mnSize
;
660 Reference
< XPropertySet
> xColSet( xCols
->getByIndex(nCol
), UNO_QUERY_THROW
);
661 xColSet
->setPropertyValue( msSize
, Any( maColumns
[nCol
].mnSize
) );
665 rArea
.SetSize( Size( nNewWidth
, rArea
.GetHeight() ) );
666 updateCells( rArea
);
669 // -----------------------------------------------------------------------------
671 void TableLayouter::LayoutTableHeight( Rectangle
& rArea
, bool bFit
)
673 const sal_Int32 nColCount
= getColumnCount();
674 const sal_Int32 nRowCount
= getRowCount();
678 Reference
< XTableRows
> xRows( mxTable
->getRows() );
680 MergeVector
aMergedCells( nRowCount
);
681 Int32Vector aOptimalRows
;
683 const OUString
sOptimalSize("OptimalSize");
685 // first calculate current height and initial minimum size per column,
686 // merged cells will be counted later
687 sal_Int32 nCurrentHeight
= 0;
688 sal_Int32 nCol
, nRow
;
689 for( nRow
= 0; nRow
< nRowCount
; ++nRow
)
691 sal_Int32 nMinHeight
= 0;
693 bool bIsEmpty
= true; // check if all cells in this row are merged
695 for( nCol
= 0; nCol
< nColCount
; ++nCol
)
697 CellRef
xCell( getCell( CellPos( nCol
, nRow
) ) );
698 if( xCell
.is() && !xCell
->isMerged() )
702 sal_Int32 nRowSpan
= xCell
->getRowSpan();
705 // merged cells will be evaluated later
706 aMergedCells
[nRow
+nRowSpan
-1].push_back( xCell
);
710 nMinHeight
= std::max( nMinHeight
, xCell
->getMinimumSize().Height
);
715 maRows
[nRow
].mnMinSize
= nMinHeight
;
719 maRows
[nRow
].mnSize
= 0;
723 sal_Int32 nRowHeight
= 0;
724 Reference
< XPropertySet
> xRowSet( xRows
->getByIndex(nRow
), UNO_QUERY_THROW
);
726 sal_Bool bOptimal
= sal_False
;
727 xRowSet
->getPropertyValue( sOptimalSize
) >>= bOptimal
;
730 aOptimalRows
.push_back( nRow
);
734 xRowSet
->getPropertyValue( msSize
) >>= nRowHeight
;
737 maRows
[nRow
].mnSize
= nRowHeight
;
739 if( maRows
[nRow
].mnSize
< nMinHeight
)
740 maRows
[nRow
].mnSize
= nMinHeight
;
742 nCurrentHeight
+= maRows
[nRow
].mnSize
;
746 // if we have optimal sized rows, distribute what is given (left)
747 if( !bFit
&& !aOptimalRows
.empty() && (nCurrentHeight
< rArea
.getHeight()) )
749 sal_Int32 nLeft
= rArea
.getHeight() - nCurrentHeight
;
750 sal_Int32 nDistribute
= nLeft
/ aOptimalRows
.size();
752 Int32Vector::iterator
iter( aOptimalRows
.begin() );
753 while( iter
!= aOptimalRows
.end() )
755 sal_Int32 nOptRow
= (*iter
++);
756 if( iter
== aOptimalRows
.end() )
759 maRows
[nOptRow
].mnSize
+= nDistribute
;
760 nLeft
-= nDistribute
;
764 DBG_ASSERT( nLeft
== 0, "svx::TableLayouter::LayoutTableHeight(), layouting failed!" );
767 // now check if merged cells fit
768 for( nRow
= 1; nRow
< nRowCount
; ++nRow
)
770 bool bChanges
= false;
771 sal_Int32 nOldSize
= maRows
[nRow
].mnSize
;
773 MergeableCellVector::iterator
iter( aMergedCells
[nRow
].begin() );
774 while( iter
!= aMergedCells
[nRow
].end() )
776 CellRef
xCell( (*iter
++) );
777 sal_Int32 nMinHeight
= xCell
->getMinimumSize().Height
;
779 for( sal_Int32 nMRow
= nRow
- xCell
->getRowSpan() + 1; (nMRow
> 0) && (nMRow
< nRow
); ++nMRow
)
780 nMinHeight
-= maRows
[nMRow
].mnSize
;
782 if( nMinHeight
> maRows
[nRow
].mnMinSize
)
783 maRows
[nRow
].mnMinSize
= nMinHeight
;
785 if( nMinHeight
> maRows
[nRow
].mnSize
)
787 maRows
[nRow
].mnSize
= nMinHeight
;
792 nCurrentHeight
+= maRows
[nRow
].mnSize
- nOldSize
;
795 // now scale if wanted and needed
796 if( bFit
&& nCurrentHeight
!= rArea
.getHeight() )
797 distribute( maRows
, rArea
.getHeight() - nCurrentHeight
);
799 // last step, update left edges
800 sal_Int32 nNewHeight
= 0;
801 for( nRow
= 0; nRow
< nRowCount
; ++nRow
)
803 maRows
[nRow
].mnPos
= nNewHeight
;
804 nNewHeight
+= maRows
[nRow
].mnSize
;
808 Reference
< XPropertySet
> xRowSet( xRows
->getByIndex(nRow
), UNO_QUERY_THROW
);
809 xRowSet
->setPropertyValue( msSize
, Any( maRows
[nRow
].mnSize
) );
813 rArea
.SetSize( Size( rArea
.GetWidth(), nNewHeight
) );
814 updateCells( rArea
);
817 // -----------------------------------------------------------------------------
819 /** try to fit the table into the given rectangle.
820 If the rectangle is to small, it will be grown to fit the table. */
821 void TableLayouter::LayoutTable( Rectangle
& rRectangle
, bool bFitWidth
, bool bFitHeight
)
826 const sal_Int32 nRowCount
= mxTable
->getRowCount();
827 const sal_Int32 nColCount
= mxTable
->getColumnCount();
829 if( (nRowCount
!= getRowCount()) || (nColCount
!= getColumnCount()) )
831 if( static_cast< sal_Int32
>( maRows
.size() ) != nRowCount
)
832 maRows
.resize( nRowCount
);
834 Reference
< XTableRows
> xRows( mxTable
->getRows() );
835 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
836 maRows
[nRow
].clear();
838 if( static_cast< sal_Int32
>( maColumns
.size() ) != nColCount
)
839 maColumns
.resize( nColCount
);
841 for( sal_Int32 nCol
= 0; nCol
< nColCount
; nCol
++ )
842 maColumns
[nCol
].clear();
845 LayoutTableWidth( rRectangle
, bFitWidth
);
846 LayoutTableHeight( rRectangle
, bFitHeight
);
847 UpdateBorderLayout();
850 // -----------------------------------------------------------------------------
852 void TableLayouter::updateCells( Rectangle
& rRectangle
)
854 const sal_Int32 nColCount
= getColumnCount();
855 const sal_Int32 nRowCount
= getRowCount();
858 for( aPos
.mnRow
= 0; aPos
.mnRow
< nRowCount
; aPos
.mnRow
++ )
860 for( aPos
.mnCol
= 0; aPos
.mnCol
< nColCount
; aPos
.mnCol
++ )
862 CellRef
xCell( getCell( aPos
) );
865 basegfx::B2IRectangle aCellArea
;
866 getCellArea( aPos
, aCellArea
);
869 aCellRect
.Left() = aCellArea
.getMinX();
870 aCellRect
.Right() = aCellArea
.getMaxX();
871 aCellRect
.Top() = aCellArea
.getMinY();
872 aCellRect
.Bottom() = aCellArea
.getMaxY();
873 aCellRect
.Move( rRectangle
.Left(), rRectangle
.Top() );
874 xCell
->setCellRect( aCellRect
);
880 // -----------------------------------------------------------------------------
882 CellRef
TableLayouter::getCell( const CellPos
& rPos
) const
885 if( mxTable
.is() ) try
887 xCell
.set( dynamic_cast< Cell
* >( mxTable
->getCellByPosition( rPos
.mnCol
, rPos
.mnRow
).get() ) );
891 OSL_FAIL( "sdr::table::TableLayouter::getCell(), exception caught!" );
896 // -----------------------------------------------------------------------------
898 bool TableLayouter::HasPriority( const SvxBorderLine
* pThis
, const SvxBorderLine
* pOther
)
900 if (!pThis
|| ((pThis
== &gEmptyBorder
) && (pOther
!= 0)))
902 if (!pOther
|| (pOther
== &gEmptyBorder
))
905 sal_uInt16 nThisSize
= pThis
->GetOutWidth() + pThis
->GetDistance() + pThis
->GetInWidth();
906 sal_uInt16 nOtherSize
= pOther
->GetOutWidth() + pOther
->GetDistance() + pOther
->GetInWidth();
908 if (nThisSize
> nOtherSize
)
911 else if (nThisSize
< nOtherSize
)
917 if ( pOther
->GetInWidth() && !pThis
->GetInWidth() )
921 else if ( pThis
->GetInWidth() && !pOther
->GetInWidth() )
932 // -----------------------------------------------------------------------------
934 void TableLayouter::SetBorder( sal_Int32 nCol
, sal_Int32 nRow
, bool bHorizontal
, const SvxBorderLine
* pLine
)
937 pLine
= &gEmptyBorder
;
939 SvxBorderLine
*pOld
= bHorizontal
? maHorizontalBorders
[nCol
][nRow
] : maVerticalBorders
[nCol
][nRow
];
941 if( HasPriority( pLine
, pOld
) )
943 if( (pOld
!= 0) && (pOld
!= &gEmptyBorder
) )
946 SvxBorderLine
* pNew
= ( pLine
!= &gEmptyBorder
) ? new SvxBorderLine(*pLine
) : &gEmptyBorder
;
949 maHorizontalBorders
[nCol
][nRow
] = pNew
;
951 maVerticalBorders
[nCol
][nRow
] = pNew
;
955 // -----------------------------------------------------------------------------
957 void TableLayouter::ClearBorderLayout()
959 ClearBorderLayout(maHorizontalBorders
);
960 ClearBorderLayout(maVerticalBorders
);
963 // -----------------------------------------------------------------------------
965 void TableLayouter::ClearBorderLayout(BorderLineMap
& rMap
)
967 const sal_Int32 nColCount
= rMap
.size();
969 for( sal_Int32 nCol
= 0; nCol
< nColCount
; nCol
++ )
971 const sal_Int32 nRowCount
= rMap
[nCol
].size();
972 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
974 SvxBorderLine
* pLine
= rMap
[nCol
][nRow
];
977 if( pLine
!= &gEmptyBorder
)
980 rMap
[nCol
][nRow
] = 0;
986 // -----------------------------------------------------------------------------
988 void TableLayouter::ResizeBorderLayout()
991 ResizeBorderLayout(maHorizontalBorders
);
992 ResizeBorderLayout(maVerticalBorders
);
995 // -----------------------------------------------------------------------------
997 void TableLayouter::ResizeBorderLayout( BorderLineMap
& rMap
)
999 const sal_Int32 nColCount
= getColumnCount() + 1;
1000 const sal_Int32 nRowCount
= getRowCount() + 1;
1002 if( sal::static_int_cast
<sal_Int32
>(rMap
.size()) != nColCount
)
1003 rMap
.resize( nColCount
);
1005 for( sal_Int32 nCol
= 0; nCol
< nColCount
; nCol
++ )
1007 if( sal::static_int_cast
<sal_Int32
>(rMap
[nCol
].size()) != nRowCount
)
1008 rMap
[nCol
].resize( nRowCount
);
1012 // -----------------------------------------------------------------------------
1014 void TableLayouter::UpdateBorderLayout()
1016 // make sure old border layout is cleared and border maps have correct size
1017 ResizeBorderLayout();
1019 const sal_Int32 nColCount
= getColumnCount();
1020 const sal_Int32 nRowCount
= getRowCount();
1023 for( aPos
.mnRow
= 0; aPos
.mnRow
< nRowCount
; aPos
.mnRow
++ )
1025 for( aPos
.mnCol
= 0; aPos
.mnCol
< nColCount
; aPos
.mnCol
++ )
1027 CellRef
xCell( getCell( aPos
) );
1031 const SvxBoxItem
* pThisAttr
= (const SvxBoxItem
*)xCell
->GetItemSet().GetItem( SDRATTR_TABLE_BORDER
);
1032 OSL_ENSURE(pThisAttr
,"sdr::table::TableLayouter::UpdateBorderLayout(), no border attribute?");
1037 const sal_Int32 nLastRow
= xCell
->getRowSpan() + aPos
.mnRow
;
1038 const sal_Int32 nLastCol
= xCell
->getColumnSpan() + aPos
.mnCol
;
1040 for( sal_Int32 nRow
= aPos
.mnRow
; nRow
< nLastRow
; nRow
++ )
1042 SetBorder( aPos
.mnCol
, nRow
, false, pThisAttr
->GetLeft() );
1043 SetBorder( nLastCol
, nRow
, false, pThisAttr
->GetRight() );
1046 for( sal_Int32 nCol
= aPos
.mnCol
; nCol
< nLastCol
; nCol
++ )
1048 SetBorder( nCol
, aPos
.mnRow
, true, pThisAttr
->GetTop() );
1049 SetBorder( nCol
, nLastRow
, true, pThisAttr
->GetBottom() );
1055 // -----------------------------------------------------------------------------
1057 void TableLayouter::DistributeColumns( ::Rectangle
& rArea
, sal_Int32 nFirstCol
, sal_Int32 nLastCol
)
1059 if( mxTable
.is() ) try
1061 const sal_Int32 nColCount
= getColumnCount();
1063 if( (nFirstCol
< 0) || (nFirstCol
>= nLastCol
) || (nLastCol
>= nColCount
) )
1066 sal_Int32 nAllWidth
= 0;
1067 for( sal_Int32 nCol
= nFirstCol
; nCol
<= nLastCol
; ++nCol
)
1068 nAllWidth
+= getColumnWidth(nCol
);
1070 sal_Int32 nWidth
= nAllWidth
/ (nLastCol
-nFirstCol
+1);
1072 Reference
< XTableColumns
> xCols( mxTable
->getColumns(), UNO_QUERY_THROW
);
1074 for( sal_Int32 nCol
= nFirstCol
; nCol
<= nLastCol
; ++nCol
)
1076 if( nCol
== nLastCol
)
1077 nWidth
= nAllWidth
; // last column get round errors
1079 Reference
< XPropertySet
> xColSet( xCols
->getByIndex( nCol
), UNO_QUERY_THROW
);
1080 xColSet
->setPropertyValue( msSize
, Any( nWidth
) );
1082 nAllWidth
-= nWidth
;
1085 LayoutTable( rArea
, true, false );
1087 catch( Exception
& e
)
1090 OSL_FAIL("sdr::table::TableLayouter::DistributeColumns(), exception caught!");
1094 // -----------------------------------------------------------------------------
1096 void TableLayouter::DistributeRows( ::Rectangle
& rArea
, sal_Int32 nFirstRow
, sal_Int32 nLastRow
)
1098 if( mxTable
.is() ) try
1100 const sal_Int32 nRowCount
= mxTable
->getRowCount();
1102 if( (nFirstRow
< 0) || (nFirstRow
>= nLastRow
) || (nLastRow
>= nRowCount
) )
1105 sal_Int32 nAllHeight
= 0;
1106 sal_Int32 nMinHeight
= 0;
1108 for( sal_Int32 nRow
= nFirstRow
; nRow
<= nLastRow
; ++nRow
)
1110 nMinHeight
= std::max( maRows
[nRow
].mnMinSize
, nMinHeight
);
1111 nAllHeight
+= maRows
[nRow
].mnSize
;
1114 const sal_Int32 nRows
= (nLastRow
-nFirstRow
+1);
1115 sal_Int32 nHeight
= nAllHeight
/ nRows
;
1117 if( nHeight
< nMinHeight
)
1119 sal_Int32 nNeededHeight
= nRows
* nMinHeight
;
1120 rArea
.Bottom() += nNeededHeight
- nAllHeight
;
1121 nHeight
= nMinHeight
;
1122 nAllHeight
= nRows
* nMinHeight
;
1125 Reference
< XTableRows
> xRows( mxTable
->getRows(), UNO_QUERY_THROW
);
1126 for( sal_Int32 nRow
= nFirstRow
; nRow
<= nLastRow
; ++nRow
)
1128 if( nRow
== nLastRow
)
1129 nHeight
= nAllHeight
; // last row get round errors
1131 Reference
< XPropertySet
> xRowSet( xRows
->getByIndex( nRow
), UNO_QUERY_THROW
);
1132 xRowSet
->setPropertyValue( msSize
, Any( nHeight
) );
1134 nAllHeight
-= nHeight
;
1137 LayoutTable( rArea
, false, true );
1139 catch( Exception
& e
)
1142 OSL_FAIL("sdr::table::TableLayouter::DistributeRows(), exception caught!");
1146 // -----------------------------------------------------------------------------
1147 void TableLayouter::SetWritingMode( com::sun::star::text::WritingMode eWritingMode
)
1149 meWritingMode
= eWritingMode
;
1154 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */