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