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