xref: /aoo41x/main/sc/source/core/tool/rangenam.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 //------------------------------------------------------------------------
33 
34 #include <tools/debug.hxx>
35 #include <string.h>
36 #include <memory>
37 #include <unotools/collatorwrapper.hxx>
38 #include <unotools/transliterationwrapper.hxx>
39 
40 #include "token.hxx"
41 #include "tokenarray.hxx"
42 #include "rangenam.hxx"
43 #include "global.hxx"
44 #include "compiler.hxx"
45 #include "rangeutl.hxx"
46 #include "rechead.hxx"
47 #include "refupdat.hxx"
48 #include "document.hxx"
49 
50 using namespace formula;
51 
52 //========================================================================
53 // ScRangeData
54 //========================================================================
55 
56 // Interner ctor fuer das Suchen nach einem Index
57 
58 ScRangeData::ScRangeData( sal_uInt16 n )
59            : pCode( NULL ), nIndex( n ), bModified( sal_False ), mnMaxRow(-1), mnMaxCol(-1)
60 {}
61 
62 ScRangeData::ScRangeData( ScDocument* pDok,
63 						  const String& rName,
64 						  const String& rSymbol,
65                           const ScAddress& rAddress,
66 						  RangeType nType,
67 						  const FormulaGrammar::Grammar eGrammar ) :
68 				aName		( rName ),
69                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
70 				pCode		( NULL ),
71 				aPos		( rAddress ),
72 				eType		( nType ),
73 				pDoc		( pDok ),
74 				nIndex		( 0 ),
75                 bModified	( sal_False ),
76                 mnMaxRow    (-1),
77                 mnMaxCol    (-1)
78 {
79 	if (rSymbol.Len() > 0)
80 	{
81 		ScCompiler aComp( pDoc, aPos );
82         aComp.SetGrammar(eGrammar);
83 		pCode = aComp.CompileString( rSymbol );
84 		if( !pCode->GetCodeError() )
85 		{
86 			pCode->Reset();
87 			FormulaToken* p = pCode->GetNextReference();
88 			if( p )// genau eine Referenz als erstes
89 			{
90 				if( p->GetType() == svSingleRef )
91 					eType = eType | RT_ABSPOS;
92 				else
93 					eType = eType | RT_ABSAREA;
94 			}
95 			// ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
96 			// Dies ist fuer die manuelle Eingabe
97 			aComp.CompileTokenArray();
98 			pCode->DelRPN();
99 		}
100 	}
101     else
102     {
103         // #i63513#/#i65690# don't leave pCode as NULL.
104         // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
105         // to ensure same behavior if unnecessary copying is left out.
106 
107         pCode = new ScTokenArray();
108     }
109 }
110 
111 ScRangeData::ScRangeData( ScDocument* pDok,
112 						  const String& rName,
113 						  const ScTokenArray& rArr,
114                           const ScAddress& rAddress,
115 						  RangeType nType ) :
116 				aName		( rName ),
117                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
118 				pCode		( new ScTokenArray( rArr ) ),
119 				aPos		( rAddress ),
120 				eType		( nType ),
121 				pDoc		( pDok ),
122 				nIndex		( 0 ),
123                 bModified	( sal_False ),
124                 mnMaxRow    (-1),
125                 mnMaxCol    (-1)
126 {
127 	if( !pCode->GetCodeError() )
128 	{
129 		pCode->Reset();
130 		FormulaToken* p = pCode->GetNextReference();
131 		if( p )// genau eine Referenz als erstes
132 		{
133 			if( p->GetType() == svSingleRef )
134 				eType = eType | RT_ABSPOS;
135 			else
136 				eType = eType | RT_ABSAREA;
137 		}
138 		// Die Importfilter haben diesen Test nicht,
139 		// da die benannten Bereiche z.T. noch unvollstaendig sind.
140 //		if( !pCode->GetCodeLen() )
141 //		{
142 //			// ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
143 //			ScCompiler aComp( pDok, aPos, *pCode );
144 //			aComp.CompileTokenArray();
145 //			pCode->DelRPN();
146 //		}
147 	}
148 }
149 
150 ScRangeData::ScRangeData( ScDocument* pDok,
151 						  const String& rName,
152 						  const ScAddress& rTarget ) :
153 				aName		( rName ),
154                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
155 				pCode		( new ScTokenArray() ),
156 				aPos		( rTarget ),
157 				eType		( RT_NAME ),
158 				pDoc		( pDok ),
159 				nIndex		( 0 ),
160                 bModified	( sal_False ),
161                 mnMaxRow    (-1),
162                 mnMaxCol    (-1)
163 {
164 	ScSingleRefData aRefData;
165 	aRefData.InitAddress( rTarget );
166 	aRefData.SetFlag3D( sal_True );
167 	pCode->AddSingleReference( aRefData );
168 	ScCompiler aComp( pDoc, aPos, *pCode );
169     aComp.SetGrammar(pDoc->GetGrammar());
170 	aComp.CompileTokenArray();
171 	if ( !pCode->GetCodeError() )
172 		eType |= RT_ABSPOS;
173 }
174 
175 ScRangeData::ScRangeData(const ScRangeData& rScRangeData) :
176     ScDataObject(),
177 	aName 	(rScRangeData.aName),
178     aUpperName  (rScRangeData.aUpperName),
179 	pCode		(rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()),		// echte Kopie erzeugen (nicht copy-ctor)
180 	aPos		(rScRangeData.aPos),
181 	eType		(rScRangeData.eType),
182 	pDoc		(rScRangeData.pDoc),
183 	nIndex   	(rScRangeData.nIndex),
184     bModified	(rScRangeData.bModified),
185     mnMaxRow    (rScRangeData.mnMaxRow),
186     mnMaxCol    (rScRangeData.mnMaxCol)
187 {}
188 
189 ScRangeData::~ScRangeData()
190 {
191 	delete pCode;
192 }
193 
194 ScDataObject* ScRangeData::Clone() const
195 {
196 	return new ScRangeData(*this);
197 }
198 
199 void ScRangeData::GuessPosition()
200 {
201 	//	setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel
202 	//	ohne Fehler verabsolutiert werden koennen
203 
204 	DBG_ASSERT(aPos == ScAddress(), "die Position geht jetzt verloren");
205 
206 	SCsCOL nMinCol = 0;
207 	SCsROW nMinRow = 0;
208 	SCsTAB nMinTab = 0;
209 
210 	ScToken* t;
211 	pCode->Reset();
212     while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
213 	{
214 		ScSingleRefData& rRef1 = t->GetSingleRef();
215 		if ( rRef1.IsColRel() && rRef1.nRelCol < nMinCol )
216 			nMinCol = rRef1.nRelCol;
217 		if ( rRef1.IsRowRel() && rRef1.nRelRow < nMinRow )
218 			nMinRow = rRef1.nRelRow;
219 		if ( rRef1.IsTabRel() && rRef1.nRelTab < nMinTab )
220 			nMinTab = rRef1.nRelTab;
221 
222 		if ( t->GetType() == svDoubleRef )
223 		{
224 			ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
225 			if ( rRef2.IsColRel() && rRef2.nRelCol < nMinCol )
226 				nMinCol = rRef2.nRelCol;
227 			if ( rRef2.IsRowRel() && rRef2.nRelRow < nMinRow )
228 				nMinRow = rRef2.nRelRow;
229 			if ( rRef2.IsTabRel() && rRef2.nRelTab < nMinTab )
230 				nMinTab = rRef2.nRelTab;
231 		}
232 	}
233 
234 	aPos = ScAddress( (SCCOL)(-nMinCol), (SCROW)(-nMinRow), (SCTAB)(-nMinTab) );
235 
236 	//!	Test
237 //	DBG_ERROR(String("Pos ")+String((SCCOL)(-nMinCol))+String("/")+
238 //			String((SCROW)(-nMinRow))+String("/")+String((SCTAB)(-nMinTab)));
239 }
240 
241 void ScRangeData::GetSymbol( String& rSymbol, const FormulaGrammar::Grammar eGrammar ) const
242 {
243 	ScCompiler aComp(pDoc, aPos, *pCode);
244     aComp.SetGrammar(eGrammar);
245 	aComp.CreateStringFromTokenArray( rSymbol );
246 }
247 
248 void ScRangeData::UpdateSymbol(	rtl::OUStringBuffer& rBuffer, const ScAddress& rPos,
249 								const FormulaGrammar::Grammar eGrammar )
250 {
251     ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
252 	ScCompiler aComp( pDoc, rPos, *pTemp.get());
253     aComp.SetGrammar(eGrammar);
254     aComp.MoveRelWrap(GetMaxCol(), GetMaxRow());
255 	aComp.CreateStringFromTokenArray( rBuffer );
256 }
257 
258 void ScRangeData::UpdateReference(	UpdateRefMode eUpdateRefMode,
259 									const ScRange& r,
260 									SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
261 {
262 	sal_Bool bChanged = sal_False;
263 
264 	pCode->Reset();
265 	if( pCode->GetNextReference() )
266 	{
267         sal_Bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED);
268 		ScCompiler aComp( pDoc, aPos, *pCode );
269         aComp.SetGrammar(pDoc->GetGrammar());
270 		const sal_Bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r,
271 													nDx, nDy, nDz,
272 													bChanged, bSharedFormula);
273 		if (bSharedFormula)
274 		{
275 			if (bRelRef)
276 				eType = eType | RT_SHAREDMOD;
277 			else
278 				eType = eType & ~RT_SHAREDMOD;
279 		}
280 	}
281 
282 	bModified = bChanged;
283 }
284 
285 
286 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
287 {
288 	sal_Bool bChanged = sal_False;
289 
290 	ScToken* t;
291 	pCode->Reset();
292 
293 	while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
294 	{
295 		if( t->GetType() != svIndex )
296 		{
297 			SingleDoubleRefModifier aMod( *t );
298 			ScComplexRefData& rRef = aMod.Ref();
299 			if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
300 					(!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
301 				( t->GetType() == svSingleRef ||
302 				(!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
303 					(!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
304 			{
305 				if ( ScRefUpdate::UpdateTranspose( pDoc, rSource, rDest, rRef ) != UR_NOTHING )
306 					bChanged = sal_True;
307 			}
308 		}
309 	}
310 
311 	bModified = bChanged;
312 }
313 
314 void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
315 {
316 	sal_Bool bChanged = sal_False;
317 
318 	ScToken* t;
319 	pCode->Reset();
320 
321 	while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
322 	{
323 		if( t->GetType() != svIndex )
324 		{
325 			SingleDoubleRefModifier aMod( *t );
326 			ScComplexRefData& rRef = aMod.Ref();
327 			if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
328 					(!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
329 				( t->GetType() == svSingleRef ||
330 				(!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
331 					(!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
332 			{
333 				if ( ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, rRef ) != UR_NOTHING )
334 					bChanged = sal_True;
335 			}
336 		}
337 	}
338 
339 	bModified = bChanged;			// muss direkt hinterher ausgewertet werden
340 }
341 
342 sal_Bool ScRangeData::operator== (const ScRangeData& rData) const		// fuer Undo
343 {
344 	if ( nIndex	!= rData.nIndex	||
345 		 aName	!= rData.aName	||
346 		 aPos	!= rData.aPos	||
347 		 eType	!= rData.eType     ) return sal_False;
348 
349 	sal_uInt16 nLen = pCode->GetLen();
350 	if ( nLen != rData.pCode->GetLen() ) return sal_False;
351 
352 	FormulaToken** ppThis = pCode->GetArray();
353 	FormulaToken** ppOther = rData.pCode->GetArray();
354 
355 	for ( sal_uInt16 i=0; i<nLen; i++ )
356 		if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
357 			return sal_False;
358 
359 	return sal_True;
360 }
361 
362 //UNUSED2009-05 sal_Bool ScRangeData::IsRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
363 //UNUSED2009-05 {
364 //UNUSED2009-05     sal_Bool bRet = sal_False;
365 //UNUSED2009-05     ScRange aRange;
366 //UNUSED2009-05     if ( IsReference(aRange) )
367 //UNUSED2009-05     {
368 //UNUSED2009-05         if ( bStartOnly )
369 //UNUSED2009-05             bRet = ( rPos == aRange.aStart );
370 //UNUSED2009-05         else
371 //UNUSED2009-05             bRet = ( aRange.In( rPos ) );
372 //UNUSED2009-05     }
373 //UNUSED2009-05     return bRet;
374 //UNUSED2009-05 }
375 
376 sal_Bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
377 {
378 	sal_Bool bRet = sal_False;
379 	ScRange aRange;
380 	if ( IsReference(aRange) )
381 		bRet = ( rBlock == aRange );
382 	return bRet;
383 }
384 
385 sal_Bool ScRangeData::IsReference( ScRange& rRange ) const
386 {
387 	if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode )
388 		return pCode->IsReference( rRange );
389 
390     return sal_False;
391 }
392 
393 sal_Bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
394 {
395 	if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
396     {
397         ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
398         ScCompiler aComp( pDoc, rPos, *pTemp);
399         aComp.SetGrammar(pDoc->GetGrammar());
400         aComp.MoveRelWrap(MAXCOL, MAXROW);
401         return pTemp->IsReference( rRange );
402     }
403 
404     return sal_False;
405 }
406 
407 sal_Bool ScRangeData::IsValidReference( ScRange& rRange ) const
408 {
409     if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
410         return pCode->IsValidReference( rRange );
411 
412     return sal_False;
413 }
414 
415 void ScRangeData::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
416 {
417 	pCode->Reset();
418 	if( pCode->GetNextReference() )
419 	{
420         ScRangeData* pRangeData = NULL;     // must not be dereferenced
421 		sal_Bool bChanged;
422 		ScCompiler aComp( pDoc, aPos, *pCode);
423         aComp.SetGrammar(pDoc->GetGrammar());
424 		switch (nFlag)
425 		{
426 			case 1:										// einfache InsertTab (doc.cxx)
427 				pRangeData = aComp.UpdateInsertTab(nOldTable, sal_True );	// und CopyTab (doc2.cxx)
428 				break;
429 			case 2:										// einfaches delete (doc.cxx)
430 				pRangeData = aComp.UpdateDeleteTab(nOldTable, sal_False, sal_True, bChanged);
431 				break;
432 			case 3:										// move (doc2.cxx)
433 			{
434 				pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, sal_True );
435 			}
436 				break;
437 			default:
438 			{
439 				DBG_ERROR("ScRangeName::UpdateTabRef: Unknown Flag");
440 			}
441 				break;
442 		}
443 		if (eType&RT_SHARED)
444 		{
445 			if (pRangeData)
446 				eType = eType | RT_SHAREDMOD;
447 			else
448 				eType = eType & ~RT_SHAREDMOD;
449 		}
450 	}
451 }
452 
453 
454 void ScRangeData::MakeValidName( String& rName )		// static
455 {
456     //ScCompiler::InitSymbolsNative();
457 
458     // strip leading invalid characters
459 	xub_StrLen nPos = 0;
460 	xub_StrLen nLen = rName.Len();
461 	while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
462 		++nPos;
463 	if ( nPos>0 )
464 		rName.Erase(0,nPos);
465 
466     // if the first character is an invalid start character, precede with '_'
467 	if ( rName.Len() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) )
468 		rName.Insert('_',0);
469 
470     // replace invalid with '_'
471 	nLen = rName.Len();
472 	for (nPos=0; nPos<nLen; nPos++)
473 	{
474 		if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
475 			rName.SetChar( nPos, '_' );
476 	}
477 
478     // Ensure that the proposed name is not a reference under any convention,
479     // same as in IsNameValid()
480 	ScAddress aAddr;
481 	ScRange aRange;
482     for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
483     {
484         ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
485         // Don't check Parse on VALID, any partial only VALID may result in
486         // #REF! during compile later!
487         while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details))
488         {
489             //! Range Parse is partially valid also with invalid sheet name,
490             //! Address Parse dito, during compile name would generate a #REF!
491             if ( rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND )
492                 rName.Insert('_',0);
493         }
494     }
495 }
496 
497 sal_Bool ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc )
498 {
499     /* XXX If changed, sc/source/filter/ftools/ftools.cxx
500      * ScfTools::ConvertToScDefinedName needs to be changed too. */
501 	xub_StrLen nPos = 0;
502 	xub_StrLen nLen = rName.Len();
503 	if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) )
504 		return sal_False;
505 	while ( nPos < nLen )
506 	{
507 		if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) )
508 			return sal_False;
509 	}
510     ScAddress aAddr;
511 	ScRange aRange;
512     for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
513     {
514         ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
515         // Don't check Parse on VALID, any partial only VALID may result in
516         // #REF! during compile later!
517         if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details))
518 		    return sal_False;
519     }
520 	return sal_True;
521 }
522 
523 void ScRangeData::SetMaxRow(SCROW nRow)
524 {
525     mnMaxRow = nRow;
526 }
527 
528 SCROW ScRangeData::GetMaxRow() const
529 {
530     return mnMaxRow >= 0 ? mnMaxRow : MAXROW;
531 }
532 
533 void ScRangeData::SetMaxCol(SCCOL nCol)
534 {
535     mnMaxCol = nCol;
536 }
537 
538 SCCOL ScRangeData::GetMaxCol() const
539 {
540     return mnMaxCol >= 0 ? mnMaxCol : MAXCOL;
541 }
542 
543 
544 sal_uInt16 ScRangeData::GetErrCode()
545 {
546 	return pCode ? pCode->GetCodeError() : 0;
547 }
548 
549 sal_Bool ScRangeData::HasReferences() const
550 {
551 	pCode->Reset();
552 	return sal_Bool( pCode->GetNextReference() != NULL );
553 }
554 
555 // bei TransferTab von einem in ein anderes Dokument anpassen,
556 // um Referenzen auf die eigene Tabelle mitzubekommen
557 
558 void ScRangeData::TransferTabRef( SCTAB nOldTab, SCTAB nNewTab )
559 {
560 	long nTabDiff = (long)nNewTab - nOldTab;
561 	long nPosDiff = (long)nNewTab - aPos.Tab();
562 	aPos.SetTab( nNewTab );
563 	ScToken* t;
564 	pCode->Reset();
565     while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
566 	{
567 		ScSingleRefData& rRef1 = t->GetSingleRef();
568 		if ( rRef1.IsTabRel() )
569             rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nPosDiff );
570 		else
571             rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nTabDiff );
572 		if ( t->GetType() == svDoubleRef )
573 		{
574 			ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
575 			if ( rRef2.IsTabRel() )
576                 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nPosDiff );
577 			else
578                 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nTabDiff );
579 		}
580 	}
581 }
582 
583 void ScRangeData::ReplaceRangeNamesInUse( const IndexMap& rMap )
584 {
585     bool bCompile = false;
586     for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
587     {
588         if ( p->GetOpCode() == ocName )
589         {
590             const sal_uInt16 nOldIndex = p->GetIndex();
591             IndexMap::const_iterator itr = rMap.find(nOldIndex);
592             const sal_uInt16 nNewIndex = itr == rMap.end() ? nOldIndex : itr->second;
593             if ( nOldIndex != nNewIndex )
594             {
595                 p->SetIndex( nNewIndex );
596                 bCompile = true;
597             }
598         }
599     }
600     if ( bCompile )
601     {
602         ScCompiler aComp( pDoc, aPos, *pCode);
603         aComp.SetGrammar(pDoc->GetGrammar());
604         aComp.CompileTokenArray();
605     }
606 }
607 
608 
609 void ScRangeData::ValidateTabRefs()
610 {
611 	//	try to make sure all relative references and the reference position
612 	//	are within existing tables, so they can be represented as text
613 	//	(if the range of used tables is more than the existing tables,
614 	//	the result may still contain invalid tables, because the relative
615 	//	references aren't changed so formulas stay the same)
616 
617 	//	find range of used tables
618 
619 	SCTAB nMinTab = aPos.Tab();
620 	SCTAB nMaxTab = nMinTab;
621 	ScToken* t;
622 	pCode->Reset();
623     while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
624 	{
625 		ScSingleRefData& rRef1 = t->GetSingleRef();
626 		if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
627 		{
628 			if ( rRef1.nTab < nMinTab )
629 				nMinTab = rRef1.nTab;
630 			if ( rRef1.nTab > nMaxTab )
631 				nMaxTab = rRef1.nTab;
632 		}
633 		if ( t->GetType() == svDoubleRef )
634 		{
635 			ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
636 			if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
637 			{
638 				if ( rRef2.nTab < nMinTab )
639 					nMinTab = rRef2.nTab;
640 				if ( rRef2.nTab > nMaxTab )
641 					nMaxTab = rRef2.nTab;
642 			}
643 		}
644 	}
645 
646 	SCTAB nTabCount = pDoc->GetTableCount();
647 	if ( nMaxTab >= nTabCount && nMinTab > 0 )
648 	{
649 		//	move position and relative tab refs
650 		//	The formulas that use the name are not changed by this
651 
652 		SCTAB nMove = nMinTab;
653 		aPos.SetTab( aPos.Tab() - nMove );
654 
655 		pCode->Reset();
656         while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
657 		{
658 			ScSingleRefData& rRef1 = t->GetSingleRef();
659 			if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
660                 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab - nMove );
661 			if ( t->GetType() == svDoubleRef )
662 			{
663 				ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
664 				if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
665                     rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab - nMove );
666 			}
667 		}
668 	}
669 }
670 
671 
672 extern "C" int
673 #ifdef WNT
674 __cdecl
675 #endif
676 ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
677 {
678 	return (int) ScGlobal::GetCollator()->compareString(
679 			(*(const ScRangeData**)p1)->GetName(),
680 			(*(const ScRangeData**)p2)->GetName() );
681 }
682 
683 
684 //========================================================================
685 // ScRangeName
686 //========================================================================
687 
688 ScRangeName::ScRangeName(const ScRangeName& rScRangeName, ScDocument* pDocument) :
689 				ScSortedCollection ( rScRangeName ),
690 				pDoc ( pDocument ),
691 				nSharedMaxIndex (rScRangeName.nSharedMaxIndex)
692 {
693 	for (sal_uInt16 i = 0; i < nCount; i++)
694 	{
695 		((ScRangeData*)At(i))->SetDocument(pDocument);
696 		((ScRangeData*)At(i))->SetIndex(((ScRangeData*)rScRangeName.At(i))->GetIndex());
697 	}
698 }
699 
700 short ScRangeName::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
701 {
702 	sal_uInt16 i1 = ((ScRangeData*)pKey1)->GetIndex();
703 	sal_uInt16 i2 = ((ScRangeData*)pKey2)->GetIndex();
704 	return (short) i1 - (short) i2;
705 }
706 
707 sal_Bool ScRangeName::SearchNameUpper( const String& rUpperName, sal_uInt16& rIndex ) const
708 {
709     // SearchNameUpper must be called with an upper-case search string
710 
711     sal_uInt16 i = 0;
712     while (i < nCount)
713     {
714         if ( ((*this)[i])->GetUpperName() == rUpperName )
715         {
716             rIndex = i;
717             return sal_True;
718         }
719         i++;
720     }
721     return sal_False;
722 }
723 
724 sal_Bool ScRangeName::SearchName( const String& rName, sal_uInt16& rIndex ) const
725 {
726     if ( nCount > 0 )
727         return SearchNameUpper( ScGlobal::pCharClass->upper( rName ), rIndex );
728     else
729         return sal_False;
730 }
731 
732 void ScRangeName::UpdateReference(	UpdateRefMode eUpdateRefMode,
733 									const ScRange& rRange,
734 									SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
735 {
736 	for (sal_uInt16 i=0; i<nCount; i++)
737 		((ScRangeData*)pItems[i])->UpdateReference(eUpdateRefMode, rRange,
738 												   nDx, nDy, nDz);
739 }
740 
741 void ScRangeName::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
742 {
743 	for (sal_uInt16 i=0; i<nCount; i++)
744 		((ScRangeData*)pItems[i])->UpdateTranspose( rSource, rDest );
745 }
746 
747 void ScRangeName::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
748 {
749 	for (sal_uInt16 i=0; i<nCount; i++)
750 		((ScRangeData*)pItems[i])->UpdateGrow( rArea, nGrowX, nGrowY );
751 }
752 
753 sal_Bool ScRangeName::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const
754 {
755 	return *(ScRangeData*)pKey1 == *(ScRangeData*)pKey2;
756 }
757 
758 sal_Bool ScRangeName::Insert(ScDataObject* pScDataObject)
759 {
760 	if (!((ScRangeData*)pScDataObject)->GetIndex())		// schon gesetzt?
761 	{
762 		((ScRangeData*)pScDataObject)->SetIndex( GetEntryIndex() );
763 	}
764 
765 	return ScSortedCollection::Insert(pScDataObject);
766 }
767 
768 // Suche nach einem freien Index
769 
770 sal_uInt16 ScRangeName::GetEntryIndex()
771 {
772 	sal_uInt16 nLast = 0;
773 	for ( sal_uInt16 i = 0; i < nCount; i++ )
774 	{
775 		sal_uInt16 nIdx = ((ScRangeData*)pItems[i])->GetIndex();
776 		if( nIdx > nLast )
777 		{
778 			nLast = nIdx;
779 		}
780 	}
781 	return nLast + 1;
782 }
783 
784 ScRangeData* ScRangeName::FindIndex( sal_uInt16 nIndex )
785 {
786 	ScRangeData aDataObj( nIndex );
787 	sal_uInt16 n;
788 	if( Search( &aDataObj, n ) )
789 		return (*this)[ n ];
790 	else
791 		return NULL;
792 }
793 
794 //UNUSED2009-05 ScRangeData* ScRangeName::GetRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const
795 //UNUSED2009-05 {
796 //UNUSED2009-05     if ( pItems )
797 //UNUSED2009-05     {
798 //UNUSED2009-05         for ( sal_uInt16 i = 0; i < nCount; i++ )
799 //UNUSED2009-05             if ( ((ScRangeData*)pItems[i])->IsRangeAtCursor( rPos, bStartOnly ) )
800 //UNUSED2009-05                 return (ScRangeData*)pItems[i];
801 //UNUSED2009-05     }
802 //UNUSED2009-05     return NULL;
803 //UNUSED2009-05 }
804 
805 ScRangeData* ScRangeName::GetRangeAtBlock( const ScRange& rBlock ) const
806 {
807 	if ( pItems )
808 	{
809 		for ( sal_uInt16 i = 0; i < nCount; i++ )
810 			if ( ((ScRangeData*)pItems[i])->IsRangeAtBlock( rBlock ) )
811 				return (ScRangeData*)pItems[i];
812 	}
813 	return NULL;
814 }
815 
816 void ScRangeName::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable)
817 {
818 	for (sal_uInt16 i=0; i<nCount; i++)
819 		((ScRangeData*)pItems[i])->UpdateTabRef(nOldTable, nFlag, nNewTable);
820 }
821 
822 
823 
824 
825