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 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 57 bool Table::ChildData::isVisible() 58 { 59 return Box_Base::ChildData::isVisible() 60 && ( mnColSpan > 0 ) && ( mnRowSpan > 0 ); 61 } 62 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 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* 87 Table::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild ) 88 { 89 return new ChildData( xChild ); 90 } 91 92 Table::ChildProps* 93 Table::createChildProps( Box_Base::ChildData *pData ) 94 { 95 return new ChildProps( static_cast<Table::ChildData*> ( pData ) ); 96 } 97 98 void SAL_CALL 99 Table::addChild( const uno::Reference< awt::XLayoutConstrains >& xChild ) 100 { 101 if ( xChild.is() ) 102 { 103 Box_Base::addChild( xChild ); 104 // cause of flicker 105 allocateChildAt( xChild, awt::Rectangle( 0,0,0,0 ) ); 106 } 107 } 108 109 awt::Size SAL_CALL 110 Table::getMinimumSize() 111 { 112 int nRowsLen = 0; 113 114 // 1. layout the table -- adjust to cope with row-spans... 115 { 116 // temporary 1D representation of the table 117 std::vector< ChildData *> aTable; 118 119 int col = 0; 120 int row = 0; 121 for ( std::list<Box_Base::ChildData *>::iterator it 122 = maChildren.begin(); it != maChildren.end(); it++ ) 123 { 124 ChildData *child = static_cast<Table::ChildData*> ( *it ); 125 if ( !child->isVisible() ) 126 continue; 127 128 while ( col + SAL_MIN( child->mnColSpan, mnColsLen ) > mnColsLen ) 129 { 130 col = 0; 131 row++; 132 133 unsigned int i = col +( row*mnColsLen ); 134 while ( aTable.size() > i && !aTable[ i ] ) 135 i++; 136 137 col = i % mnColsLen; 138 row = i / mnColsLen; 139 } 140 141 child->mnLeftCol = col; 142 child->mnRightCol = SAL_MIN( col + child->mnColSpan, mnColsLen ); 143 child->mnTopRow = row; 144 child->mnBottomRow = row + child->mnRowSpan; 145 146 col += child->mnColSpan; 147 148 unsigned int start = child->mnLeftCol +( child->mnTopRow*mnColsLen ); 149 unsigned int end =( child->mnRightCol-1 ) +( ( child->mnBottomRow-1 )*mnColsLen ); 150 if ( aTable.size() < end+1 ) 151 aTable.resize( end+1, NULL ); 152 for ( unsigned int i = start; i < end; i++ ) 153 aTable[ i ] = child; 154 155 nRowsLen = SAL_MAX( nRowsLen, child->mnBottomRow ); 156 } 157 } 158 159 // 2. calculate columns/rows sizes 160 for ( int g = 0; g < 2; g++ ) 161 { 162 std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; 163 164 aGroup.clear(); 165 aGroup.resize( g == 0 ? mnColsLen : nRowsLen ); 166 167 // 2.1 base sizes on one-column/row children 168 for ( std::list<Box_Base::ChildData *>::iterator it 169 = maChildren.begin(); it != maChildren.end(); it++ ) 170 { 171 ChildData *child = static_cast<Table::ChildData*> ( *it ); 172 if ( !child->isVisible() ) 173 continue; 174 const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; 175 const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; 176 177 if ( nFirstAttach == nLastAttach-1 ) 178 { 179 child->maRequisition = child->mxChild->getMinimumSize(); 180 int attach = nFirstAttach; 181 int child_size = g == 0 ? child->maRequisition.Width 182 : child->maRequisition.Height; 183 aGroup[ attach ].mnSize = SAL_MAX( aGroup[ attach ].mnSize, 184 child_size ); 185 if ( child->mbExpand[ g ] ) 186 aGroup[ attach ].mbExpand = true; 187 } 188 } 189 190 // 2.2 make sure multiple-columns/rows children fit 191 for ( std::list<Box_Base::ChildData *>::iterator it 192 = maChildren.begin(); it != maChildren.end(); it++ ) 193 { 194 ChildData *child = static_cast<Table::ChildData*> ( *it ); 195 if ( !child->isVisible() ) 196 continue; 197 const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; 198 const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; 199 200 if ( nFirstAttach != nLastAttach-1 ) 201 { 202 child->maRequisition = child->mxChild->getMinimumSize(); 203 int size = 0; 204 int expandables = 0; 205 for ( int i = nFirstAttach; i < nLastAttach; i++ ) 206 { 207 size += aGroup[ i ].mnSize; 208 if ( aGroup[ i ].mbExpand ) 209 expandables++; 210 } 211 212 int child_size = g == 0 ? child->maRequisition.Width 213 : child->maRequisition.Height; 214 int extra = child_size - size; 215 if ( extra > 0 ) 216 { 217 if ( expandables ) 218 extra /= expandables; 219 else 220 extra /= nLastAttach - nFirstAttach; 221 222 for ( int i = nFirstAttach; i < nLastAttach; i++ ) 223 if ( expandables == 0 || aGroup[ i ].mbExpand ) 224 aGroup[ i ].mnSize += extra; 225 } 226 } 227 } 228 } 229 230 // 3. Sum everything up 231 mnColExpandables =( mnRowExpandables = 0 ); 232 maRequisition.Width =( maRequisition.Height = 0 ); 233 for ( std::vector<GroupData>::iterator it = maCols.begin(); 234 it != maCols.end(); it++ ) 235 { 236 maRequisition.Width += it->mnSize; 237 if ( it->mbExpand ) 238 mnColExpandables++; 239 } 240 for ( std::vector<GroupData>::iterator it = maRows.begin(); 241 it != maRows.end(); it++ ) 242 { 243 maRequisition.Height += it->mnSize; 244 if ( it->mbExpand ) 245 mnRowExpandables++; 246 } 247 248 return maRequisition; 249 } 250 251 void SAL_CALL 252 Table::allocateArea( const awt::Rectangle &rArea ) 253 { 254 maAllocation = rArea; 255 if ( maCols.size() == 0 || maRows.size() == 0 ) 256 return; 257 258 int nExtraSize[ 2 ] = { SAL_MAX( rArea.Width - maRequisition.Width, 0 ), 259 SAL_MAX( rArea.Height - maRequisition.Height, 0 ) }; 260 // split it 261 nExtraSize[ 0 ] /= mnColExpandables ? mnColExpandables : mnColsLen; 262 nExtraSize[ 1 ] /= mnRowExpandables ? mnRowExpandables : maRows.size(); 263 264 for ( std::list<Box_Base::ChildData *>::const_iterator it 265 = maChildren.begin(); it != maChildren.end(); it++ ) 266 { 267 ChildData *child = static_cast<Table::ChildData*> ( *it ); 268 if ( !child->isVisible() ) 269 continue; 270 271 awt::Rectangle rChildArea( rArea.X, rArea.Y, 0, 0 ); 272 273 for ( int g = 0; g < 2; g++ ) 274 { 275 std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; 276 const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; 277 const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; 278 279 for ( int i = 0; i < nFirstAttach; i++ ) 280 { 281 int gSize = aGroup[ i ].mnSize; 282 if ( aGroup[ i ].mbExpand ) 283 gSize += nExtraSize[ g ]; 284 if ( g == 0 ) 285 rChildArea.X += gSize; 286 else 287 rChildArea.Y += gSize; 288 } 289 for ( int i = nFirstAttach; i < nLastAttach; i++ ) 290 { 291 int gSize = aGroup[ i ].mnSize; 292 if ( aGroup[ i ].mbExpand ) 293 gSize += nExtraSize[ g ]; 294 if ( g == 0 ) 295 rChildArea.Width += gSize; 296 else 297 rChildArea.Height += gSize; 298 } 299 } 300 301 allocateChildAt( child->mxChild, rChildArea ); 302 } 303 } 304 305 } // namespace layoutimpl 306