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 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 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 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