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