xref: /trunk/main/toolkit/source/layout/core/table.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <table.hxx>
29 
30 #include <sal/macros.h>
31 #include <osl/mutex.hxx>
32 #include <cppuhelper/propshlp.hxx>
33 #include <cppuhelper/interfacecontainer.h>
34 #include <com/sun/star/awt/PosSize.hpp>
35 #include <tools/debug.hxx>
36 
37 // fixed point precision for distributing error
38 #define FIXED_PT 16
39 
40 namespace layoutimpl
41 {
42 
43 using namespace com::sun::star;
44 
45 Table::ChildProps::ChildProps( Table::ChildData *pData )
46 {
47     addProp( RTL_CONSTASCII_USTRINGPARAM( "XExpand" ),
48              ::getCppuType( static_cast< const sal_Bool* >( NULL ) ),
49              &( pData->mbExpand[ 0 ] ) );
50     addProp( RTL_CONSTASCII_USTRINGPARAM( "YExpand" ),
51              ::getCppuType( static_cast< const sal_Bool* >( NULL ) ),
52              &( pData->mbExpand[ 1 ] ) );
53     addProp( RTL_CONSTASCII_USTRINGPARAM( "ColSpan" ),
54              ::getCppuType( static_cast< const sal_Int32* >( NULL ) ),
55              &( pData->mnColSpan ) );
56     addProp( RTL_CONSTASCII_USTRINGPARAM( "RowSpan" ),
57              ::getCppuType( static_cast< const sal_Int32* >( NULL ) ),
58              &( pData->mnRowSpan ) );
59 }
60 
61 bool Table::ChildData::isVisible()
62 {
63     return Box_Base::ChildData::isVisible()
64         && ( mnColSpan > 0 ) && ( mnRowSpan > 0 );
65 }
66 
67 Table::Table()
68     : Box_Base()
69     , mnColsLen( 1 )// another default value could be 0xffff for infinite columns( = 1 row )
70 {
71     addProp( RTL_CONSTASCII_USTRINGPARAM( "Columns" ),
72              ::getCppuType( static_cast< const sal_Int32* >( NULL ) ),
73              &mnColsLen );
74 }
75 
76 Table::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild )
77     : Box_Base::ChildData( xChild )
78 //    , mbExpand( { 1, 1 } )
79     , mnColSpan( 1 )
80     , mnRowSpan( 1 )
81     , mnLeftCol( 0 )
82     , mnRightCol( 0 )
83     , mnTopRow( 0 )
84     , mnBottomRow( 0 )
85 {
86     mbExpand[ 0 ] = 1;
87     mbExpand[ 1 ] = 1;
88 }
89 
90 Table::ChildData*
91 Table::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild )
92 {
93     return new ChildData( xChild );
94 }
95 
96 Table::ChildProps*
97 Table::createChildProps( Box_Base::ChildData *pData )
98 {
99     return new ChildProps( static_cast<Table::ChildData*> ( pData ) );
100 }
101 
102 void SAL_CALL
103 Table::addChild( const uno::Reference< awt::XLayoutConstrains >& xChild )
104     throw( uno::RuntimeException, awt::MaxChildrenException )
105 {
106     if ( xChild.is() )
107     {
108         Box_Base::addChild( xChild );
109         // cause of flicker
110         allocateChildAt( xChild, awt::Rectangle( 0,0,0,0 ) );
111     }
112 }
113 
114 awt::Size SAL_CALL
115 Table::getMinimumSize() throw( uno::RuntimeException )
116 {
117     int nRowsLen = 0;
118 
119     // 1. layout the table -- adjust to cope with row-spans...
120     {
121         // temporary 1D representation of the table
122         std::vector< ChildData *> aTable;
123 
124         int col = 0;
125         int row = 0;
126         for ( std::list<Box_Base::ChildData *>::iterator it
127                   = maChildren.begin(); it != maChildren.end(); it++ )
128         {
129             ChildData *child = static_cast<Table::ChildData*> ( *it );
130             if ( !child->isVisible() )
131                 continue;
132 
133             while ( col + SAL_MIN( child->mnColSpan, mnColsLen ) > mnColsLen )
134             {
135                 col = 0;
136                 row++;
137 
138                 unsigned int i = col +( row*mnColsLen );
139                 while ( aTable.size() > i && !aTable[ i ] )
140                     i++;
141 
142                 col = i % mnColsLen;
143                 row = i / mnColsLen;
144             }
145 
146             child->mnLeftCol = col;
147             child->mnRightCol = SAL_MIN( col + child->mnColSpan, mnColsLen );
148             child->mnTopRow = row;
149             child->mnBottomRow = row + child->mnRowSpan;
150 
151             col += child->mnColSpan;
152 
153             unsigned int start = child->mnLeftCol +( child->mnTopRow*mnColsLen );
154             unsigned int end =( child->mnRightCol-1 ) +( ( child->mnBottomRow-1 )*mnColsLen );
155             if ( aTable.size() < end+1 )
156                 aTable.resize( end+1, NULL );
157             for ( unsigned int i = start; i < end; i++ )
158                 aTable[ i ] = child;
159 
160             nRowsLen = SAL_MAX( nRowsLen, child->mnBottomRow );
161         }
162     }
163 
164     // 2. calculate columns/rows sizes
165     for ( int g = 0; g < 2; g++ )
166     {
167         std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows;
168 
169         aGroup.clear();
170         aGroup.resize( g == 0 ? mnColsLen : nRowsLen );
171 
172         // 2.1 base sizes on one-column/row children
173         for ( std::list<Box_Base::ChildData *>::iterator it
174                   = maChildren.begin(); it != maChildren.end(); it++ )
175         {
176             ChildData *child = static_cast<Table::ChildData*> ( *it );
177             if ( !child->isVisible() )
178                 continue;
179             const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow;
180             const int nLastAttach  = g == 0 ? child->mnRightCol : child->mnBottomRow;
181 
182             if ( nFirstAttach == nLastAttach-1 )
183             {
184                 child->maRequisition = child->mxChild->getMinimumSize();
185                 int attach = nFirstAttach;
186                 int child_size = g == 0 ? child->maRequisition.Width
187                     : child->maRequisition.Height;
188                 aGroup[ attach ].mnSize = SAL_MAX( aGroup[ attach ].mnSize,
189                                                    child_size );
190                 if ( child->mbExpand[ g ] )
191                     aGroup[ attach ].mbExpand = true;
192             }
193         }
194 
195         // 2.2 make sure multiple-columns/rows children fit
196         for ( std::list<Box_Base::ChildData *>::iterator it
197                   = maChildren.begin(); it != maChildren.end(); it++ )
198         {
199             ChildData *child = static_cast<Table::ChildData*> ( *it );
200             if ( !child->isVisible() )
201                 continue;
202             const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow;
203             const int nLastAttach  = g == 0 ? child->mnRightCol : child->mnBottomRow;
204 
205             if ( nFirstAttach != nLastAttach-1 )
206             {
207                 child->maRequisition = child->mxChild->getMinimumSize();
208                 int size = 0;
209                 int expandables = 0;
210                 for ( int i = nFirstAttach; i < nLastAttach; i++ )
211                 {
212                     size += aGroup[ i ].mnSize;
213                     if ( aGroup[ i ].mbExpand )
214                         expandables++;
215                 }
216 
217                 int child_size = g == 0 ? child->maRequisition.Width
218                     : child->maRequisition.Height;
219                 int extra = child_size - size;
220                 if ( extra > 0 )
221                 {
222                     if ( expandables )
223                         extra /= expandables;
224                     else
225                         extra /= nLastAttach - nFirstAttach;
226 
227                     for ( int i = nFirstAttach; i < nLastAttach; i++ )
228                         if ( expandables == 0 || aGroup[ i ].mbExpand )
229                             aGroup[ i ].mnSize += extra;
230                 }
231             }
232         }
233     }
234 
235     // 3. Sum everything up
236     mnColExpandables =( mnRowExpandables = 0 );
237     maRequisition.Width =( maRequisition.Height = 0 );
238     for ( std::vector<GroupData>::iterator it = maCols.begin();
239           it != maCols.end(); it++ )
240     {
241         maRequisition.Width += it->mnSize;
242         if ( it->mbExpand )
243             mnColExpandables++;
244     }
245     for ( std::vector<GroupData>::iterator it = maRows.begin();
246           it != maRows.end(); it++ )
247     {
248         maRequisition.Height += it->mnSize;
249         if ( it->mbExpand )
250             mnRowExpandables++;
251     }
252 
253     return maRequisition;
254 }
255 
256 void SAL_CALL
257 Table::allocateArea( const awt::Rectangle &rArea )
258     throw( uno::RuntimeException )
259 {
260     maAllocation = rArea;
261     if ( maCols.size() == 0 || maRows.size() == 0 )
262         return;
263 
264     int nExtraSize[ 2 ] = { SAL_MAX( rArea.Width - maRequisition.Width, 0 ),
265                             SAL_MAX( rArea.Height - maRequisition.Height, 0 ) };
266     // split it
267     nExtraSize[ 0 ] /= mnColExpandables ? mnColExpandables : mnColsLen;
268     nExtraSize[ 1 ] /= mnRowExpandables ? mnRowExpandables : maRows.size();
269 
270     for ( std::list<Box_Base::ChildData *>::const_iterator it
271               = maChildren.begin(); it != maChildren.end(); it++ )
272     {
273         ChildData *child = static_cast<Table::ChildData*> ( *it );
274         if ( !child->isVisible() )
275             continue;
276 
277         awt::Rectangle rChildArea( rArea.X, rArea.Y, 0, 0 );
278 
279         for ( int g = 0; g < 2; g++ )
280         {
281             std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows;
282             const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow;
283             const int nLastAttach  = g == 0 ? child->mnRightCol : child->mnBottomRow;
284 
285             for ( int i = 0; i < nFirstAttach; i++ )
286             {
287                 int gSize = aGroup[ i ].mnSize;
288                 if ( aGroup[ i ].mbExpand )
289                     gSize += nExtraSize[ g ];
290                 if ( g == 0 )
291                     rChildArea.X += gSize;
292                 else
293                     rChildArea.Y += gSize;
294             }
295             for ( int i = nFirstAttach; i < nLastAttach; i++ )
296             {
297                 int gSize = aGroup[ i ].mnSize;
298                 if ( aGroup[ i ].mbExpand )
299                     gSize += nExtraSize[ g ];
300                 if ( g == 0 )
301                     rChildArea.Width  += gSize;
302                 else
303                     rChildArea.Height += gSize;
304             }
305         }
306 
307         allocateChildAt( child->mxChild, rChildArea );
308     }
309 }
310 
311 } // namespace layoutimpl
312