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