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