xref: /aoo41x/main/sc/source/filter/excel/xename.cxx (revision dffa72de)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 #include "xename.hxx"
27 
28 #include <map>
29 
30 #include "globstr.hrc"
31 #include "document.hxx"
32 #include "rangenam.hxx"
33 #include "dbcolect.hxx"
34 #include "xehelper.hxx"
35 #include "xelink.hxx"
36 
37 // for filter manager
38 #include "excrecds.hxx"
39 
40 #include <formula/grammar.hxx>
41 
42 using namespace ::oox;
43 
44 using ::rtl::OString;
45 
46 // ============================================================================
47 // *** Helper classes ***
48 // ============================================================================
49 
50 /** Represents an internal defined name, supports writing it to a NAME record. */
51 class XclExpName : public XclExpRecord, protected XclExpRoot
52 {
53 public:
54     /** Creates a standard defined name. */
55     explicit            XclExpName( const XclExpRoot& rRoot, const String& rName );
56     /** Creates a built-in defined name. */
57     explicit            XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn );
58 
59     /** Sets a token array containing the definition of this name. */
60     void                SetTokenArray( XclTokenArrayRef xTokArr );
61     /** Changes this defined name to be local on the specified Calc sheet. */
62     void                SetLocalTab( SCTAB nScTab );
63     /** Hides or unhides the defined name. */
64     void                SetHidden( bool bHidden = true );
65     /** Changes this name to be the call to a VB macro function or procedure.
66         @param bVBasic  true = Visual Basic macro, false = Sheet macro.
67         @param bFunc  true = Macro function; false = Macro procedure. */
68     void                SetMacroCall( bool bVBasic, bool bFunc );
69 
70 
71     /** Sets the name's symbol value
72         @param sValue   the name's symbolic value */
73     void                SetSymbol( String sValue );
74     /** Returns the name's symbol value */
GetSymbol() const75     inline const String& GetSymbol() const { return msSymbol; }
76 
77     /** Returns the original name (title) of this defined name. */
GetOrigName() const78     inline const String& GetOrigName() const { return maOrigName; }
79     /** Returns the Excel built-in name index of this defined name.
80         @return  The built-in name index or EXC_BUILTIN_UNKNOWN for user-defined names. */
GetBuiltInName() const81     inline sal_Unicode  GetBuiltInName() const { return mcBuiltIn; }
82 
83     /** Returns the token array for this defined name. */
GetTokenArray() const84     inline XclTokenArrayRef GetTokenArray() const { return mxTokArr; }
85 
86     /** Returns true, if this is a document-global defined name. */
IsGlobal() const87     inline bool         IsGlobal() const { return mnXclTab == EXC_NAME_GLOBAL; }
88     /** Returns the Calc sheet of a local defined name. */
GetScTab() const89     inline SCTAB        GetScTab() const { return mnScTab; }
90 	//
91 	/** Set name range flag value */
SetScTab(sal_uInt16 nXclTab)92 	void				SetScTab( sal_uInt16 nXclTab ) { mnXclTab = nXclTab; }
93 
94     /** Returns true, if this defined name is volatile. */
95     bool                IsVolatile() const;
96     /** Returns true, if this defined name is hidden. */
97     bool                IsHidden() const;
98     /** Returns true, if this defined name describes a macro call.
99         @param bFunc  true = Macro function; false = Macro procedure. */
100     bool                IsMacroCall( bool bVBasic, bool bFunc ) const;
101 
102     /** Writes the entire NAME record to the passed stream. */
103     virtual void        Save( XclExpStream& rStrm );
104 
105     virtual void        SaveXml( XclExpXmlStream& rStrm );
106 
107 private:
108     /** Writes the body of the NAME record to the passed stream. */
109     virtual void        WriteBody( XclExpStream& rStrm );
110 
111 private:
112     String              maOrigName;     /// The original user-defined name.
113     String              msSymbol;       /// The value of the symbol
114     XclExpStringRef     mxName;         /// The name as Excel string object.
115     XclTokenArrayRef    mxTokArr;       /// The definition of the defined name.
116     sal_Unicode         mcBuiltIn;      /// The built-in index for built-in names.
117     SCTAB               mnScTab;        /// The Calc sheet index for local names.
118     sal_uInt16          mnFlags;        /// Additional flags for this defined name.
119     sal_uInt16          mnExtSheet;     /// The 1-based index to a global EXTERNSHEET record.
120     sal_uInt16          mnXclTab;       /// The 1-based Excel sheet index for local names.
121 };
122 
123 // ----------------------------------------------------------------------------
124 
125 class ScRangeData;
126 class ScDBData;
127 
128 /** Implementation class of the name manager. */
129 class XclExpNameManagerImpl : protected XclExpRoot
130 {
131 public:
132     explicit            XclExpNameManagerImpl( const XclExpRoot& rRoot );
133 
134     /** Creates NAME records for built-in and user defined names. */
135     void                Initialize();
136 
137     /** Inserts the Calc name with the passed index and returns the Excel NAME index. */
138     sal_uInt16          InsertName( sal_uInt16 nScNameIdx );
139     /** Inserts the Calc database range with the passed index and returns the Excel NAME index. */
140     sal_uInt16          InsertDBRange( sal_uInt16 nScDBRangeIdx );
141 
142     /** Inserts a new built-in defined name. */
143     sal_uInt16          InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab );
144     /** Inserts a new defined name. Sets another unused name, if rName already exists. */
145     sal_uInt16          InsertUniqueName( const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab );
146     /** Returns index of an existing name, or creates a name without definition. */
147     sal_uInt16          InsertRawName( const String& rName );
148     /** Searches or inserts a defined name describing a macro name.
149         @param bVBasic  true = Visual Basic macro; false = Sheet macro.
150         @param bFunc  true = Macro function; false = Macro procedure. */
151     sal_uInt16          InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden );
152 
153     /** Returns the NAME record at the specified position or 0 on error. */
154     const XclExpName*   GetName( sal_uInt16 nNameIdx ) const;
155 
156     /** Writes the entire list of NAME records.
157         @descr  In BIFF7 and lower, writes the entire global link table, which
158             consists of an EXTERNCOUNT record, several EXTERNSHEET records, and
159             the list of NAME records. */
160     void                Save( XclExpStream& rStrm );
161 
162     void                SaveXml( XclExpXmlStream& rStrm );
163 
164 private:
165     typedef XclExpRecordList< XclExpName >      XclExpNameList;
166     typedef XclExpNameList::RecordRefType       XclExpNameRef;
167     typedef ::std::map< sal_uInt16, sal_uInt16 >    XclExpIndexMap;
168 
169 private:
170     /** Finds the index of a NAME record from the passed Calc index in the specified map. */
171     sal_uInt16          FindNameIdx( const XclExpIndexMap& rMap, sal_uInt16 nScIdx ) const;
172     /** Returns the index of an existing built-in NAME record with the passed definition, otherwise 0. */
173     sal_uInt16          FindBuiltInNameIdx( const String& rName,
174                             const XclTokenArray& rTokArr, bool bDBRange ) const;
175     /** Returns an unused name for the passed name. */
176     String              GetUnusedName( const String& rName ) const;
177 
178     /** Appends a new NAME record to the record list.
179         @return  The 1-based NAME record index used elsewhere in the Excel file. */
180     sal_uInt16          Append( XclExpNameRef xName );
181     /** Creates a new NAME record for the passed user-defined name.
182         @return  The 1-based NAME record index used elsewhere in the Excel file. */
183     sal_uInt16          CreateName( const ScRangeData& rRangeData );
184     /** Creates a new NAME record for the passed database range.
185         @return  The 1-based NAME record index used elsewhere in the Excel file. */
186     sal_uInt16          CreateName( const ScDBData& rDBData );
187 
188     /** Creates NAME records for all built-in names in the document. */
189     void                CreateBuiltInNames();
190     /** Creates NAME records for all user-defined names in the document. */
191     void                CreateUserNames();
192     /** Creates NAME records for all database ranges in the document. */
193     void                CreateDatabaseNames();
194 
195 private:
196     XclExpNameList      maNameList;         /// List of NAME records.
197     XclExpIndexMap      maNameMap;          /// Maps Calc defined names to Excel NAME records.
198     XclExpIndexMap      maDBRangeMap;       /// Maps Calc database ranges to Excel NAME records.
199     String              maUnnamedDBName;    /// Name of the hidden unnamed database range.
200     size_t              mnFirstUserIdx;     /// List index of first user-defined NAME record.
201 };
202 
203 // ============================================================================
204 // *** Implementation ***
205 // ============================================================================
206 
XclExpName(const XclExpRoot & rRoot,const String & rName)207 XclExpName::XclExpName( const XclExpRoot& rRoot, const String& rName ) :
208     XclExpRecord( EXC_ID_NAME ),
209     XclExpRoot( rRoot ),
210     maOrigName( rName ),
211     mxName( XclExpStringHelper::CreateString( rRoot, rName, EXC_STR_8BITLENGTH ) ),
212     mcBuiltIn( EXC_BUILTIN_UNKNOWN ),
213     mnScTab( SCTAB_GLOBAL ),
214     mnFlags( EXC_NAME_DEFAULT ),
215     mnExtSheet( EXC_NAME_GLOBAL ),
216     mnXclTab( EXC_NAME_GLOBAL )
217 {
218 }
219 
XclExpName(const XclExpRoot & rRoot,sal_Unicode cBuiltIn)220 XclExpName::XclExpName( const XclExpRoot& rRoot, sal_Unicode cBuiltIn ) :
221     XclExpRecord( EXC_ID_NAME ),
222     XclExpRoot( rRoot ),
223     mcBuiltIn( cBuiltIn ),
224     mnScTab( SCTAB_GLOBAL ),
225     mnFlags( EXC_NAME_DEFAULT ),
226     mnExtSheet( EXC_NAME_GLOBAL ),
227     mnXclTab( EXC_NAME_GLOBAL )
228 {
229     // filter source range is hidden in Excel
230     if( cBuiltIn == EXC_BUILTIN_FILTERDATABASE )
231         SetHidden();
232 
233     // special case for BIFF5/7 filter source range - name appears as plain text without built-in flag
234     if( (GetBiff() <= EXC_BIFF5) && (cBuiltIn == EXC_BUILTIN_FILTERDATABASE) )
235     {
236         String aName( XclTools::GetXclBuiltInDefName( EXC_BUILTIN_FILTERDATABASE ) );
237         mxName = XclExpStringHelper::CreateString( rRoot, aName, EXC_STR_8BITLENGTH );
238     }
239     else
240     {
241         mxName = XclExpStringHelper::CreateString( rRoot, cBuiltIn, EXC_STR_8BITLENGTH );
242         ::set_flag( mnFlags, EXC_NAME_BUILTIN );
243     }
244 }
245 
SetTokenArray(XclTokenArrayRef xTokArr)246 void XclExpName::SetTokenArray( XclTokenArrayRef xTokArr )
247 {
248     mxTokArr = xTokArr;
249 }
250 
SetLocalTab(SCTAB nScTab)251 void XclExpName::SetLocalTab( SCTAB nScTab )
252 {
253     DBG_ASSERT( GetTabInfo().IsExportTab( nScTab ), "XclExpName::SetLocalTab - invalid sheet index" );
254     if( GetTabInfo().IsExportTab( nScTab ) )
255     {
256         mnScTab = nScTab;
257         GetGlobalLinkManager().FindExtSheet( mnExtSheet, mnXclTab, nScTab );
258 
259         // special handling for NAME record
260         switch( GetBiff() )
261         {
262             case EXC_BIFF5: // EXTERNSHEET index is positive in NAME record
263                 mnExtSheet = ~mnExtSheet + 1;
264             break;
265             case EXC_BIFF8: // EXTERNSHEET index not used, but must be created in link table
266                 mnExtSheet = 0;
267             break;
268             default:    DBG_ERROR_BIFF();
269         }
270 
271         // Excel sheet index is 1-based
272         ++mnXclTab;
273     }
274 }
275 
SetHidden(bool bHidden)276 void XclExpName::SetHidden( bool bHidden )
277 {
278     ::set_flag( mnFlags, EXC_NAME_HIDDEN, bHidden );
279 }
280 
SetMacroCall(bool bVBasic,bool bFunc)281 void XclExpName::SetMacroCall( bool bVBasic, bool bFunc )
282 {
283     ::set_flag( mnFlags, EXC_NAME_PROC );
284     ::set_flag( mnFlags, EXC_NAME_VB, bVBasic );
285     ::set_flag( mnFlags, EXC_NAME_FUNC, bFunc );
286 }
287 
SetSymbol(String sSymbol)288 void XclExpName::SetSymbol( String sSymbol )
289 {
290     msSymbol = sSymbol;
291 }
292 
IsVolatile() const293 bool XclExpName::IsVolatile() const
294 {
295     return mxTokArr.is() && mxTokArr->IsVolatile();
296 }
297 
IsHidden() const298 bool XclExpName::IsHidden() const
299 {
300     return ::get_flag( mnFlags, EXC_NAME_HIDDEN );
301 }
302 
IsMacroCall(bool bVBasic,bool bFunc) const303 bool XclExpName::IsMacroCall( bool bVBasic, bool bFunc ) const
304 {
305     return
306         (::get_flag( mnFlags, EXC_NAME_VB ) == bVBasic) &&
307         (::get_flag( mnFlags, EXC_NAME_FUNC ) == bFunc);
308 }
309 
Save(XclExpStream & rStrm)310 void XclExpName::Save( XclExpStream& rStrm )
311 {
312     DBG_ASSERT( mxName.is() && (mxName->Len() > 0), "XclExpName::Save - missing name" );
313     DBG_ASSERT( !(IsGlobal() && ::get_flag( mnFlags, EXC_NAME_BUILTIN )), "XclExpName::Save - global built-in name" );
314     SetRecSize( 11 + mxName->GetSize() + (mxTokArr.is() ? mxTokArr->GetSize() : 2) );
315     XclExpRecord::Save( rStrm );
316 }
317 
SaveXml(XclExpXmlStream & rStrm)318 void XclExpName::SaveXml( XclExpXmlStream& rStrm )
319 {
320     // For some reason, AutoFilter creates exportable names where maOrigName==""
321     if( maOrigName.Len() == 0 )
322         return;
323 
324     sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
325     rWorkbook->startElement( XML_definedName,
326             // OOXTODO: XML_comment, "",
327             // OOXTODO: XML_customMenu, "",
328             // OOXTODO: XML_description, "",
329             XML_function, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ),
330             // OOXTODO: XML_functionGroupId, "",
331             // OOXTODO: XML_help, "",
332             XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_HIDDEN ) ),
333             XML_localSheetId, mnScTab == SCTAB_GLOBAL ? NULL : OString::valueOf( (sal_Int32)mnScTab ).getStr(),
334             XML_name, XclXmlUtils::ToOString( maOrigName ).getStr(),
335             // OOXTODO: XML_publishToServer, "",
336             // OOXTODO: XML_shortcutKey, "",
337             // OOXTODO: XML_statusBar, "",
338             XML_vbProcedure, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_NAME_VB ) ),
339             // OOXTODO: XML_workbookParameter, "",
340             // OOXTODO: XML_xlm, "",
341             FSEND );
342     rWorkbook->writeEscaped( XclXmlUtils::ToOUString( msSymbol ) );
343     rWorkbook->endElement( XML_definedName );
344 }
345 
WriteBody(XclExpStream & rStrm)346 void XclExpName::WriteBody( XclExpStream& rStrm )
347 {
348     sal_uInt16 nFmlaSize = mxTokArr.is() ? mxTokArr->GetSize() : 0;
349 
350     rStrm   << mnFlags                  // flags
351             << sal_uInt8( 0 );          // keyboard shortcut
352     mxName->WriteLenField( rStrm );     // length of name
353     rStrm   << nFmlaSize                // size of token array
354             << mnExtSheet               // BIFF5/7: EXTSHEET index, BIFF8: not used
355             << mnXclTab                 // 1-based sheet index for local names
356             << sal_uInt32( 0 );         // length of menu/descr/help/status text
357     mxName->WriteFlagField( rStrm );    // BIFF8 flag field (no-op in <=BIFF7)
358     mxName->WriteBuffer( rStrm );       // character array of the name
359     if( mxTokArr.is() )
360         mxTokArr->WriteArray( rStrm );  // token array without size
361 }
362 
363 // ----------------------------------------------------------------------------
364 
XclExpNameManagerImpl(const XclExpRoot & rRoot)365 XclExpNameManagerImpl::XclExpNameManagerImpl( const XclExpRoot& rRoot ) :
366     XclExpRoot( rRoot ),
367     maUnnamedDBName( ScGlobal::GetRscString( STR_DB_NONAME ) ),
368     mnFirstUserIdx( 0 )
369 {
370 }
371 
Initialize()372 void XclExpNameManagerImpl::Initialize()
373 {
374     CreateBuiltInNames();
375     mnFirstUserIdx = maNameList.GetSize();
376     CreateUserNames();
377     CreateDatabaseNames();
378 }
379 
InsertName(sal_uInt16 nScNameIdx)380 sal_uInt16 XclExpNameManagerImpl::InsertName( sal_uInt16 nScNameIdx )
381 {
382     sal_uInt16 nNameIdx = FindNameIdx( maNameMap, nScNameIdx );
383     if( nNameIdx == 0 )
384         if( const ScRangeData* pRangeData = GetNamedRanges().FindIndex( nScNameIdx ) )
385             nNameIdx = CreateName( *pRangeData );
386     return nNameIdx;
387 }
388 
InsertDBRange(sal_uInt16 nScDBRangeIdx)389 sal_uInt16 XclExpNameManagerImpl::InsertDBRange( sal_uInt16 nScDBRangeIdx )
390 {
391     sal_uInt16 nNameIdx = FindNameIdx( maDBRangeMap, nScDBRangeIdx );
392     if( nNameIdx == 0 )
393         if( const ScDBData* pDBData = GetDatabaseRanges().FindIndex( nScDBRangeIdx ) )
394             nNameIdx = CreateName( *pDBData );
395     return nNameIdx;
396 }
397 
InsertBuiltInName(sal_Unicode cBuiltIn,XclTokenArrayRef xTokArr,SCTAB nScTab)398 sal_uInt16 XclExpNameManagerImpl::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab )
399 {
400     XclExpNameRef xName( new XclExpName( GetRoot(), cBuiltIn ) );
401     xName->SetTokenArray( xTokArr );
402     xName->SetLocalTab( nScTab );
403     return Append( xName );
404 }
405 
InsertUniqueName(const String & rName,XclTokenArrayRef xTokArr,SCTAB nScTab)406 sal_uInt16 XclExpNameManagerImpl::InsertUniqueName(
407         const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab )
408 {
409     DBG_ASSERT( rName.Len(), "XclExpNameManagerImpl::InsertUniqueName - empty name" );
410     XclExpNameRef xName( new XclExpName( GetRoot(), GetUnusedName( rName ) ) );
411     xName->SetTokenArray( xTokArr );
412     xName->SetLocalTab( nScTab );
413     return Append( xName );
414 }
415 
InsertRawName(const String & rName)416 sal_uInt16 XclExpNameManagerImpl::InsertRawName( const String& rName )
417 {
418     // empty name? may occur in broken external Calc tokens
419     if( !rName.Len() )
420         return 0;
421 
422     // try to find an existing NAME record, regardless of its type
423     for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx )
424     {
425         XclExpNameRef xName = maNameList.GetRecord( nListIdx );
426         if( xName->IsGlobal() && (xName->GetOrigName() == rName) )
427             return static_cast< sal_uInt16 >( nListIdx + 1 );
428     }
429 
430     // create a new NAME record
431     XclExpNameRef xName( new XclExpName( GetRoot(), rName ) );
432     return Append( xName );
433 }
434 
InsertMacroCall(const String & rMacroName,bool bVBasic,bool bFunc,bool bHidden)435 sal_uInt16 XclExpNameManagerImpl::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden )
436 {
437     // empty name? may occur in broken external Calc tokens
438     if( !rMacroName.Len() )
439         return 0;
440 
441     // try to find an existing NAME record
442     for( size_t nListIdx = mnFirstUserIdx, nListSize = maNameList.GetSize(); nListIdx < nListSize; ++nListIdx )
443     {
444         XclExpNameRef xName = maNameList.GetRecord( nListIdx );
445         if( xName->IsMacroCall( bVBasic, bFunc ) && (xName->GetOrigName() == rMacroName) )
446             return static_cast< sal_uInt16 >( nListIdx + 1 );
447     }
448 
449     // create a new NAME record
450     XclExpNameRef xName( new XclExpName( GetRoot(), rMacroName ) );
451     xName->SetMacroCall( bVBasic, bFunc );
452     xName->SetHidden( bHidden );
453 
454     // for sheet macros, add a #NAME! error
455     if( !bVBasic )
456         xName->SetTokenArray( GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NAME ) );
457 
458     return Append( xName );
459 }
460 
GetName(sal_uInt16 nNameIdx) const461 const XclExpName* XclExpNameManagerImpl::GetName( sal_uInt16 nNameIdx ) const
462 {
463     DBG_ASSERT( maNameList.HasRecord( nNameIdx - 1 ), "XclExpNameManagerImpl::GetName - wrong record index" );
464     return maNameList.GetRecord( nNameIdx - 1 ).get();
465 }
466 
Save(XclExpStream & rStrm)467 void XclExpNameManagerImpl::Save( XclExpStream& rStrm )
468 {
469     maNameList.Save( rStrm );
470 }
471 
SaveXml(XclExpXmlStream & rStrm)472 void XclExpNameManagerImpl::SaveXml( XclExpXmlStream& rStrm )
473 {
474     if( maNameList.IsEmpty() )
475         return;
476     sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
477     rWorkbook->startElement( XML_definedNames, FSEND );
478     maNameList.SaveXml( rStrm );
479     rWorkbook->endElement( XML_definedNames );
480 }
481 
482 // private --------------------------------------------------------------------
483 
FindNameIdx(const XclExpIndexMap & rMap,sal_uInt16 nScIdx) const484 sal_uInt16 XclExpNameManagerImpl::FindNameIdx( const XclExpIndexMap& rMap, sal_uInt16 nScIdx ) const
485 {
486     XclExpIndexMap::const_iterator aIt = rMap.find( nScIdx );
487     return (aIt == rMap.end()) ? 0 : aIt->second;
488 }
489 
FindBuiltInNameIdx(const String & rName,const XclTokenArray & rTokArr,bool bDBRange) const490 sal_uInt16 XclExpNameManagerImpl::FindBuiltInNameIdx(
491         const String& rName, const XclTokenArray& rTokArr, bool bDBRange ) const
492 {
493     /*  Get built-in index from the name. Special case: the database range
494         'unnamed' will be mapped to Excel's built-in '_FilterDatabase' name. */
495     sal_Unicode cBuiltIn = (bDBRange && (rName == maUnnamedDBName)) ?
496         EXC_BUILTIN_FILTERDATABASE : XclTools::GetBuiltInDefNameIndex( rName );
497 
498     if( cBuiltIn < EXC_BUILTIN_UNKNOWN )
499     {
500         // try to find the record in existing built-in NAME record list
501         for( size_t nPos = 0; nPos < mnFirstUserIdx; ++nPos )
502         {
503             XclExpNameRef xName = maNameList.GetRecord( nPos );
504             if( xName->GetBuiltInName() == cBuiltIn )
505             {
506                 XclTokenArrayRef xTokArr = xName->GetTokenArray();
507                 if( xTokArr.is() && (*xTokArr == rTokArr) )
508                     return static_cast< sal_uInt16 >( nPos + 1 );
509             }
510         }
511     }
512     return 0;
513 }
514 
GetUnusedName(const String & rName) const515 String XclExpNameManagerImpl::GetUnusedName( const String& rName ) const
516 {
517     String aNewName( rName );
518     sal_Int32 nAppIdx = 0;
519     bool bExist = true;
520     while( bExist )
521     {
522         // search the list of user-defined names
523         bExist = false;
524         for( size_t nPos = mnFirstUserIdx, nSize = maNameList.GetSize(); !bExist && (nPos < nSize); ++nPos )
525         {
526             XclExpNameRef xName = maNameList.GetRecord( nPos );
527             bExist = xName->GetOrigName() == aNewName;
528             // name exists -> create a new name "<originalname>_<counter>"
529             if( bExist )
530                 aNewName.Assign( rName ).Append( '_' ).Append( String::CreateFromInt32( ++nAppIdx ) );
531         }
532     }
533     return aNewName;
534 }
535 
Append(XclExpNameRef xName)536 sal_uInt16 XclExpNameManagerImpl::Append( XclExpNameRef xName )
537 {
538     if( maNameList.GetSize() == 0xFFFF )
539         return 0;
540     maNameList.AppendRecord( xName );
541     return static_cast< sal_uInt16 >( maNameList.GetSize() );  // 1-based
542 }
543 
CreateName(const ScRangeData & rRangeData)544 sal_uInt16 XclExpNameManagerImpl::CreateName( const ScRangeData& rRangeData )
545 {
546     const String& rName = rRangeData.GetName();
547 
548     /*  #i38821# recursive names: first insert the (empty) name object,
549         otherwise a recursive call of this function from the formula compiler
550         with the same defined name will not find it and will create it again. */
551     size_t nOldListSize = maNameList.GetSize();
552     XclExpNameRef xName( new XclExpName( GetRoot(), rName ) );
553     sal_uInt16 nNameIdx = Append( xName );
554 	//
555     xName->SetScTab( rRangeData.GetRangeScope() == MAXTABCOUNT ? EXC_NAME_GLOBAL : rRangeData.GetRangeScope()+1 );
556     // store the index of the NAME record in the lookup map
557     maNameMap[ rRangeData.GetIndex() ] = nNameIdx;
558 
559     /*  Create the definition formula.
560         This may cause recursive creation of other defined names. */
561     if( const ScTokenArray* pScTokArr = const_cast< ScRangeData& >( rRangeData ).GetCode() )
562     {
563         XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, *pScTokArr );
564         xName->SetTokenArray( xTokArr );
565 
566         String sSymbol;
567         rRangeData.GetSymbol( sSymbol, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 );
568         xName->SetSymbol( sSymbol );
569 
570         /*  Try to replace by existing built-in name - complete token array is
571             needed for comparison, and due to the recursion problem above this
572             cannot be done earlier. If a built-in name is found, the created NAME
573             record for this name and all following records in the list must be
574             deleted, otherwise they may contain wrong name list indexes. */
575         sal_uInt16 nBuiltInIdx = FindBuiltInNameIdx( rName, *xTokArr, false );
576         if( nBuiltInIdx != 0 )
577         {
578             // delete the new NAME records
579             while( maNameList.GetSize() > nOldListSize )
580                 maNameList.RemoveRecord( maNameList.GetSize() - 1 );
581             // use index of the found built-in NAME record
582             maNameMap[ rRangeData.GetIndex() ] = nNameIdx = nBuiltInIdx;
583         }
584     }
585 
586     return nNameIdx;
587 }
588 
CreateName(const ScDBData & rDBData)589 sal_uInt16 XclExpNameManagerImpl::CreateName( const ScDBData& rDBData )
590 {
591     // get name and source range, and create the definition formula
592     const String& rName = rDBData.GetName();
593     ScRange aRange;
594     rDBData.GetArea( aRange );
595     XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, aRange );
596 
597     // try to use an existing built-in name
598     sal_uInt16 nNameIdx = FindBuiltInNameIdx( rName, *xTokArr, true );
599     if( nNameIdx == 0 )
600     {
601         // insert a new name into the list
602         XclExpNameRef xName( new XclExpName( GetRoot(), GetUnusedName( rName ) ) );
603         xName->SetTokenArray( xTokArr );
604         nNameIdx = Append( xName );
605     }
606 
607     // store the index of the NAME record in the lookup map
608     maDBRangeMap[ rDBData.GetIndex() ] = nNameIdx;
609     return nNameIdx;
610 }
611 
CreateBuiltInNames()612 void XclExpNameManagerImpl::CreateBuiltInNames()
613 {
614     ScDocument& rDoc = GetDoc();
615     XclExpTabInfo& rTabInfo = GetTabInfo();
616 
617     /*  #i2394# #100489# built-in defined names must be sorted by the name of the
618         containing sheet. Example: SheetA!Print_Range must be stored *before*
619         SheetB!Print_Range, regardless of the position of SheetA in the document! */
620     for( SCTAB nScTabIdx = 0, nScTabCount = rTabInfo.GetScTabCount(); nScTabIdx < nScTabCount; ++nScTabIdx )
621     {
622         // find real sheet index from the nScTabIdx counter
623         SCTAB nScTab = rTabInfo.GetRealScTab( nScTabIdx );
624         // create NAME records for all built-in names of this sheet
625         if( rTabInfo.IsExportTab( nScTab ) )
626         {
627             // *** 1) print ranges *** ----------------------------------------
628 
629             if( rDoc.HasPrintRange() )
630             {
631                 ScRangeList aRangeList;
632                 for( sal_uInt16 nIdx = 0, nCount = rDoc.GetPrintRangeCount( nScTab ); nIdx < nCount; ++nIdx )
633                 {
634                     ScRange aRange( *rDoc.GetPrintRange( nScTab, nIdx ) );
635                     // Calc document does not care about sheet index in print ranges
636                     aRange.aStart.SetTab( nScTab );
637                     aRange.aEnd.SetTab( nScTab );
638                     aRange.Justify();
639                     aRangeList.Append( aRange );
640                 }
641                 // create the NAME record (do not warn if ranges are shrunken)
642                 GetAddressConverter().ValidateRangeList( aRangeList, false );
643                 if( aRangeList.Count() > 0 )
644                     GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTAREA, aRangeList );
645             }
646 
647             // *** 2) print titles *** ----------------------------------------
648 
649             ScRangeList aTitleList;
650             // repeated columns
651             if( const ScRange* pColRange = rDoc.GetRepeatColRange( nScTab ) )
652                 aTitleList.Append( ScRange(
653                     pColRange->aStart.Col(), 0, nScTab,
654                     pColRange->aEnd.Col(), GetXclMaxPos().Row(), nScTab ) );
655             // repeated rows
656             if( const ScRange* pRowRange = rDoc.GetRepeatRowRange( nScTab ) )
657                 aTitleList.Append( ScRange(
658                     0, pRowRange->aStart.Row(), nScTab,
659                     GetXclMaxPos().Col(), pRowRange->aEnd.Row(), nScTab ) );
660             // create the NAME record
661             GetAddressConverter().ValidateRangeList( aTitleList, false );
662             if( aTitleList.Count() > 0 )
663                 GetNameManager().InsertBuiltInName( EXC_BUILTIN_PRINTTITLES, aTitleList );
664 
665             // *** 3) filter ranges *** ---------------------------------------
666 
667             if( GetBiff() == EXC_BIFF8 )
668                 GetFilterManager().InitTabFilter( nScTab );
669         }
670     }
671 }
672 
CreateUserNames()673 void XclExpNameManagerImpl::CreateUserNames()
674 {
675     const ScRangeName& rNamedRanges = GetNamedRanges();
676     for( sal_uInt16 nNameIdx = 0, nNameCount = rNamedRanges.GetCount(); nNameIdx < nNameCount; ++nNameIdx )
677     {
678         const ScRangeData* pRangeData = rNamedRanges[ nNameIdx ];
679         DBG_ASSERT( rNamedRanges[ nNameIdx ], "XclExpNameManagerImpl::CreateUserNames - missing defined name" );
680         // skip definitions of shared formulas
681         if( pRangeData && !pRangeData->HasType( RT_SHARED ) && !FindNameIdx( maNameMap, pRangeData->GetIndex() ) )
682             CreateName( *pRangeData );
683     }
684 }
685 
CreateDatabaseNames()686 void XclExpNameManagerImpl::CreateDatabaseNames()
687 {
688     const ScDBCollection& rDBRanges = GetDatabaseRanges();
689     for( sal_uInt16 nDBIdx = 0, nDBCount = rDBRanges.GetCount(); nDBIdx < nDBCount; ++nDBIdx )
690     {
691         const ScDBData* pDBData = rDBRanges[ nDBIdx ];
692         DBG_ASSERT( pDBData, "XclExpNameManagerImpl::CreateDatabaseNames - missing database range" );
693         // skip hidden "unnamed" range
694         if( pDBData && (pDBData->GetName() != maUnnamedDBName) && !FindNameIdx( maDBRangeMap, pDBData->GetIndex() ) )
695             CreateName( *pDBData );
696     }
697 }
698 
699 // ----------------------------------------------------------------------------
700 
XclExpNameManager(const XclExpRoot & rRoot)701 XclExpNameManager::XclExpNameManager( const XclExpRoot& rRoot ) :
702     XclExpRoot( rRoot ),
703     mxImpl( new XclExpNameManagerImpl( rRoot ) )
704 {
705 }
706 
~XclExpNameManager()707 XclExpNameManager::~XclExpNameManager()
708 {
709 }
710 
Initialize()711 void XclExpNameManager::Initialize()
712 {
713     mxImpl->Initialize();
714 }
715 
InsertName(sal_uInt16 nScNameIdx)716 sal_uInt16 XclExpNameManager::InsertName( sal_uInt16 nScNameIdx )
717 {
718     return mxImpl->InsertName( nScNameIdx );
719 }
720 
InsertDBRange(sal_uInt16 nScDBRangeIdx)721 sal_uInt16 XclExpNameManager::InsertDBRange( sal_uInt16 nScDBRangeIdx )
722 {
723     return mxImpl->InsertDBRange( nScDBRangeIdx );
724 }
725 
726 //UNUSED2009-05 sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, XclTokenArrayRef xTokArr, SCTAB nScTab )
727 //UNUSED2009-05 {
728 //UNUSED2009-05     return mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, nScTab );
729 //UNUSED2009-05 }
730 
InsertBuiltInName(sal_Unicode cBuiltIn,const ScRange & rRange)731 sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRange& rRange )
732 {
733     XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRange );
734     return mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRange.aStart.Tab() );
735 }
736 
InsertBuiltInName(sal_Unicode cBuiltIn,const ScRangeList & rRangeList)737 sal_uInt16 XclExpNameManager::InsertBuiltInName( sal_Unicode cBuiltIn, const ScRangeList& rRangeList )
738 {
739     sal_uInt16 nNameIdx = 0;
740     if( rRangeList.Count() )
741     {
742         XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_NAME, rRangeList );
743         nNameIdx = mxImpl->InsertBuiltInName( cBuiltIn, xTokArr, rRangeList.GetObject( 0 )->aStart.Tab() );
744     }
745     return nNameIdx;
746 }
747 
InsertUniqueName(const String & rName,XclTokenArrayRef xTokArr,SCTAB nScTab)748 sal_uInt16 XclExpNameManager::InsertUniqueName(
749         const String& rName, XclTokenArrayRef xTokArr, SCTAB nScTab )
750 {
751     return mxImpl->InsertUniqueName( rName, xTokArr, nScTab );
752 }
753 
InsertRawName(const String & rName)754 sal_uInt16 XclExpNameManager::InsertRawName( const String& rName )
755 {
756     return mxImpl->InsertRawName( rName );
757 }
758 
InsertMacroCall(const String & rMacroName,bool bVBasic,bool bFunc,bool bHidden)759 sal_uInt16 XclExpNameManager::InsertMacroCall( const String& rMacroName, bool bVBasic, bool bFunc, bool bHidden )
760 {
761     return mxImpl->InsertMacroCall( rMacroName, bVBasic, bFunc, bHidden );
762 }
763 
GetOrigName(sal_uInt16 nNameIdx) const764 const String& XclExpNameManager::GetOrigName( sal_uInt16 nNameIdx ) const
765 {
766     const XclExpName* pName = mxImpl->GetName( nNameIdx );
767     return pName ? pName->GetOrigName() : EMPTY_STRING;
768 }
769 
GetScTab(sal_uInt16 nNameIdx) const770 SCTAB XclExpNameManager::GetScTab( sal_uInt16 nNameIdx ) const
771 {
772     const XclExpName* pName = mxImpl->GetName( nNameIdx );
773     return pName ? pName->GetScTab() : SCTAB_GLOBAL;
774 }
775 
IsVolatile(sal_uInt16 nNameIdx) const776 bool XclExpNameManager::IsVolatile( sal_uInt16 nNameIdx ) const
777 {
778     const XclExpName* pName = mxImpl->GetName( nNameIdx );
779     return pName && pName->IsVolatile();
780 }
781 
Save(XclExpStream & rStrm)782 void XclExpNameManager::Save( XclExpStream& rStrm )
783 {
784     mxImpl->Save( rStrm );
785 }
786 
SaveXml(XclExpXmlStream & rStrm)787 void XclExpNameManager::SaveXml( XclExpXmlStream& rStrm )
788 {
789     mxImpl->SaveXml( rStrm );
790 }
791 
792 // ============================================================================
793 
794