blob: f36a0baa83126fae8d2124ec30dfbe5c8c9b390b [file] [log] [blame]
/**************************************************************
*
* 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