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