office-gobmx/oox/source/xls/sharedformulabuffer.cxx
2008-09-30 13:51:36 +00:00

218 lines
8.4 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: sharedformulabuffer.cxx,v $
* $Revision: 1.4.20.1 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include "oox/xls/sharedformulabuffer.hxx"
#include <rtl/ustrbuf.hxx>
#include <com/sun/star/sheet/XFormulaTokens.hpp>
#include "oox/helper/propertyset.hxx"
#include "oox/helper/recordinputstream.hxx"
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/formulaparser.hxx"
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::uno::UNO_QUERY;
using ::com::sun::star::table::CellAddress;
using ::com::sun::star::table::CellRangeAddress;
using ::com::sun::star::sheet::XFormulaTokens;
using ::com::sun::star::sheet::XNamedRange;
namespace oox {
namespace xls {
// ============================================================================
namespace {
bool operator==( const CellAddress& rAddr1, const CellAddress& rAddr2 )
{
return
(rAddr1.Sheet == rAddr2.Sheet) &&
(rAddr1.Column == rAddr2.Column) &&
(rAddr1.Row == rAddr2.Row);
}
bool lclContains( const CellRangeAddress& rRange, const CellAddress& rAddr )
{
return
(rRange.Sheet == rAddr.Sheet) &&
(rRange.StartColumn <= rAddr.Column) && (rAddr.Column <= rRange.EndColumn) &&
(rRange.StartRow <= rAddr.Row) && (rAddr.Row <= rRange.EndRow);
}
} // namespace
// ============================================================================
ExtCellFormulaContext::ExtCellFormulaContext( const WorksheetHelper& rHelper,
const Reference< XFormulaTokens >& rxTokens, const CellAddress& rCellPos ) :
SimpleFormulaContext( rxTokens, false, false ),
WorksheetHelper( rHelper )
{
setBaseAddress( rCellPos );
}
void ExtCellFormulaContext::setSharedFormula( const CellAddress& rBaseAddr )
{
getSharedFormulas().setSharedFormulaCell( *this, rBaseAddr );
}
// ============================================================================
SharedFormulaBuffer::SharedFormulaBuffer( const WorksheetHelper& rHelper ) :
WorksheetHelper( rHelper ),
maIsSharedProp( CREATE_OUSTRING( "IsSharedFormula" ) )
{
}
void SharedFormulaBuffer::importSharedFmla( const OUString& rFormula, const OUString& rSharedRange, sal_Int32 nSharedId, const CellAddress& rBaseAddr )
{
CellRangeAddress aFmlaRange;
if( getAddressConverter().convertToCellRange( aFmlaRange, rSharedRange, getSheetIndex(), true ) )
{
// create the defined name representing the shared formula
OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
BinAddress aMapKey( nSharedId, 0 );
Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
// convert the formula definition
Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
if( xTokens.is() )
{
SimpleFormulaContext aContext( xTokens, true, false );
aContext.setBaseAddress( rBaseAddr );
getFormulaParser().importFormula( aContext, rFormula );
updateCachedCell( rBaseAddr, aMapKey );
}
}
}
void SharedFormulaBuffer::importSharedFmla( RecordInputStream& rStrm, const CellAddress& rBaseAddr )
{
BinRange aRange;
rStrm >> aRange;
CellRangeAddress aFmlaRange;
if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true ) )
{
// create the defined name representing the shared formula
OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
BinAddress aMapKey( rBaseAddr );
Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
// load the formula definition
Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
if( xTokens.is() )
{
SimpleFormulaContext aContext( xTokens, true, false );
aContext.setBaseAddress( rBaseAddr );
getFormulaParser().importFormula( aContext, rStrm );
updateCachedCell( rBaseAddr, aMapKey );
}
}
}
void SharedFormulaBuffer::importSharedFmla( BiffInputStream& rStrm, const CellAddress& rBaseAddr )
{
BinRange aRange;
aRange.read( rStrm, false ); // always 8bit column indexes
CellRangeAddress aFmlaRange;
if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true ) )
{
// create the defined name representing the shared formula
OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SharedFormulaBuffer::importSharedFmla - invalid range for shared formula" );
BinAddress aMapKey( rBaseAddr );
Reference< XNamedRange > xNamedRange = createDefinedName( aMapKey );
// load the formula definition
Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY );
if( xTokens.is() )
{
rStrm.skip( 2 ); // flags
SimpleFormulaContext aContext( xTokens, true, false );
aContext.setBaseAddress( rBaseAddr );
getFormulaParser().importFormula( aContext, rStrm );
updateCachedCell( rBaseAddr, aMapKey );
}
}
}
void SharedFormulaBuffer::setSharedFormulaCell( ExtCellFormulaContext& rContext, const CellAddress& rBaseAddr )
{
if( !implSetSharedFormulaCell( rContext, BinAddress( rBaseAddr ) ) )
if( rContext.getBaseAddress() == rBaseAddr )
mxLastContext.reset( new ExtCellFormulaContext( rContext ) );
}
void SharedFormulaBuffer::setSharedFormulaCell( ExtCellFormulaContext& rContext, sal_Int32 nSharedId )
{
implSetSharedFormulaCell( rContext, BinAddress( nSharedId, 0 ) );
}
Reference< XNamedRange > SharedFormulaBuffer::createDefinedName( const BinAddress& rMapKey )
{
OSL_ENSURE( maIndexMap.count( rMapKey ) == 0, "SharedFormulaBuffer::createDefinedName - shared formula exists already" );
// create the defined name representing the shared formula
OUString aName = OUStringBuffer().appendAscii( "__shared_" ).
append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) ).
append( sal_Unicode( '_' ) ).append( rMapKey.mnRow ).
append( sal_Unicode( '_' ) ).append( rMapKey.mnCol ).makeStringAndClear();
Reference< XNamedRange > xNamedRange = createNamedRangeObject( aName );
PropertySet aNameProps( xNamedRange );
aNameProps.setProperty( maIsSharedProp, true );
sal_Int32 nTokenIndex = -1;
if( aNameProps.getProperty( nTokenIndex, CREATE_OUSTRING( "TokenIndex" ) ) && (nTokenIndex >= 0) )
maIndexMap[ rMapKey ] = nTokenIndex;
return xNamedRange;
}
bool SharedFormulaBuffer::implSetSharedFormulaCell( ExtCellFormulaContext& rContext, const BinAddress& rMapKey )
{
TokenIndexMap::const_iterator aIt = maIndexMap.find( rMapKey );
sal_Int32 nTokenIndex = (aIt == maIndexMap.end()) ? -1 : aIt->second;
if( nTokenIndex >= 0 )
{
getFormulaParser().convertNameToFormula( rContext, nTokenIndex );
return true;
}
return false;
}
void SharedFormulaBuffer::updateCachedCell( const CellAddress& rBaseAddr, const BinAddress& rMapKey )
{
if( mxLastContext.get() && (mxLastContext->getBaseAddress() == rBaseAddr) )
implSetSharedFormulaCell( *mxLastContext, rMapKey );
mxLastContext.reset();
}
// ============================================================================
} // namespace xls
} // namespace oox