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