diff options
Diffstat (limited to 'sc/source/filter/excel/xename.cxx')
-rw-r--r-- | sc/source/filter/excel/xename.cxx | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xename.cxx b/sc/source/filter/excel/xename.cxx new file mode 100644 index 000000000000..b4de1126959d --- /dev/null +++ b/sc/source/filter/excel/xename.cxx @@ -0,0 +1,790 @@ +/************************************************************************* + * + * 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: xename.cxx,v $ + * $Revision: 1.11 $ + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" +#include "xename.hxx" + +#include <map> + +#include "globstr.hrc" +#include "document.hxx" +#include "rangenam.hxx" +#include "dbcolect.hxx" +#include "xehelper.hxx" +#include "xelink.hxx" + +// for filter manager +#include "excrecds.hxx" + +#include <oox/core/tokens.hxx> +#include <formula/grammar.hxx> + +using ::rtl::OString; + +// ============================================================================ +// *** Helper classes *** +// ============================================================================ + +/** Represents an internal defined name, supports writing it to a NAME record. */ +class XclExpName : public XclExpRecord, protected XclExpRoot +{ +public: + /** Creates a standard defined name. */ + explicit XclExpName( const XclExpRoot& rRoot, const String& rName ); + /** Creates a built-in defined name. */ + explicit XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn ); + + /** Sets a token array containing the definition of this name. */ + void SetTokenArray( XclTokenArrayRef xTokArr ); + /** Changes this defined name to be local on the specified Calc sheet. */ + void SetLocalTab( SCTAB nScTab ); + /** Hides or unhides the defined name. */ + void SetHidden( bool bHidden = true ); + /** Changes this name to be the call to a VB macro function or procedure. + @param bVBasic true = Visual Basic macro, false = Sheet macro. + @param bFunc true = Macro function; false = Macro procedure. */ + void SetMacroCall( bool bVBasic, bool bFunc ); + + + /** Sets the name's symbol value + @param sValue the name's symbolic value */ + void SetSymbol( String sValue ); + /** Returns the name's symbol value */ + inline const String& GetSymbol() const { return msSymbol; } + + /** Returns the original name (title) of this defined name. */ + inline const String& GetOrigName() const { return maOrigName; } + /** Returns the Excel built-in name index of this defined name. + @return The built-in name index or EXC_BUILTIN_UNKNOWN for user-defined names. */ + inline sal_Unicode GetBuiltInName() const { return mcBuiltIn; } + + /** Returns the token array for this defined name. */ + inline XclTokenArrayRef GetTokenArray() const { return mxTokArr; } + + /** Returns true, if this is a document-global defined name. */ + inline bool IsGlobal() const { return mnXclTab == EXC_NAME_GLOBAL; } + /** Returns the Calc sheet of a local defined name. */ + inline SCTAB GetScTab() const { return mnScTab; } + + /** Returns true, if this defined name is volatile. */ + bool IsVolatile() const; + /** Returns true, if this defined name is hidden. */ + bool IsHidden() const; + /** Returns true, if this defined name describes a macro call. + @param bFunc true = Macro function; false = Macro procedure. */ + bool IsMacroCall( bool bVBasic, bool bFunc ) const; + + /** Writes the entire NAME record to the passed stream. */ + virtual void Save( XclExpStream& rStrm ); + + virtual void SaveXml( XclExpXmlStream& rStrm ); + +private: + /** Writes the body of the NAME record to the passed stream. */ + virtual void WriteBody( XclExpStream& rStrm ); + +private: + String maOrigName; /// The original user-defined name. + String msSymbol; /// The value of the symbol + XclExpStringRef mxName; /// The name as Excel string object. + XclTokenArrayRef mxTokArr; /// The definition of the defined name. + sal_Unicode mcBuiltIn; /// The built-in index for built-in names. + SCTAB mnScTab; /// The Calc sheet index for local names. + sal_uInt16 mnFlags; /// Additional flags for this defined name. + sal_uInt16 mnExtSheet; /// The 1-based index to a global EXTERNSHEET record. + sal_uInt16 mnXclTab; /// The 1-based Excel sheet index for local names. +}; + +// ---------------------------------------------------------------------------- + +class ScRangeData; +class ScDBData; + +/** Implementation class of the name manager. */ +class XclExpNameManagerImpl : protected XclExpRoot +{ +public: + explicit XclExpNameManagerImpl( const XclExpRoot& rRoot ); + + /** Creates NAME records for built-in and user defined names. */ + void Initialize(); + + /** Inserts the Calc name with the passed index and returns the Excel NAME index. */ + sal_uInt16 InsertName( USHORT nScNameIdx ); + /** Inserts the Calc database range with the passed index and returns the Excel NAME index. */ + sal_uInt16 InsertDBRange( USHORT nScDBRangeIdx ); + + /** Inserts a new built-in defined name. */ + sal_uInt16 InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab ); + /** Inserts a new defined name. Sets another unused name, if rName already exists. */ + sal_uInt16 InsertUniqueName( const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab ); + /** Returns index of an existing name, or creates a name without definition. */ + sal_uInt16 InsertRawName( const String& rName ); + /** Searches or inserts a defined name describing a macro name. + @param bVBasic true = Visual Basic macro; false = Sheet macro. + @param bFunc true = Macro function; false = Macro procedure. */ + sal_uInt16 InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden ); + + /** Returns the NAME record at the specified position or 0 on error. */ + const XclExpName* GetName( sal_uInt16 nNameIdx ) const; + + /** Writes the entire list of NAME records. + @descr In BIFF7 and lower, writes the entire global link table, which + consists of an EXTERNCOUNT record, several EXTERNSHEET records, and + the list of NAME records. */ + void Save( XclExpStream& rStrm ); + + void SaveXml( XclExpXmlStream& rStrm ); + +private: + typedef XclExpRecordList< XclExpName > XclExpNameList; + typedef XclExpNameList::RecordRefType XclExpNameRef; + typedef ::std::map< USHORT, sal_uInt16 > XclExpIndexMap; + +private: + /** Finds the index of a NAME record from the passed Calc index in the specified map. */ + sal_uInt16 FindNameIdx( const XclExpIndexMap& rMap, USHORT nScIdx ) const; + /** Returns the index of an existing built-in NAME record with the passed definition, otherwise 0. */ + sal_uInt16 FindBuiltInNameIdx( const String& rName, + const XclTokenArray& rTokArr, bool bDBRange ) const; + /** Returns an unused name for the passed name. */ + String GetUnusedName( const String& rName ) const; + + /** Appends a new NAME record to the record list. + @return The 1-based NAME record index used elsewhere in the Excel file. */ + sal_uInt16 Append( XclExpNameRef xName ); + /** Creates a new NAME record for the passed user-defined name. + @return The 1-based NAME record index used elsewhere in the Excel file. */ + sal_uInt16 CreateName( const ScRangeData& rRangeData ); + /** Creates a new NAME record for the passed database range. + @return The 1-based NAME record index used elsewhere in the Excel file. */ + sal_uInt16 CreateName( const ScDBData& rDBData ); + + /** Creates NAME records for all built-in names in the document. */ + void CreateBuiltInNames(); + /** Creates NAME records for all user-defined names in the document. */ + void CreateUserNames(); + /** Creates NAME records for all database ranges in the document. */ + void CreateDatabaseNames(); + +private: + XclExpNameList maNameList; /// List of NAME records. + XclExpIndexMap maNameMap; /// Maps Calc defined names to Excel NAME records. + XclExpIndexMap maDBRangeMap; /// Maps Calc database ranges to Excel NAME records. + String maUnnamedDBName; /// Name of the hidden unnamed database range. + size_t mnFirstUserIdx; /// List index of first user-defined NAME record. +}; + +// ============================================================================ +// *** Implementation *** +// ============================================================================ + +XclExpName::XclExpName( const XclExpRoot& rRoot, const String& rName ) : + XclExpRecord( EXC_ID_NAME ), + XclExpRoot( rRoot ), + maOrigName( rName ), + mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ), + mcBuiltIn( EXC_BUILTIN_UNKNOWN ), + mnScTab( SCTAB_GLOBAL ), + mnFlags( EXC_NAME_DEFAULT ), + mnExtSheet( EXC_NAME_GLOBAL ), + mnXclTab( EXC_NAME_GLOBAL ) +{ +} + +XclExpName::XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn ) : + XclExpRecord( EXC_ID_NAME ), + XclExpRoot( rRoot ), + mcBuiltIn( cBuiltIn ), + mnScTab( SCTAB_GLOBAL ), + mnFlags( EXC_NAME_DEFAULT ), + mnExtSheet( EXC_NAME_GLOBAL ), + mnXclTab( EXC_NAME_GLOBAL ) +{ + // filter source range is hidden in Excel + if( cBuiltIn == EXC_BUILTIN_FILTERDATABASE ) + SetHidden(); + + // special case for BIFF5/7 filter source range - name appears as plain text without built-in flag + if( (GetBiff() <= EXC_BIFF5) && (cBuiltIn == EXC_BUILTIN_FILTERDATABASE) ) + { + String aName( XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE ) ); + mxName = XclExpStringHelper::CreateString( rRoot, aName, EXC_STR_8BITLENGTH ); + } + else + { + mxName = XclExpStringHelper::CreateString( rRoot, cBuiltIn, EXC_STR_8BITLENGTH ); + ::set_flag( mnFlags, EXC_NAME_BUILTIN ); + } +} + +void XclExpName::SetTokenArray( XclTokenArrayRef xTokArr ) +{ + mxTokArr = xTokArr; +} + +void XclExpName::SetLocalTab( SCTAB nScTab ) +{ + DBG_ASSERT( GetTabInfo().IsExportTab( nScTab ), "XclExpName::SetLocalTab - invalid sheet index" ); + if( GetTabInfo().IsExportTab( nScTab ) ) + { + mnScTab = nScTab; + GetGlobalLinkManager().FindExtSheet( mnExtSheet, mnXclTab, nScTab ); + + // special handling for NAME record + switch( GetBiff() ) + { + case EXC_BIFF5: // EXTERNSHEET index is positive in NAME record + mnExtSheet = ~mnExtSheet + 1; + break; + case EXC_BIFF8: // EXTERNSHEET index not used, but must be created in link table + mnExtSheet = 0; + break; + default: DBG_ERROR_BIFF(); + } + + // Excel sheet index is 1-based + ++mnXclTab; + } +} + +void XclExpName::SetHidden( bool bHidden ) +{ + ::set_flag( mnFlags, EXC_NAME_HIDDEN, bHidden ); +} + +void XclExpName::SetMacroCall( bool bVBasic, bool bFunc ) +{ + ::set_flag( mnFlags, EXC_NAME_PROC ); + ::set_flag( mnFlags, EXC_NAME_VB, bVBasic ); + ::set_flag( mnFlags, EXC_NAME_FUNC, bFunc ); +} + +void XclExpName::SetSymbol( String sSymbol ) +{ + msSymbol = sSymbol; +} + +bool XclExpName::IsVolatile() const +{ + return mxTokArr.is() && mxTokArr->IsVolatile(); +} + +bool XclExpName::IsHidden() const +{ + return ::get_flag( mnFlags, EXC_NAME_HIDDEN ); +} + +bool XclExpName::IsMacroCall( bool bVBasic, bool bFunc ) const +{ + return + (::get_flag( mnFlags, EXC_NAME_VB ) == bVBasic) && + (::get_flag( mnFlags, EXC_NAME_FUNC ) == bFunc); +} + +void XclExpName::Save( XclExpStream& rStrm ) +{ + DBG_ASSERT( mxName.is() && (mxName->Len() > 0), "XclExpName::Save - missing name" ); + DBG_ASSERT( !(IsGlobal() && ::get_flag( mnFlags, EXC_NAME_BUILTIN )), "XclExpName::Save - global built-in name" ); + SetRecSize( 11 + mxName->GetSize() + (mxTokArr.is() ? mxTokArr->GetSize() : 2) ); + XclExpRecord::Save( rStrm ); +} + +void XclExpName::SaveXml( XclExpXmlStream& rStrm ) +{ + // For some reason, AutoFilter creates exportable names where maOrigName=="" + if( maOrigName.Len() == 0 ) + return; + + sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream(); + rWorkbook->startElement( XML_definedName, + // OOXTODO: XML_comment, "", + // OOXTODO: XML_customMenu, "", + // OOXTODO: XML_description, "", + XML_function, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ), + // OOXTODO: XML_functionGroupId, "", + // OOXTODO: XML_help, "", + XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_HIDDEN ) ), + XML_localSheetId, mnScTab == SCTAB_GLOBAL ? NULL : OString::valueOf( (sal_Int32)mnScTab ).getStr(), + XML_name, XclXmlUtils::ToOString( maOrigName ).getStr(), + // OOXTODO: XML_publishToServer, "", + // OOXTODO: XML_shortcutKey, "", + // OOXTODO: XML_statusBar, "", + XML_vbProcedure, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ), + // OOXTODO: XML_workbookParameter, "", + // OOXTODO: XML_xlm, "", + FSEND ); + rWorkbook->writeEscaped( XclXmlUtils::ToOUString( msSymbol ) ); + rWorkbook->endElement( XML_definedName ); +} + +void XclExpName::WriteBody( XclExpStream& rStrm ) +{ + sal_uInt16 nFmlaSize = mxTokArr.is() ? mxTokArr->GetSize() : 0; + + rStrm << mnFlags // flags + << sal_uInt8( 0 ); // keyboard shortcut + mxName->WriteLenField( rStrm ); // length of name + rStrm << nFmlaSize // size of token array + << mnExtSheet // BIFF5/7: EXTSHEET index, BIFF8: not used + << mnXclTab // 1-based sheet index for local names + << sal_uInt32( 0 ); // length of menu/descr/help/status text + mxName->WriteFlagField( rStrm ); // BIFF8 flag field (no-op in <=BIFF7) + mxName->WriteBuffer( rStrm ); // character array of the name + if( mxTokArr.is() ) + mxTokArr->WriteArray( rStrm ); // token array without size +} + +// ---------------------------------------------------------------------------- + +XclExpNameManagerImpl::XclExpNameManagerImpl( const XclExpRoot& rRoot ) : + XclExpRoot( rRoot ), + maUnnamedDBName( ScGlobal::GetRscString( STR_DB_NONAME ) ), + mnFirstUserIdx( 0 ) +{ +} + +void XclExpNameManagerImpl::Initialize() +{ + CreateBuiltInNames(); + mnFirstUserIdx = maNameList.GetSize(); + CreateUserNames(); + CreateDatabaseNames(); +} + +sal_uInt16 XclExpNameManagerImpl::InsertName( USHORT nScNameIdx ) +{ + sal_uInt16 nNameIdx = FindNameIdx( maNameMap, nScNameIdx ); + if( nNameIdx == 0 ) + if( const ScRangeData* pRangeData = GetNamedRanges().FindIndex( nScNameIdx ) ) + nNameIdx = CreateName( *pRangeData ); + return nNameIdx; +} + +sal_uInt16 XclExpNameManagerImpl::InsertDBRange( USHORT nScDBRangeIdx ) +{ + sal_uInt16 nNameIdx = FindNameIdx( maDBRangeMap, nScDBRangeIdx ); + if( nNameIdx == 0 ) + if( const ScDBData* pDBData = GetDatabaseRanges().FindIndex( nScDBRangeIdx ) ) + nNameIdx = CreateName( *pDBData ); + return nNameIdx; +} + +sal_uInt16 XclExpNameManagerImpl::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab ) +{ + XclExpNameRef xName( new XclExpName( GetRoot(), cBuiltIn ) ); + xName->SetTokenArray( xTokArr ); + xName->SetLocalTab( nScTab ); + return Append( xName ); +} + +sal_uInt16 XclExpNameManagerImpl::InsertUniqueName( + const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab ) +{ + DBG_ASSERT( rName.Len(), "XclExpNameManagerImpl::InsertUniqueName - empty name" ); + XclExpNameRef xName( new XclExpName( GetRoot(), GetUnusedName( rName ) ) ); + xName->SetTokenArray( xTokArr ); + xName->SetLocalTab( nScTab ); + return Append( xName ); +} + +sal_uInt16 XclExpNameManagerImpl::InsertRawName( const String& rName ) +{ + // empty name? may occur in broken external Calc tokens + if( !rName.Len() ) + return 0; + + // try to find an existing NAME record, regardless of its type + for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx ) + { + XclExpNameRef xName = maNameList.GetRecord( nListIdx ); + if( xName->IsGlobal() && (xName->GetOrigName() == rName) ) + return static_cast< sal_uInt16 >( nListIdx + 1 ); + } + + // create a new NAME record + XclExpNameRef xName( new XclExpName( GetRoot(), rName ) ); + return Append( xName ); +} + +sal_uInt16 XclExpNameManagerImpl::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden ) +{ + // empty name? may occur in broken external Calc tokens + if( !rMacroName.Len() ) + return 0; + + // try to find an existing NAME record + for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx ) + { + XclExpNameRef xName = maNameList.GetRecord( nListIdx ); + if( xName->IsMacroCall( bVBasic, bFunc ) && (xName->GetOrigName() == rMacroName) ) + return static_cast< sal_uInt16 >( nListIdx + 1 ); + } + + // create a new NAME record + XclExpNameRef xName( new XclExpName( GetRoot(), rMacroName ) ); + xName->SetMacroCall( bVBasic, bFunc ); + xName->SetHidden( bHidden ); + + // for sheet macros, add a #NAME! error + if( !bVBasic ) + xName->SetTokenArray( GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NAME ) ); + + return Append( xName ); +} + +const XclExpName* XclExpNameManagerImpl::GetName( sal_uInt16 nNameIdx ) const +{ + DBG_ASSERT( maNameList.HasRecord( nNameIdx - 1 ), "XclExpNameManagerImpl::GetName - wrong record index" ); + return maNameList.GetRecord( nNameIdx - 1 ).get(); +} + +void XclExpNameManagerImpl::Save( XclExpStream& rStrm ) +{ + maNameList.Save( rStrm ); +} + +void XclExpNameManagerImpl::SaveXml( XclExpXmlStream& rStrm ) +{ + if( maNameList.IsEmpty() ) + return; + sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream(); + rWorkbook->startElement( XML_definedNames, FSEND ); + maNameList.SaveXml( rStrm ); + rWorkbook->endElement( XML_definedNames ); +} + +// private -------------------------------------------------------------------- + +sal_uInt16 XclExpNameManagerImpl::FindNameIdx( const XclExpIndexMap& rMap, USHORT nScIdx ) const +{ + XclExpIndexMap::const_iterator aIt = rMap.find( nScIdx ); + return (aIt == rMap.end()) ? 0 : aIt->second; +} + +sal_uInt16 XclExpNameManagerImpl::FindBuiltInNameIdx( + const String& rName, const XclTokenArray& rTokArr, bool bDBRange ) const +{ + /* Get built-in index from the name. Special case: the database range + 'unnamed' will be mapped to Excel's built-in '_FilterDatabase' name. */ + sal_Unicode cBuiltIn = (bDBRange && (rName == maUnnamedDBName)) ? + EXC_BUILTIN_FILTERDATABASE : XclTools::GetBuiltInDefNameIndex( rName ); + + if( cBuiltIn < EXC_BUILTIN_UNKNOWN ) + { + // try to find the record in existing built-in NAME record list + for( size_t nPos = 0; nPos < mnFirstUserIdx; ++nPos ) + { + XclExpNameRef xName = maNameList.GetRecord( nPos ); + if( xName->GetBuiltInName() == cBuiltIn ) + { + XclTokenArrayRef xTokArr = xName->GetTokenArray(); + if( xTokArr.is() && (*xTokArr == rTokArr) ) + return static_cast< sal_uInt16 >( nPos + 1 ); + } + } + } + return 0; +} + +String XclExpNameManagerImpl::GetUnusedName( const String& rName ) const +{ + String aNewName( rName ); + sal_Int32 nAppIdx = 0; + bool bExist = true; + while( bExist ) + { + // search the list of user-defined names + bExist = false; + for( size_t nPos = mnFirstUserIdx, nSize = maNameList.GetSize(); !bExist && (nPos < nSize); ++nPos ) + { + XclExpNameRef xName = maNameList.GetRecord( nPos ); + bExist = xName->GetOrigName() == aNewName; + // name exists -> create a new name "<originalname>_<counter>" + if( bExist ) + aNewName.Assign( rName ).Append( '_' ).Append( String::CreateFromInt32( ++nAppIdx ) ); + } + } + return aNewName; +} + +sal_uInt16 XclExpNameManagerImpl::Append( XclExpNameRef xName ) +{ + if( maNameList.GetSize() == 0xFFFF ) + return 0; + maNameList.AppendRecord( xName ); + return static_cast< sal_uInt16 >( maNameList.GetSize() ); // 1-based +} + +sal_uInt16 XclExpNameManagerImpl::CreateName( const ScRangeData& rRangeData ) +{ + const String& rName = rRangeData.GetName(); + + /* #i38821# recursive names: first insert the (empty) name object, + otherwise a recursive call of this function from the formula compiler + with the same defined name will not find it and will create it again. */ + size_t nOldListSize = maNameList.GetSize(); + XclExpNameRef xName( new XclExpName( GetRoot(), rName ) ); + sal_uInt16 nNameIdx = Append( xName ); + // store the index of the NAME record in the lookup map + maNameMap[ rRangeData.GetIndex() ] = nNameIdx; + + /* Create the definition formula. + This may cause recursive creation of other defined names. */ + if( const ScTokenArray* pScTokArr = const_cast< ScRangeData& >( rRangeData ).GetCode() ) + { + XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pScTokArr ); + xName->SetTokenArray( xTokArr ); + + String sSymbol; + rRangeData.GetSymbol( sSymbol, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ); + xName->SetSymbol( sSymbol ); + + /* Try to replace by existing built-in name - complete token array is + needed for comparison, and due to the recursion problem above this + cannot be done earlier. If a built-in name is found, the created NAME + record for this name and all following records in the list must be + deleted, otherwise they may contain wrong name list indexes. */ + sal_uInt16 nBuiltInIdx = FindBuiltInNameIdx( rName, *xTokArr, false ); + if( nBuiltInIdx != 0 ) + { + // delete the new NAME records + while( maNameList.GetSize() > nOldListSize ) + maNameList.RemoveRecord( maNameList.GetSize() - 1 ); + // use index of the found built-in NAME record + maNameMap[ rRangeData.GetIndex() ] = nNameIdx = nBuiltInIdx; + } + } + + return nNameIdx; +} + +sal_uInt16 XclExpNameManagerImpl::CreateName( const ScDBData& rDBData ) +{ + // get name and source range, and create the definition formula + const String& rName = rDBData.GetName(); + ScRange aRange; + rDBData.GetArea( aRange ); + XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, aRange ); + + // try to use an existing built-in name + sal_uInt16 nNameIdx = FindBuiltInNameIdx( rName, *xTokArr, true ); + if( nNameIdx == 0 ) + { + // insert a new name into the list + XclExpNameRef xName( new XclExpName( GetRoot(), GetUnusedName( rName ) ) ); + xName->SetTokenArray( xTokArr ); + nNameIdx = Append( xName ); + } + + // store the index of the NAME record in the lookup map + maDBRangeMap[ rDBData.GetIndex() ] = nNameIdx; + return nNameIdx; +} + +void XclExpNameManagerImpl::CreateBuiltInNames() +{ + ScDocument& rDoc = GetDoc(); + XclExpTabInfo& rTabInfo = GetTabInfo(); + + /* #i2394# #100489# built-in defined names must be sorted by the name of the + containing sheet. Example: SheetA!Print_Range must be stored *before* + SheetB!Print_Range, regardless of the position of SheetA in the document! */ + for( SCTAB nScTabIdx = 0, nScTabCount = rTabInfo.GetScTabCount(); nScTabIdx < nScTabCount; ++nScTabIdx ) + { + // find real sheet index from the nScTabIdx counter + SCTAB nScTab = rTabInfo.GetRealScTab( nScTabIdx ); + // create NAME records for all built-in names of this sheet + if( rTabInfo.IsExportTab( nScTab ) ) + { + // *** 1) print ranges *** ---------------------------------------- + + if( rDoc.HasPrintRange() ) + { + ScRangeList aRangeList; + for( USHORT nIdx = 0, nCount = rDoc.GetPrintRangeCount( nScTab ); nIdx < nCount; ++nIdx ) + { + ScRange aRange( *rDoc.GetPrintRange( nScTab, nIdx ) ); + // Calc document does not care about sheet index in print ranges + aRange.aStart.SetTab( nScTab ); + aRange.aEnd.SetTab( nScTab ); + aRangeList.Append( aRange ); + } + GetAddressConverter().ValidateRangeList( aRangeList, true ); + GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTAREA, aRangeList ); + } + + // *** 2) print titles *** ---------------------------------------- + + ScRangeList aTitleList; + // repeated columns + if( const ScRange* pColRange = rDoc.GetRepeatColRange( nScTab ) ) + aTitleList.Append( ScRange( + pColRange->aStart.Col(), 0, nScTab, + pColRange->aEnd.Col(), GetXclMaxPos().Row(), nScTab ) ); + // repeated rows + if( const ScRange* pRowRange = rDoc.GetRepeatRowRange( nScTab ) ) + aTitleList.Append( ScRange( + 0, pRowRange->aStart.Row(), nScTab, + GetXclMaxPos().Col(), pRowRange->aEnd.Row(), nScTab ) ); + // create the NAME record + GetAddressConverter().ValidateRangeList( aTitleList, true ); + GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTTITLES, aTitleList ); + + // *** 3) filter ranges *** --------------------------------------- + + if( GetBiff() == EXC_BIFF8 ) + GetFilterManager().InitTabFilter( nScTab ); + } + } +} + +void XclExpNameManagerImpl::CreateUserNames() +{ + const ScRangeName& rNamedRanges = GetNamedRanges(); + for( USHORT nNameIdx = 0, nNameCount = rNamedRanges.GetCount(); nNameIdx < nNameCount; ++nNameIdx ) + { + const ScRangeData* pRangeData = rNamedRanges[ nNameIdx ]; + DBG_ASSERT( rNamedRanges[ nNameIdx ], "XclExpNameManagerImpl::CreateUserNames - missing defined name" ); + // skip definitions of shared formulas + if( pRangeData && !pRangeData->HasType( RT_SHARED ) && !FindNameIdx( maNameMap, pRangeData->GetIndex() ) ) + CreateName( *pRangeData ); + } +} + +void XclExpNameManagerImpl::CreateDatabaseNames() +{ + const ScDBCollection& rDBRanges = GetDatabaseRanges(); + for( USHORT nDBIdx = 0, nDBCount = rDBRanges.GetCount(); nDBIdx < nDBCount; ++nDBIdx ) + { + const ScDBData* pDBData = rDBRanges[ nDBIdx ]; + DBG_ASSERT( pDBData, "XclExpNameManagerImpl::CreateDatabaseNames - missing database range" ); + // skip hidden "unnamed" range + if( pDBData && (pDBData->GetName() != maUnnamedDBName) && !FindNameIdx( maDBRangeMap, pDBData->GetIndex() ) ) + CreateName( *pDBData ); + } +} + +// ---------------------------------------------------------------------------- + +XclExpNameManager::XclExpNameManager( const XclExpRoot& rRoot ) : + XclExpRoot( rRoot ), + mxImpl( new XclExpNameManagerImpl( rRoot ) ) +{ +} + +XclExpNameManager::~XclExpNameManager() +{ +} + +void XclExpNameManager::Initialize() +{ + mxImpl->Initialize(); +} + +sal_uInt16 XclExpNameManager::InsertName( USHORT nScNameIdx ) +{ + return mxImpl->InsertName( nScNameIdx ); +} + +sal_uInt16 XclExpNameManager::InsertDBRange( USHORT nScDBRangeIdx ) +{ + return mxImpl->InsertDBRange( nScDBRangeIdx ); +} + +sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab ) +{ + return mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, nScTab ); +} + +sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRange& rRange ) +{ + XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRange ); + return mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRange.aStart.Tab() ); +} + +sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRangeList& rRangeList ) +{ + sal_uInt16 nNameIdx = 0; + if( rRangeList.Count() ) + { + XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRangeList ); + nNameIdx = mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRangeList.GetObject( 0 )->aStart.Tab() ); + } + return nNameIdx; +} + +sal_uInt16 XclExpNameManager::InsertUniqueName( + const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab ) +{ + return mxImpl->InsertUniqueName( rName, xTokArr, nScTab ); +} + +sal_uInt16 XclExpNameManager::InsertRawName( const String& rName ) +{ + return mxImpl->InsertRawName( rName ); +} + +sal_uInt16 XclExpNameManager::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden ) +{ + return mxImpl->InsertMacroCall( rMacroName, bVBasic, bFunc, bHidden ); +} + +const String& XclExpNameManager::GetOrigName( sal_uInt16 nNameIdx ) const +{ + const XclExpName* pName = mxImpl->GetName( nNameIdx ); + return pName ? pName->GetOrigName() : EMPTY_STRING; +} + +SCTAB XclExpNameManager::GetScTab( sal_uInt16 nNameIdx ) const +{ + const XclExpName* pName = mxImpl->GetName( nNameIdx ); + return pName ? pName->GetScTab() : SCTAB_GLOBAL; +} + +bool XclExpNameManager::IsVolatile( sal_uInt16 nNameIdx ) const +{ + const XclExpName* pName = mxImpl->GetName( nNameIdx ); + return pName && pName->IsVolatile(); +} + +void XclExpNameManager::Save( XclExpStream& rStrm ) +{ + mxImpl->Save( rStrm ); +} + +void XclExpNameManager::SaveXml( XclExpXmlStream& rStrm ) +{ + mxImpl->SaveXml( rStrm ); +} + +// ============================================================================ + |