blob: 8be0b74d17d546317d6a118c20817d69300fda57 [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 "oox/xls/defnamesbuffer.hxx"
#include <com/sun/star/sheet/ComplexReference.hpp>
#include <com/sun/star/sheet/ExternalReference.hpp>
#include <com/sun/star/sheet/NamedRangeFlag.hpp>
#include <com/sun/star/sheet/ReferenceFlags.hpp>
#include <com/sun/star/sheet/SingleReference.hpp>
#include <com/sun/star/sheet/XFormulaTokens.hpp>
#include <com/sun/star/sheet/XPrintAreas.hpp>
#include <rtl/ustrbuf.hxx>
#include "oox/helper/attributelist.hxx"
#include "oox/helper/containerhelper.hxx"
#include "oox/helper/propertyset.hxx"
#include "oox/xls/addressconverter.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/externallinkbuffer.hxx"
#include "oox/xls/formulaparser.hxx"
#include "oox/xls/worksheetbuffer.hxx"
namespace oox {
namespace xls {
// ============================================================================
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::uno;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
// ============================================================================
namespace {
const sal_uInt32 BIFF12_DEFNAME_HIDDEN = 0x00000001;
const sal_uInt32 BIFF12_DEFNAME_FUNC = 0x00000002;
const sal_uInt32 BIFF12_DEFNAME_VBNAME = 0x00000004;
const sal_uInt32 BIFF12_DEFNAME_MACRO = 0x00000008;
const sal_uInt32 BIFF12_DEFNAME_CALCEXP = 0x00000010;
const sal_uInt32 BIFF12_DEFNAME_BUILTIN = 0x00000020;
const sal_uInt32 BIFF12_DEFNAME_PUBLISHED = 0x00008000;
const sal_uInt32 BIFF12_DEFNAME_WBPARAM = 0x00010000;
const sal_uInt16 BIFF_DEFNAME_HIDDEN = 0x0001;
const sal_uInt16 BIFF_DEFNAME_FUNC = 0x0002;
const sal_uInt16 BIFF_DEFNAME_VBNAME = 0x0004;
const sal_uInt16 BIFF_DEFNAME_MACRO = 0x0008;
const sal_uInt16 BIFF_DEFNAME_CALCEXP = 0x0010;
const sal_uInt16 BIFF_DEFNAME_BUILTIN = 0x0020;
const sal_uInt16 BIFF_DEFNAME_BIG = 0x1000;
const sal_uInt8 BIFF2_DEFNAME_FUNC = 0x02; /// BIFF2 function/command flag.
const sal_uInt16 BIFF_DEFNAME_GLOBAL = 0; /// 0 = Globally defined name.
const sal_uInt16 BIFF_REFFLAG_COL1REL = 0x0001;
const sal_uInt16 BIFF_REFFLAG_ROW1REL = 0x0002;
const sal_uInt16 BIFF_REFFLAG_COL2REL = 0x0004;
const sal_uInt16 BIFF_REFFLAG_ROW2REL = 0x0008;
// ----------------------------------------------------------------------------
const sal_Char* const spcLegacyPrefix = "Excel_BuiltIn_";
const sal_Char* const spcOoxPrefix = "_xlnm.";
const sal_Char* const sppcBaseNames[] =
{
"Consolidate_Area",
"Auto_Open",
"Auto_Close",
"Extract",
"Database",
"Criteria",
"Print_Area",
"Print_Titles",
"Recorder",
"Data_Form",
"Auto_Activate",
"Auto_Deactivate",
"Sheet_Title",
"_FilterDatabase"
};
/** Localized names for _xlnm._FilterDatabase as used in BIFF5. */
const sal_Char* const sppcFilterDbNames[] =
{
"_FilterDatabase", // English
"_FilterDatenbank" // German
};
OUString lclGetBaseName( sal_Unicode cBuiltinId )
{
OSL_ENSURE( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ), "lclGetBaseName - unsupported built-in identifier" );
OUStringBuffer aBuffer;
if( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ) )
aBuffer.appendAscii( sppcBaseNames[ cBuiltinId ] );
else
aBuffer.append( static_cast< sal_Int32 >( cBuiltinId ) );
return aBuffer.makeStringAndClear();
}
OUString lclGetPrefixedName( sal_Unicode cBuiltinId )
{
return OUStringBuffer().appendAscii( spcOoxPrefix ).append( lclGetBaseName( cBuiltinId ) ).makeStringAndClear();
}
/** returns the built-in name identifier from a perfixed built-in name, e.g. '_xlnm.Print_Area'. */
sal_Unicode lclGetBuiltinIdFromPrefixedName( const OUString& rModelName )
{
OUString aPrefix = OUString::createFromAscii( spcOoxPrefix );
sal_Int32 nPrefixLen = aPrefix.getLength();
if( rModelName.matchIgnoreAsciiCase( aPrefix ) )
{
for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
{
OUString aBaseName = lclGetBaseName( cBuiltinId );
sal_Int32 nBaseNameLen = aBaseName.getLength();
if( (rModelName.getLength() == nPrefixLen + nBaseNameLen) && rModelName.matchIgnoreAsciiCase( aBaseName, nPrefixLen ) )
return cBuiltinId;
}
}
return BIFF_DEFNAME_UNKNOWN;
}
/** returns the built-in name identifier from a built-in base name, e.g. 'Print_Area'. */
sal_Unicode lclGetBuiltinIdFromBaseName( const OUString& rModelName )
{
for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
if( rModelName.equalsIgnoreAsciiCaseAscii( sppcBaseNames[ cBuiltinId ] ) )
return cBuiltinId;
return BIFF_DEFNAME_UNKNOWN;
}
bool lclIsFilterDatabaseName( const OUString& rModelName )
{
for( const sal_Char* const* ppcName = sppcFilterDbNames; ppcName < STATIC_ARRAY_END( sppcFilterDbNames ); ++ppcName )
if( rModelName.equalsIgnoreAsciiCaseAscii( *ppcName ) )
return true;
return false;
}
OUString lclGetUpcaseModelName( const OUString& rModelName )
{
// TODO: i18n?
return rModelName.toAsciiUpperCase();
}
void lclConvertRefFlags( sal_Int32& ornFlags, sal_Int32& ornAbsPos, sal_Int32& ornRelPos, sal_Int32 nBasePos, sal_Int32 nApiRelFlag, bool bRel )
{
if( getFlag( ornFlags, nApiRelFlag ) && !bRel )
{
// convert relative to absolute
setFlag( ornFlags, nApiRelFlag, false );
ornAbsPos = nBasePos + ornRelPos;
}
else if( !getFlag( ornFlags, nApiRelFlag ) && bRel )
{
// convert absolute to relative
setFlag( ornFlags, nApiRelFlag, true );
ornRelPos = ornAbsPos - nBasePos;
}
}
void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBaseAddr, bool bColRel, bool bRowRel )
{
using namespace ::com::sun::star::sheet::ReferenceFlags;
lclConvertRefFlags(
orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn,
rBaseAddr.Column, COLUMN_RELATIVE, bColRel );
lclConvertRefFlags(
orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow,
rBaseAddr.Row, ROW_RELATIVE, bRowRel );
}
Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddr, sal_uInt16 nRelFlags )
{
if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) )
{
SingleReference aApiRef;
rRefAny >>= aApiRef;
lclConvertSingleRefFlags( aApiRef, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
return Any( aApiRef );
}
if( rRefAny.has< ComplexReference >() )
{
ComplexReference aApiRef;
rRefAny >>= aApiRef;
lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) );
return Any( aApiRef );
}
return Any();
}
} // namespace
// ============================================================================
DefinedNameModel::DefinedNameModel() :
mnSheet( -1 ),
mnFuncGroupId( -1 ),
mbMacro( false ),
mbFunction( false ),
mbVBName( false ),
mbHidden( false )
{
}
// ============================================================================
DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) :
WorkbookHelper( rHelper )
{
}
const OUString& DefinedNameBase::getUpcaseModelName() const
{
if( maUpModelName.getLength() == 0 )
maUpModelName = lclGetUpcaseModelName( maModel.maName );
return maUpModelName;
}
Any DefinedNameBase::getReference( const CellAddress& rBaseAddr ) const
{
if( maRefAny.hasValue() && (maModel.maName.getLength() >= 2) && (maModel.maName[ 0 ] == '\x01') )
{
sal_Unicode cFlagsChar = getUpcaseModelName()[ 1 ];
if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') )
{
sal_uInt16 nRelFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' );
if( maRefAny.has< ExternalReference >() )
{
ExternalReference aApiExtRef;
maRefAny >>= aApiExtRef;
Any aRefAny = lclConvertReference( aApiExtRef.Reference, rBaseAddr, nRelFlags );
if( aRefAny.hasValue() )
{
aApiExtRef.Reference <<= aRefAny;
return Any( aApiExtRef );
}
}
else
{
return lclConvertReference( maRefAny, rBaseAddr, nRelFlags );
}
}
}
return Any();
}
ApiTokenSequence DefinedNameBase::importOoxFormula( sal_Int16 nBaseSheet )
{
return (maModel.maFormula.getLength() > 0) ?
getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), maModel.maFormula ) :
getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME );
}
ApiTokenSequence DefinedNameBase::importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm )
{
return getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm );
}
ApiTokenSequence DefinedNameBase::importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
{
return (!pnFmlaSize || (*pnFmlaSize > 0)) ?
getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) :
getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME );
}
void DefinedNameBase::extractReference( const ApiTokenSequence& rTokens )
{
OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "DefinedNameBase::extractReference - unexpected call" );
maRefAny = getFormulaParser().extractReference( rTokens );
}
// ============================================================================
DefinedName::DefinedName( const WorkbookHelper& rHelper ) :
DefinedNameBase( rHelper ),
mnTokenIndex( -1 ),
mcBuiltinId( BIFF_DEFNAME_UNKNOWN ),
mnFmlaSize( 0 )
{
}
void DefinedName::importDefinedName( const AttributeList& rAttribs )
{
maModel.maName = rAttribs.getXString( XML_name, OUString() );
maModel.mnSheet = rAttribs.getInteger( XML_localSheetId, -1 );
maModel.mnFuncGroupId = rAttribs.getInteger( XML_functionGroupId, -1 );
maModel.mbMacro = rAttribs.getBool( XML_xlm, false );
maModel.mbFunction = rAttribs.getBool( XML_function, false );
maModel.mbVBName = rAttribs.getBool( XML_vbProcedure, false );
maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
/* Detect built-in state from name itself, there is no built-in flag.
Built-in names are prexixed with '_xlnm.' instead. */
mcBuiltinId = lclGetBuiltinIdFromPrefixedName( maModel.maName );
}
void DefinedName::setFormula( const OUString& rFormula )
{
maModel.maFormula = rFormula;
}
void DefinedName::importDefinedName( SequenceInputStream& rStrm )
{
sal_uInt32 nFlags;
rStrm >> nFlags;
rStrm.skip( 1 ); // keyboard shortcut
rStrm >> maModel.mnSheet >> maModel.maName;
mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
// macro function/command, hidden flag
maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 9 );
maModel.mbMacro = getFlag( nFlags, BIFF12_DEFNAME_MACRO );
maModel.mbFunction = getFlag( nFlags, BIFF12_DEFNAME_FUNC );
maModel.mbVBName = getFlag( nFlags, BIFF12_DEFNAME_VBNAME );
maModel.mbHidden = getFlag( nFlags, BIFF12_DEFNAME_HIDDEN );
// get built-in name index from name
if( getFlag( nFlags, BIFF12_DEFNAME_BUILTIN ) )
mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
// store token array data
sal_Int64 nRecPos = rStrm.tell();
sal_Int32 nFmlaSize = rStrm.readInt32();
rStrm.skip( nFmlaSize );
sal_Int32 nAddDataSize = rStrm.readInt32();
if( !rStrm.isEof() && (nFmlaSize > 0) && (nAddDataSize >= 0) && (rStrm.getRemaining() >= nAddDataSize) )
{
sal_Int32 nTotalSize = 8 + nFmlaSize + nAddDataSize;
mxFormula.reset( new StreamDataSequence );
rStrm.seek( nRecPos );
rStrm.readData( *mxFormula, nTotalSize );
}
}
void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet )
{
BiffType eBiff = getBiff();
sal_uInt16 nFlags = 0;
sal_Int16 nRefId = BIFF_DEFNAME_GLOBAL;
sal_Int16 nTabId = BIFF_DEFNAME_GLOBAL;
sal_uInt8 nNameLen = 0, nShortCut = 0;
switch( eBiff )
{
case BIFF2:
{
sal_uInt8 nFlagsBiff2;
rStrm >> nFlagsBiff2;
rStrm.skip( 1 );
rStrm >> nShortCut >> nNameLen;
mnFmlaSize = rStrm.readuInt8();
setFlag( nFlags, BIFF_DEFNAME_FUNC, getFlag( nFlagsBiff2, BIFF2_DEFNAME_FUNC ) );
maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
}
break;
case BIFF3:
case BIFF4:
rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize;
maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
break;
case BIFF5:
rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
rStrm.skip( 4 );
maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
break;
case BIFF8:
rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
rStrm.skip( 4 );
maModel.maName = rStrm.readUniStringBody( nNameLen, true );
break;
case BIFF_UNKNOWN: break;
}
// macro function/command, hidden flag
maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 6 );
maModel.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO );
maModel.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC );
maModel.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME );
maModel.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN );
// get built-in name index from name
if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
{
// name may be the built-in identifier or the built-in base name
if( maModel.maName.getLength() == 1 )
mcBuiltinId = maModel.maName[ 0 ];
else
mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
}
/* In BIFF5, '_FilterDatabase' appears as hidden user name without
built-in flag, and even worse, localized. */
else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maModel.maName ) )
{
mcBuiltinId = BIFF_DEFNAME_FILTERDATABASE;
}
// get sheet index for sheet-local names in BIFF5-BIFF8
switch( getBiff() )
{
case BIFF2:
case BIFF3:
case BIFF4:
// BIFF2-BIFF4: all defined names are sheet-local
mnCalcSheet = nCalcSheet;
break;
case BIFF5:
// #i44019# nTabId may be invalid, resolve nRefId to sheet index
if( nRefId != BIFF_DEFNAME_GLOBAL )
if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
if( pExtLink->getLinkType() == LINKTYPE_INTERNAL )
mnCalcSheet = pExtLink->getCalcSheetIndex();
break;
case BIFF8:
// convert one-based worksheet index to zero-based Calc sheet index
OSL_ENSURE( nTabId >= 0, "DefinedName::importDefinedName - invalid local sheet index" );
if( nTabId != BIFF_DEFNAME_GLOBAL )
mnCalcSheet = getWorksheets().getCalcSheetIndex( nTabId - 1 );
break;
case BIFF_UNKNOWN:
break;
}
if( (getBiff() <= BIFF4) && maModel.mbHidden && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') )
{
/* Read the token array of special internal names containing addresses
for BIFF3-BIFF4 3D references immediately. It is expected that
these names contain a simple cell reference or range reference.
Other regular defined names and external names rely on existence of
this reference. */
ApiTokenSequence aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
extractReference( aTokens );
}
else
{
/* Store record position of other defined names to be able to import
token array later. This is needed to correctly resolve references
to names that are stored later in the defined names list following
this name. */
mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) );
}
}
void DefinedName::createNameObject()
{
// do not create names for (macro) functions or VBA procedures
// #163146# do not ignore hidden names (may be regular names created by VBA scripts)
if( /*maModel.mbHidden ||*/ maModel.mbFunction || maModel.mbVBName )
return;
// skip BIFF names without stream position (e.g. BIFF3-BIFF4 internal 3D references)
if( (getFilterType() == FILTER_BIFF) && !mxBiffStrm.get() )
return;
// convert original name to final Calc name (TODO: filter invalid characters from model name)
maCalcName = isBuiltinName() ? lclGetPrefixedName( mcBuiltinId ) : maModel.maName;
// #163146# do not rename sheet-local names by default, this breaks VBA scripts
#if 0
// append sheet index for local names in multi-sheet documents
if( isWorkbookFile() && !isGlobalName() )
maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ).
append( static_cast< sal_Int32 >( mnCalcSheet + 1 ) ).makeStringAndClear();
#endif
// special flags for this name
sal_Int32 nNameFlags = 0;
using namespace ::com::sun::star::sheet::NamedRangeFlag;
if( !isGlobalName() ) switch( mcBuiltinId )
{
case BIFF_DEFNAME_CRITERIA: nNameFlags = FILTER_CRITERIA; break;
case BIFF_DEFNAME_PRINTAREA: nNameFlags = PRINT_AREA; break;
case BIFF_DEFNAME_PRINTTITLES: nNameFlags = COLUMN_HEADER | ROW_HEADER; break;
}
// create the name and insert it into the document, maCalcName will be changed to the resulting name
mxNamedRange = createNamedRangeObject( maCalcName, maModel.mnSheet, nNameFlags );
// index of this defined name used in formula token arrays
PropertySet aPropSet( mxNamedRange );
aPropSet.getProperty( mnTokenIndex, PROP_TokenIndex );
}
void DefinedName::convertFormula()
{
Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
if( !xTokens.is() )
return;
// convert and set formula of the defined name
ApiTokenSequence aTokens;
switch( getFilterType() )
{
case FILTER_OOXML:
{
if( mxFormula.get() )
{
SequenceInputStream aStrm( *mxFormula );
aTokens = importBiff12Formula( mnCalcSheet, aStrm );
}
else
aTokens = importOoxFormula( mnCalcSheet );
}
break;
case FILTER_BIFF:
{
OSL_ENSURE( mxBiffStrm.get(), "DefinedName::convertFormula - missing BIFF stream" );
if( mxBiffStrm.get() )
{
BiffInputStream& rStrm = mxBiffStrm->getStream();
BiffInputStreamPosGuard aStrmGuard( rStrm );
if( mxBiffStrm->restorePosition() )
aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
}
}
break;
case FILTER_UNKNOWN:
break;
}
xTokens->setTokens( aTokens );
// set built-in names (print ranges, repeated titles, filter ranges)
if( !isGlobalName() ) switch( mcBuiltinId )
{
case BIFF_DEFNAME_PRINTAREA:
{
Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
ApiCellRangeList aPrintRanges;
getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, mnCalcSheet );
if( xPrintAreas.is() && !aPrintRanges.empty() )
xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) );
}
break;
case BIFF_DEFNAME_PRINTTITLES:
{
Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
ApiCellRangeList aTitleRanges;
getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, mnCalcSheet );
if( xPrintAreas.is() && !aTitleRanges.empty() )
{
bool bHasRowTitles = false;
bool bHasColTitles = false;
const CellAddress& rMaxPos = getAddressConverter().getMaxAddress();
for( ApiCellRangeList::const_iterator aIt = aTitleRanges.begin(), aEnd = aTitleRanges.end(); (aIt != aEnd) && (!bHasRowTitles || !bHasColTitles); ++aIt )
{
bool bFullRow = (aIt->StartColumn == 0) && (aIt->EndColumn >= rMaxPos.Column);
bool bFullCol = (aIt->StartRow == 0) && (aIt->EndRow >= rMaxPos.Row);
if( !bHasRowTitles && bFullRow && !bFullCol )
{
xPrintAreas->setTitleRows( *aIt );
xPrintAreas->setPrintTitleRows( sal_True );
bHasRowTitles = true;
}
else if( !bHasColTitles && bFullCol && !bFullRow )
{
xPrintAreas->setTitleColumns( *aIt );
xPrintAreas->setPrintTitleColumns( sal_True );
bHasColTitles = true;
}
}
}
}
break;
}
}
bool DefinedName::getAbsoluteRange( CellRangeAddress& orRange ) const
{
/* ScNamedRangeObj::XCellRangeReferrer::getReferredCells is buggy with
relative references, so we extract an absolute reference by hand. */
Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
return xTokens.is() && getFormulaParser().extractCellRange( orRange, xTokens->getTokens(), false );
}
// ============================================================================
DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) :
WorkbookHelper( rHelper ),
mnCalcSheet( -1 )
{
}
void DefinedNamesBuffer::setLocalCalcSheet( sal_Int16 nCalcSheet )
{
OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4),
"DefinedNamesBuffer::setLocalCalcSheet - invalid call" );
mnCalcSheet = nCalcSheet;
}
DefinedNameRef DefinedNamesBuffer::importDefinedName( const AttributeList& rAttribs )
{
DefinedNameRef xDefName = createDefinedName();
xDefName->importDefinedName( rAttribs );
return xDefName;
}
void DefinedNamesBuffer::importDefinedName( SequenceInputStream& rStrm )
{
createDefinedName()->importDefinedName( rStrm );
}
void DefinedNamesBuffer::importDefinedName( BiffInputStream& rStrm )
{
createDefinedName()->importDefinedName( rStrm, mnCalcSheet );
}
void DefinedNamesBuffer::finalizeImport()
{
// first insert all names without formula definition into the document, and insert them into the maps
for( DefNameVector::iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); aIt != aEnd; ++aIt )
{
DefinedNameRef xDefName = *aIt;
xDefName->createNameObject();
// map by sheet index and original model name
maModelNameMap[ SheetNameKey( xDefName->getLocalCalcSheet(), xDefName->getUpcaseModelName() ) ] = xDefName;
// map by sheet index and built-in identifier
if( !xDefName->isGlobalName() && xDefName->isBuiltinName() )
maBuiltinMap[ BuiltinKey( xDefName->getLocalCalcSheet(), xDefName->getBuiltinId() ) ] = xDefName;
// map by API formula token identifier
sal_Int32 nTokenIndex = xDefName->getTokenIndex();
if( nTokenIndex >= 0 )
maTokenIdMap[ nTokenIndex ] = xDefName;
}
/* Now convert all name formulas, so that the formula parser can find all
names in case of circular dependencies. */
maDefNames.forEachMem( &DefinedName::convertFormula );
}
DefinedNameRef DefinedNamesBuffer::getByIndex( sal_Int32 nIndex ) const
{
return maDefNames.get( nIndex );
}
DefinedNameRef DefinedNamesBuffer::getByTokenIndex( sal_Int32 nIndex ) const
{
return maTokenIdMap.get( nIndex );
}
DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const
{
OUString aUpcaseName = lclGetUpcaseModelName( rModelName );
DefinedNameRef xDefName = maModelNameMap.get( SheetNameKey( nCalcSheet, aUpcaseName ) );
// lookup global name, if no local name exists
if( !xDefName && (nCalcSheet >= 0) )
xDefName = maModelNameMap.get( SheetNameKey( -1, aUpcaseName ) );
return xDefName;
}
DefinedNameRef DefinedNamesBuffer::getByBuiltinId( sal_Unicode cBuiltinId, sal_Int16 nCalcSheet ) const
{
return maBuiltinMap.get( BuiltinKey( nCalcSheet, cBuiltinId ) );
}
DefinedNameRef DefinedNamesBuffer::createDefinedName()
{
DefinedNameRef xDefName( new DefinedName( *this ) );
maDefNames.push_back( xDefName );
return xDefName;
}
// ============================================================================
} // namespace xls
} // namespace oox