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