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