| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include <table.hxx> |
| |
| #include <sal/macros.h> |
| #include <osl/mutex.hxx> |
| #include <cppuhelper/propshlp.hxx> |
| #include <cppuhelper/interfacecontainer.h> |
| #include <com/sun/star/awt/PosSize.hpp> |
| #include <tools/debug.hxx> |
| |
| // fixed point precision for distributing error |
| #define FIXED_PT 16 |
| |
| namespace layoutimpl |
| { |
| |
| using namespace com::sun::star; |
| |
| Table::ChildProps::ChildProps( Table::ChildData *pData ) |
| { |
| addProp( RTL_CONSTASCII_USTRINGPARAM( "XExpand" ), |
| ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), |
| &( pData->mbExpand[ 0 ] ) ); |
| addProp( RTL_CONSTASCII_USTRINGPARAM( "YExpand" ), |
| ::getCppuType( static_cast< const sal_Bool* >( NULL ) ), |
| &( pData->mbExpand[ 1 ] ) ); |
| addProp( RTL_CONSTASCII_USTRINGPARAM( "ColSpan" ), |
| ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), |
| &( pData->mnColSpan ) ); |
| addProp( RTL_CONSTASCII_USTRINGPARAM( "RowSpan" ), |
| ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), |
| &( pData->mnRowSpan ) ); |
| } |
| |
| bool Table::ChildData::isVisible() |
| { |
| return Box_Base::ChildData::isVisible() |
| && ( mnColSpan > 0 ) && ( mnRowSpan > 0 ); |
| } |
| |
| Table::Table() |
| : Box_Base() |
| , mnColsLen( 1 )// another default value could be 0xffff for infinite columns( = 1 row ) |
| { |
| addProp( RTL_CONSTASCII_USTRINGPARAM( "Columns" ), |
| ::getCppuType( static_cast< const sal_Int32* >( NULL ) ), |
| &mnColsLen ); |
| } |
| |
| Table::ChildData::ChildData( uno::Reference< awt::XLayoutConstrains > const& xChild ) |
| : Box_Base::ChildData( xChild ) |
| // , mbExpand( { 1, 1 } ) |
| , mnColSpan( 1 ) |
| , mnRowSpan( 1 ) |
| , mnLeftCol( 0 ) |
| , mnRightCol( 0 ) |
| , mnTopRow( 0 ) |
| , mnBottomRow( 0 ) |
| { |
| mbExpand[ 0 ] = 1; |
| mbExpand[ 1 ] = 1; |
| } |
| |
| Table::ChildData* |
| Table::createChild( uno::Reference< awt::XLayoutConstrains > const& xChild ) |
| { |
| return new ChildData( xChild ); |
| } |
| |
| Table::ChildProps* |
| Table::createChildProps( Box_Base::ChildData *pData ) |
| { |
| return new ChildProps( static_cast<Table::ChildData*> ( pData ) ); |
| } |
| |
| void SAL_CALL |
| Table::addChild( const uno::Reference< awt::XLayoutConstrains >& xChild ) |
| throw( uno::RuntimeException, awt::MaxChildrenException ) |
| { |
| if ( xChild.is() ) |
| { |
| Box_Base::addChild( xChild ); |
| // cause of flicker |
| allocateChildAt( xChild, awt::Rectangle( 0,0,0,0 ) ); |
| } |
| } |
| |
| awt::Size SAL_CALL |
| Table::getMinimumSize() throw( uno::RuntimeException ) |
| { |
| int nRowsLen = 0; |
| |
| // 1. layout the table -- adjust to cope with row-spans... |
| { |
| // temporary 1D representation of the table |
| std::vector< ChildData *> aTable; |
| |
| int col = 0; |
| int row = 0; |
| for ( std::list<Box_Base::ChildData *>::iterator it |
| = maChildren.begin(); it != maChildren.end(); it++ ) |
| { |
| ChildData *child = static_cast<Table::ChildData*> ( *it ); |
| if ( !child->isVisible() ) |
| continue; |
| |
| while ( col + SAL_MIN( child->mnColSpan, mnColsLen ) > mnColsLen ) |
| { |
| col = 0; |
| row++; |
| |
| unsigned int i = col +( row*mnColsLen ); |
| while ( aTable.size() > i && !aTable[ i ] ) |
| i++; |
| |
| col = i % mnColsLen; |
| row = i / mnColsLen; |
| } |
| |
| child->mnLeftCol = col; |
| child->mnRightCol = SAL_MIN( col + child->mnColSpan, mnColsLen ); |
| child->mnTopRow = row; |
| child->mnBottomRow = row + child->mnRowSpan; |
| |
| col += child->mnColSpan; |
| |
| unsigned int start = child->mnLeftCol +( child->mnTopRow*mnColsLen ); |
| unsigned int end =( child->mnRightCol-1 ) +( ( child->mnBottomRow-1 )*mnColsLen ); |
| if ( aTable.size() < end+1 ) |
| aTable.resize( end+1, NULL ); |
| for ( unsigned int i = start; i < end; i++ ) |
| aTable[ i ] = child; |
| |
| nRowsLen = SAL_MAX( nRowsLen, child->mnBottomRow ); |
| } |
| } |
| |
| // 2. calculate columns/rows sizes |
| for ( int g = 0; g < 2; g++ ) |
| { |
| std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; |
| |
| aGroup.clear(); |
| aGroup.resize( g == 0 ? mnColsLen : nRowsLen ); |
| |
| // 2.1 base sizes on one-column/row children |
| for ( std::list<Box_Base::ChildData *>::iterator it |
| = maChildren.begin(); it != maChildren.end(); it++ ) |
| { |
| ChildData *child = static_cast<Table::ChildData*> ( *it ); |
| if ( !child->isVisible() ) |
| continue; |
| const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; |
| const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; |
| |
| if ( nFirstAttach == nLastAttach-1 ) |
| { |
| child->maRequisition = child->mxChild->getMinimumSize(); |
| int attach = nFirstAttach; |
| int child_size = g == 0 ? child->maRequisition.Width |
| : child->maRequisition.Height; |
| aGroup[ attach ].mnSize = SAL_MAX( aGroup[ attach ].mnSize, |
| child_size ); |
| if ( child->mbExpand[ g ] ) |
| aGroup[ attach ].mbExpand = true; |
| } |
| } |
| |
| // 2.2 make sure multiple-columns/rows children fit |
| for ( std::list<Box_Base::ChildData *>::iterator it |
| = maChildren.begin(); it != maChildren.end(); it++ ) |
| { |
| ChildData *child = static_cast<Table::ChildData*> ( *it ); |
| if ( !child->isVisible() ) |
| continue; |
| const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; |
| const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; |
| |
| if ( nFirstAttach != nLastAttach-1 ) |
| { |
| child->maRequisition = child->mxChild->getMinimumSize(); |
| int size = 0; |
| int expandables = 0; |
| for ( int i = nFirstAttach; i < nLastAttach; i++ ) |
| { |
| size += aGroup[ i ].mnSize; |
| if ( aGroup[ i ].mbExpand ) |
| expandables++; |
| } |
| |
| int child_size = g == 0 ? child->maRequisition.Width |
| : child->maRequisition.Height; |
| int extra = child_size - size; |
| if ( extra > 0 ) |
| { |
| if ( expandables ) |
| extra /= expandables; |
| else |
| extra /= nLastAttach - nFirstAttach; |
| |
| for ( int i = nFirstAttach; i < nLastAttach; i++ ) |
| if ( expandables == 0 || aGroup[ i ].mbExpand ) |
| aGroup[ i ].mnSize += extra; |
| } |
| } |
| } |
| } |
| |
| // 3. Sum everything up |
| mnColExpandables =( mnRowExpandables = 0 ); |
| maRequisition.Width =( maRequisition.Height = 0 ); |
| for ( std::vector<GroupData>::iterator it = maCols.begin(); |
| it != maCols.end(); it++ ) |
| { |
| maRequisition.Width += it->mnSize; |
| if ( it->mbExpand ) |
| mnColExpandables++; |
| } |
| for ( std::vector<GroupData>::iterator it = maRows.begin(); |
| it != maRows.end(); it++ ) |
| { |
| maRequisition.Height += it->mnSize; |
| if ( it->mbExpand ) |
| mnRowExpandables++; |
| } |
| |
| return maRequisition; |
| } |
| |
| void SAL_CALL |
| Table::allocateArea( const awt::Rectangle &rArea ) |
| throw( uno::RuntimeException ) |
| { |
| maAllocation = rArea; |
| if ( maCols.size() == 0 || maRows.size() == 0 ) |
| return; |
| |
| int nExtraSize[ 2 ] = { SAL_MAX( rArea.Width - maRequisition.Width, 0 ), |
| SAL_MAX( rArea.Height - maRequisition.Height, 0 ) }; |
| // split it |
| nExtraSize[ 0 ] /= mnColExpandables ? mnColExpandables : mnColsLen; |
| nExtraSize[ 1 ] /= mnRowExpandables ? mnRowExpandables : maRows.size(); |
| |
| for ( std::list<Box_Base::ChildData *>::const_iterator it |
| = maChildren.begin(); it != maChildren.end(); it++ ) |
| { |
| ChildData *child = static_cast<Table::ChildData*> ( *it ); |
| if ( !child->isVisible() ) |
| continue; |
| |
| awt::Rectangle rChildArea( rArea.X, rArea.Y, 0, 0 ); |
| |
| for ( int g = 0; g < 2; g++ ) |
| { |
| std::vector< GroupData > &aGroup = g == 0 ? maCols : maRows; |
| const int nFirstAttach = g == 0 ? child->mnLeftCol : child->mnTopRow; |
| const int nLastAttach = g == 0 ? child->mnRightCol : child->mnBottomRow; |
| |
| for ( int i = 0; i < nFirstAttach; i++ ) |
| { |
| int gSize = aGroup[ i ].mnSize; |
| if ( aGroup[ i ].mbExpand ) |
| gSize += nExtraSize[ g ]; |
| if ( g == 0 ) |
| rChildArea.X += gSize; |
| else |
| rChildArea.Y += gSize; |
| } |
| for ( int i = nFirstAttach; i < nLastAttach; i++ ) |
| { |
| int gSize = aGroup[ i ].mnSize; |
| if ( aGroup[ i ].mbExpand ) |
| gSize += nExtraSize[ g ]; |
| if ( g == 0 ) |
| rChildArea.Width += gSize; |
| else |
| rChildArea.Height += gSize; |
| } |
| } |
| |
| allocateChildAt( child->mxChild, rChildArea ); |
| } |
| } |
| |
| } // namespace layoutimpl |