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 <string.h>
21 #include <memory>
22 #include <unotools/collatorwrapper.hxx>
23 #include <unotools/transliterationwrapper.hxx>
24 #include <unotools/charclass.hxx>
25 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
26 #include <osl/diagnose.h>
27 
28 #include <token.hxx>
29 #include <tokenarray.hxx>
30 #include <rangenam.hxx>
31 #include <global.hxx>
32 #include <compiler.hxx>
33 #include <rangeutl.hxx>
34 #include <rechead.hxx>
35 #include <refupdat.hxx>
36 #include <document.hxx>
37 #include <refupdatecontext.hxx>
38 #include <tokenstringcontext.hxx>
39 
40 #include <formula/errorcodes.hxx>
41 
42 using namespace formula;
43 using ::std::pair;
44 
45 // ScRangeData
46 
ScRangeData(ScDocument * pDok,const OUString & rName,const OUString & rSymbol,const ScAddress & rAddress,Type nType,const FormulaGrammar::Grammar eGrammar)47 ScRangeData::ScRangeData( ScDocument* pDok,
48                           const OUString& rName,
49                           const OUString& rSymbol,
50                           const ScAddress& rAddress,
51                           Type nType,
52                           const FormulaGrammar::Grammar eGrammar ) :
53                 aName       ( rName ),
54                 aUpperName  ( ScGlobal::pCharClass->uppercase( rName ) ),
55                 aPos        ( rAddress ),
56                 eType       ( nType ),
57                 pDoc        ( pDok ),
58                 eTempGrammar( eGrammar ),
59                 nIndex      ( 0 ),
60                 bModified   ( false )
61 {
62     if (!rSymbol.isEmpty())
63     {
64         // Let the compiler set an error on unknown names for a subsequent
65         // CompileUnresolvedXML().
66         const bool bImporting = pDoc->IsImportingXML();
67         CompileRangeData( rSymbol, bImporting);
68         if (bImporting)
69             pDoc->CheckLinkFormulaNeedingCheck( *pCode);
70     }
71     else
72     {
73         // #i63513#/#i65690# don't leave pCode as NULL.
74         // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
75         // to ensure same behavior if unnecessary copying is left out.
76 
77         pCode.reset( new ScTokenArray );
78         pCode->SetFromRangeName(true);
79     }
80 }
81 
ScRangeData(ScDocument * pDok,const OUString & rName,const ScTokenArray & rArr,const ScAddress & rAddress,Type nType)82 ScRangeData::ScRangeData( ScDocument* pDok,
83                           const OUString& rName,
84                           const ScTokenArray& rArr,
85                           const ScAddress& rAddress,
86                           Type nType ) :
87                 aName       ( rName ),
88                 aUpperName  ( ScGlobal::pCharClass->uppercase( rName ) ),
89                 pCode       ( new ScTokenArray( rArr ) ),
90                 aPos        ( rAddress ),
91                 eType       ( nType ),
92                 pDoc        ( pDok ),
93                 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
94                 nIndex      ( 0 ),
95                 bModified   ( false )
96 {
97     pCode->SetFromRangeName(true);
98     InitCode();
99 }
100 
ScRangeData(ScDocument * pDok,const OUString & rName,const ScAddress & rTarget)101 ScRangeData::ScRangeData( ScDocument* pDok,
102                           const OUString& rName,
103                           const ScAddress& rTarget ) :
104                 aName       ( rName ),
105                 aUpperName  ( ScGlobal::pCharClass->uppercase( rName ) ),
106                 pCode       ( new ScTokenArray() ),
107                 aPos        ( rTarget ),
108                 eType       ( Type::Name ),
109                 pDoc        ( pDok ),
110                 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
111                 nIndex      ( 0 ),
112                 bModified   ( false )
113 {
114     ScSingleRefData aRefData;
115     aRefData.InitAddress( rTarget );
116     aRefData.SetFlag3D( true );
117     pCode->AddSingleReference( aRefData );
118     pCode->SetFromRangeName(true);
119     ScCompiler aComp( pDoc, aPos, *pCode, pDoc->GetGrammar() );
120     aComp.CompileTokenArray();
121     if ( pCode->GetCodeError() == FormulaError::NONE )
122         eType |= Type::AbsPos;
123 }
124 
ScRangeData(const ScRangeData & rScRangeData,ScDocument * pDocument,const ScAddress * pPos)125 ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* pDocument, const ScAddress* pPos) :
126     aName   (rScRangeData.aName),
127     aUpperName  (rScRangeData.aUpperName),
128     pCode       (rScRangeData.pCode ? rScRangeData.pCode->Clone().release() : new ScTokenArray()),   // make real copy (not copy-ctor)
129     aPos        (pPos ? *pPos : rScRangeData.aPos),
130     eType       (rScRangeData.eType),
131     pDoc        (pDocument ? pDocument : rScRangeData.pDoc),
132     eTempGrammar(rScRangeData.eTempGrammar),
133     nIndex      (rScRangeData.nIndex),
134     bModified   (rScRangeData.bModified)
135 {
136     pCode->SetFromRangeName(true);
137 }
138 
~ScRangeData()139 ScRangeData::~ScRangeData()
140 {
141 }
142 
CompileRangeData(const OUString & rSymbol,bool bSetError)143 void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError )
144 {
145     if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
146     {
147         OSL_FAIL( "ScRangeData::CompileRangeData: unspecified grammar");
148         // Anything is almost as bad as this, but we might have the best choice
149         // if not loading documents.
150         eTempGrammar = FormulaGrammar::GRAM_NATIVE;
151     }
152 
153     ScCompiler aComp( pDoc, aPos, eTempGrammar );
154     if (bSetError)
155         aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_NO_BREAK);
156     pCode = aComp.CompileString( rSymbol );
157     pCode->SetFromRangeName(true);
158     if( pCode->GetCodeError() == FormulaError::NONE )
159     {
160         FormulaTokenArrayPlainIterator aIter(*pCode);
161         FormulaToken* p = aIter.GetNextReference();
162         if( p )
163         {
164             // first token is a reference
165             /* FIXME: wouldn't that need a check if it's exactly one reference? */
166             if( p->GetType() == svSingleRef )
167                 eType = eType | Type::AbsPos;
168             else
169                 eType = eType | Type::AbsArea;
170         }
171         // For manual input set an error for an incomplete formula.
172         if (!pDoc->IsImportingXML())
173         {
174             aComp.CompileTokenArray();
175             pCode->DelRPN();
176         }
177     }
178 }
179 
CompileUnresolvedXML(sc::CompileFormulaContext & rCxt)180 void ScRangeData::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt )
181 {
182     if (pCode->GetCodeError() == FormulaError::NoName)
183     {
184         // Reconstruct the symbol/formula and then recompile.
185         OUString aSymbol;
186         rCxt.setGrammar(eTempGrammar);
187         ScCompiler aComp(rCxt, aPos, *pCode);
188         aComp.CreateStringFromTokenArray( aSymbol);
189         // Don't let the compiler set an error for unknown names on final
190         // compile, errors are handled by the interpreter thereafter.
191         CompileRangeData( aSymbol, false);
192         rCxt.getDoc()->CheckLinkFormulaNeedingCheck( *pCode);
193     }
194 }
195 
196 #if DEBUG_FORMULA_COMPILER
Dump() const197 void ScRangeData::Dump() const
198 {
199     cout << "-- ScRangeData" << endl;
200     cout << "  name: " << aName << endl;
201     cout << "  ref position: (col=" << aPos.Col() << ", row=" << aPos.Row() << ", sheet=" << aPos.Tab() << ")" << endl;
202 
203     if (pCode)
204         pCode->Dump();
205 }
206 #endif
207 
GuessPosition()208 void ScRangeData::GuessPosition()
209 {
210     // set a position that allows "absoluting" of all relative references
211     // in CalcAbsIfRel without errors
212 
213     OSL_ENSURE(aPos == ScAddress(), "position will go lost now");
214 
215     SCCOL nMinCol = 0;
216     SCROW nMinRow = 0;
217     SCTAB nMinTab = 0;
218 
219     formula::FormulaToken* t;
220     formula::FormulaTokenArrayPlainIterator aIter(*pCode);
221     while ( ( t = aIter.GetNextReference() ) != nullptr )
222     {
223         ScSingleRefData& rRef1 = *t->GetSingleRef();
224         if ( rRef1.IsColRel() && rRef1.Col() < nMinCol )
225             nMinCol = rRef1.Col();
226         if ( rRef1.IsRowRel() && rRef1.Row() < nMinRow )
227             nMinRow = rRef1.Row();
228         if ( rRef1.IsTabRel() && rRef1.Tab() < nMinTab )
229             nMinTab = rRef1.Tab();
230 
231         if ( t->GetType() == svDoubleRef )
232         {
233             ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
234             if ( rRef2.IsColRel() && rRef2.Col() < nMinCol )
235                 nMinCol = rRef2.Col();
236             if ( rRef2.IsRowRel() && rRef2.Row() < nMinRow )
237                 nMinRow = rRef2.Row();
238             if ( rRef2.IsTabRel() && rRef2.Tab() < nMinTab )
239                 nMinTab = rRef2.Tab();
240         }
241     }
242 
243     aPos = ScAddress( static_cast<SCCOL>(-nMinCol), static_cast<SCROW>(-nMinRow), static_cast<SCTAB>(-nMinTab) );
244 }
245 
GetSymbol(OUString & rSymbol,const FormulaGrammar::Grammar eGrammar) const246 void ScRangeData::GetSymbol( OUString& rSymbol, const FormulaGrammar::Grammar eGrammar ) const
247 {
248     ScCompiler aComp(pDoc, aPos, *pCode, eGrammar);
249     aComp.CreateStringFromTokenArray( rSymbol );
250 }
251 
GetSymbol(OUString & rSymbol,const ScAddress & rPos,const FormulaGrammar::Grammar eGrammar) const252 void ScRangeData::GetSymbol( OUString& rSymbol, const ScAddress& rPos, const FormulaGrammar::Grammar eGrammar ) const
253 {
254     OUString aStr;
255     ScCompiler aComp(pDoc, rPos, *pCode, eGrammar);
256     aComp.CreateStringFromTokenArray( aStr );
257     rSymbol = aStr;
258 }
259 
UpdateSymbol(OUStringBuffer & rBuffer,const ScAddress & rPos)260 void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos )
261 {
262     std::unique_ptr<ScTokenArray> pTemp( pCode->Clone() );
263     ScCompiler aComp(pDoc, rPos, *pTemp, formula::FormulaGrammar::GRAM_DEFAULT);
264     aComp.MoveRelWrap();
265     aComp.CreateStringFromTokenArray( rBuffer );
266 }
267 
UpdateReference(sc::RefUpdateContext & rCxt,SCTAB nLocalTab)268 void ScRangeData::UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
269 {
270     sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt, aPos);
271     bModified = aRes.mbReferenceModified;
272     if (aRes.mbReferenceModified)
273         rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
274 }
275 
UpdateTranspose(const ScRange & rSource,const ScAddress & rDest)276 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
277 {
278     bool bChanged = false;
279 
280     formula::FormulaToken* t;
281     formula::FormulaTokenArrayPlainIterator aIter(*pCode);
282 
283     while ( ( t = aIter.GetNextReference() ) != nullptr )
284     {
285         if( t->GetType() != svIndex )
286         {
287             SingleDoubleRefModifier aMod( *t );
288             ScComplexRefData& rRef = aMod.Ref();
289             if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
290                     (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
291                 ( t->GetType() == svSingleRef ||
292                 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
293                     (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
294             {
295                 ScRange aAbs = rRef.toAbs(aPos);
296                 if (ScRefUpdate::UpdateTranspose(pDoc, rSource, rDest, aAbs) != UR_NOTHING)
297                 {
298                     rRef.SetRange(aAbs, aPos);
299                     bChanged = true;
300                 }
301             }
302         }
303     }
304 
305     bModified = bChanged;
306 }
307 
UpdateGrow(const ScRange & rArea,SCCOL nGrowX,SCROW nGrowY)308 void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
309 {
310     bool bChanged = false;
311 
312     formula::FormulaToken* t;
313     formula::FormulaTokenArrayPlainIterator aIter(*pCode);
314 
315     while ( ( t = aIter.GetNextReference() ) != nullptr )
316     {
317         if( t->GetType() != svIndex )
318         {
319             SingleDoubleRefModifier aMod( *t );
320             ScComplexRefData& rRef = aMod.Ref();
321             if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
322                     (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
323                 ( t->GetType() == svSingleRef ||
324                 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
325                     (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
326             {
327                 ScRange aAbs = rRef.toAbs(aPos);
328                 if (ScRefUpdate::UpdateGrow(rArea, nGrowX, nGrowY, aAbs) != UR_NOTHING)
329                 {
330                     rRef.SetRange(aAbs, aPos);
331                     bChanged = true;
332                 }
333             }
334         }
335     }
336 
337     bModified = bChanged;           // has to be evaluated immediately afterwards
338 }
339 
operator ==(const ScRangeData & rData) const340 bool ScRangeData::operator== (const ScRangeData& rData) const       // for Undo
341 {
342     if ( nIndex != rData.nIndex ||
343          aName  != rData.aName  ||
344          aPos   != rData.aPos   ||
345          eType  != rData.eType     ) return false;
346 
347     sal_uInt16 nLen = pCode->GetLen();
348     if ( nLen != rData.pCode->GetLen() ) return false;
349 
350     FormulaToken** ppThis = pCode->GetArray();
351     FormulaToken** ppOther = rData.pCode->GetArray();
352 
353     for ( sal_uInt16 i=0; i<nLen; i++ )
354         if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
355             return false;
356 
357     return true;
358 }
359 
IsRangeAtBlock(const ScRange & rBlock) const360 bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
361 {
362     bool bRet = false;
363     ScRange aRange;
364     if ( IsReference(aRange) )
365         bRet = ( rBlock == aRange );
366     return bRet;
367 }
368 
IsReference(ScRange & rRange) const369 bool ScRangeData::IsReference( ScRange& rRange ) const
370 {
371     if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos )) && pCode )
372         return pCode->IsReference(rRange, aPos);
373 
374     return false;
375 }
376 
IsReference(ScRange & rRange,const ScAddress & rPos) const377 bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
378 {
379     if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode )
380         return pCode->IsReference(rRange, rPos);
381 
382     return false;
383 }
384 
IsValidReference(ScRange & rRange) const385 bool ScRangeData::IsValidReference( ScRange& rRange ) const
386 {
387     if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode )
388         return pCode->IsValidReference(rRange, aPos);
389 
390     return false;
391 }
392 
UpdateInsertTab(sc::RefUpdateInsertTabContext & rCxt,SCTAB nLocalTab)393 void ScRangeData::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
394 {
395     sc::RefUpdateResult aRes = pCode->AdjustReferenceOnInsertedTab(rCxt, aPos);
396     if (aRes.mbReferenceModified)
397         rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
398 
399     if (rCxt.mnInsertPos <= aPos.Tab())
400         aPos.IncTab(rCxt.mnSheets);
401 }
402 
UpdateDeleteTab(sc::RefUpdateDeleteTabContext & rCxt,SCTAB nLocalTab)403 void ScRangeData::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
404 {
405     sc::RefUpdateResult aRes = pCode->AdjustReferenceOnDeletedTab(rCxt, aPos);
406     if (aRes.mbReferenceModified)
407         rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
408 
409     if (rCxt.mnDeletePos <= aPos.Tab())
410         aPos.IncTab(-rCxt.mnSheets);
411 }
412 
UpdateMoveTab(sc::RefUpdateMoveTabContext & rCxt,SCTAB nLocalTab)413 void ScRangeData::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
414 {
415     sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMovedTab(rCxt, aPos);
416     if (aRes.mbReferenceModified)
417         rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
418 
419     aPos.SetTab(rCxt.getNewTab(aPos.Tab()));
420 }
421 
MakeValidName(const ScDocument * pDoc,OUString & rName)422 void ScRangeData::MakeValidName( const ScDocument* pDoc, OUString& rName )
423 {
424 
425     // strip leading invalid characters
426     sal_Int32 nPos = 0;
427     sal_Int32 nLen = rName.getLength();
428     while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) )
429         ++nPos;
430     if ( nPos>0 )
431         rName = rName.copy(nPos);
432 
433     // if the first character is an invalid start character, precede with '_'
434     if ( !rName.isEmpty() && !ScCompiler::IsCharFlagAllConventions( rName, 0, ScCharFlags::CharName ) )
435         rName = "_" + rName;
436 
437     // replace invalid with '_'
438     nLen = rName.getLength();
439     for (nPos=0; nPos<nLen; nPos++)
440     {
441         if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) )
442             rName = rName.replaceAt( nPos, 1, "_" );
443     }
444 
445     // Ensure that the proposed name is not a reference under any convention,
446     // same as in IsNameValid()
447     ScAddress aAddr;
448     ScRange aRange;
449     for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
450     {
451         ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
452         // Don't check Parse on VALID, any partial only VALID may result in
453         // #REF! during compile later!
454         while (aRange.Parse(rName, pDoc, details) != ScRefFlags::ZERO ||
455                 aAddr.Parse(rName, pDoc, details) != ScRefFlags::ZERO)
456         {
457             // Range Parse is partially valid also with invalid sheet name,
458             // Address Parse dito, during compile name would generate a #REF!
459             if ( rName.indexOf( '.' ) != -1 )
460                 rName = rName.replaceFirst( ".", "_" );
461             else
462                 rName = "_" + rName;
463         }
464     }
465 }
466 
IsNameValid(const OUString & rName,const ScDocument * pDoc)467 ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, const ScDocument* pDoc )
468 {
469     /* XXX If changed, sc/source/filter/ftools/ftools.cxx
470      * ScfTools::ConvertToScDefinedName needs to be changed too. */
471     sal_Char const a('.');
472     if (rName.indexOf(a) != -1)
473         return NAME_INVALID_BAD_STRING;
474     sal_Int32 nPos = 0;
475     sal_Int32 nLen = rName.getLength();
476     if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::CharName ) )
477         return NAME_INVALID_BAD_STRING;
478     while ( nPos < nLen )
479     {
480         if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::Name ) )
481             return NAME_INVALID_BAD_STRING;
482     }
483     ScAddress aAddr;
484     ScRange aRange;
485     for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
486     {
487         ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
488         // Don't check Parse on VALID, any partial only VALID may result in
489         // #REF! during compile later!
490         if (aRange.Parse(rName, pDoc, details) != ScRefFlags::ZERO ||
491              aAddr.Parse(rName, pDoc, details) != ScRefFlags::ZERO )
492         {
493             return NAME_INVALID_CELL_REF;
494         }
495     }
496     return NAME_VALID;
497 }
498 
GetErrCode() const499 FormulaError ScRangeData::GetErrCode() const
500 {
501     return pCode ? pCode->GetCodeError() : FormulaError::NONE;
502 }
503 
HasReferences() const504 bool ScRangeData::HasReferences() const
505 {
506     return pCode->HasReferences();
507 }
508 
GetUnoType() const509 sal_uInt32 ScRangeData::GetUnoType() const
510 {
511     sal_uInt32 nUnoType = 0;
512     if ( HasType(Type::Criteria) )  nUnoType |= css::sheet::NamedRangeFlag::FILTER_CRITERIA;
513     if ( HasType(Type::PrintArea) ) nUnoType |= css::sheet::NamedRangeFlag::PRINT_AREA;
514     if ( HasType(Type::ColHeader) ) nUnoType |= css::sheet::NamedRangeFlag::COLUMN_HEADER;
515     if ( HasType(Type::RowHeader) ) nUnoType |= css::sheet::NamedRangeFlag::ROW_HEADER;
516     return nUnoType;
517 }
518 
ValidateTabRefs()519 void ScRangeData::ValidateTabRefs()
520 {
521     //  try to make sure all relative references and the reference position
522     //  are within existing tables, so they can be represented as text
523     //  (if the range of used tables is more than the existing tables,
524     //  the result may still contain invalid tables, because the relative
525     //  references aren't changed so formulas stay the same)
526 
527     //  find range of used tables
528 
529     SCTAB nMinTab = aPos.Tab();
530     SCTAB nMaxTab = nMinTab;
531     formula::FormulaToken* t;
532     formula::FormulaTokenArrayPlainIterator aIter(*pCode);
533     while ( ( t = aIter.GetNextReference() ) != nullptr )
534     {
535         ScSingleRefData& rRef1 = *t->GetSingleRef();
536         ScAddress aAbs = rRef1.toAbs(aPos);
537         if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
538         {
539             if (aAbs.Tab() < nMinTab)
540                 nMinTab = aAbs.Tab();
541             if (aAbs.Tab() > nMaxTab)
542                 nMaxTab = aAbs.Tab();
543         }
544         if ( t->GetType() == svDoubleRef )
545         {
546             ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
547             aAbs = rRef2.toAbs(aPos);
548             if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
549             {
550                 if (aAbs.Tab() < nMinTab)
551                     nMinTab = aAbs.Tab();
552                 if (aAbs.Tab() > nMaxTab)
553                     nMaxTab = aAbs.Tab();
554             }
555         }
556     }
557 
558     SCTAB nTabCount = pDoc->GetTableCount();
559     if ( nMaxTab >= nTabCount && nMinTab > 0 )
560     {
561         //  move position and relative tab refs
562         //  The formulas that use the name are not changed by this
563 
564         SCTAB nMove = nMinTab;
565         ScAddress aOldPos = aPos;
566         aPos.SetTab( aPos.Tab() - nMove );
567 
568         aIter.Reset();
569         while ( ( t = aIter.GetNextReference() ) != nullptr )
570         {
571             switch (t->GetType())
572             {
573                 case svSingleRef:
574                 {
575                     ScSingleRefData& rRef = *t->GetSingleRef();
576                     if (!rRef.IsTabDeleted())
577                     {
578                         ScAddress aAbs = rRef.toAbs(aOldPos);
579                         rRef.SetAddress(aAbs, aPos);
580                     }
581                 }
582                 break;
583                 case svDoubleRef:
584                 {
585                     ScComplexRefData& rRef = *t->GetDoubleRef();
586                     if (!rRef.Ref1.IsTabDeleted())
587                     {
588                         ScAddress aAbs = rRef.Ref1.toAbs(aOldPos);
589                         rRef.Ref1.SetAddress(aAbs, aPos);
590                     }
591                     if (!rRef.Ref2.IsTabDeleted())
592                     {
593                         ScAddress aAbs = rRef.Ref2.toAbs(aOldPos);
594                         rRef.Ref2.SetAddress(aAbs, aPos);
595                     }
596                 }
597                 break;
598                 default:
599                     ;
600             }
601         }
602     }
603 }
604 
SetCode(const ScTokenArray & rArr)605 void ScRangeData::SetCode( const ScTokenArray& rArr )
606 {
607     pCode.reset(new ScTokenArray( rArr ));
608     pCode->SetFromRangeName(true);
609     InitCode();
610 }
611 
InitCode()612 void ScRangeData::InitCode()
613 {
614     if( pCode->GetCodeError() == FormulaError::NONE )
615     {
616         FormulaToken* p = FormulaTokenArrayPlainIterator(*pCode).GetNextReference();
617         if( p )   // exact one reference at first
618         {
619             if( p->GetType() == svSingleRef )
620                 eType = eType | Type::AbsPos;
621             else
622                 eType = eType | Type::AbsArea;
623         }
624     }
625 }
626 
627 extern "C"
ScRangeData_QsortNameCompare(const void * p1,const void * p2)628 int ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
629 {
630     return static_cast<int>(ScGlobal::GetCollator()->compareString(
631             (*static_cast<const ScRangeData* const *>(p1))->GetName(),
632             (*static_cast<const ScRangeData* const *>(p2))->GetName() ));
633 }
634 
635 namespace {
636 
637 /**
638  * Predicate to check if the name references the specified range.
639  */
640 class MatchByRange
641 {
642     const ScRange& mrRange;
643 public:
MatchByRange(const ScRange & rRange)644     explicit MatchByRange(const ScRange& rRange) : mrRange(rRange) {}
operator ()(std::pair<OUString const,std::unique_ptr<ScRangeData>> const & r) const645     bool operator() (std::pair<OUString const, std::unique_ptr<ScRangeData>> const& r) const
646     {
647         return r.second->IsRangeAtBlock(mrRange);
648     }
649 };
650 
651 }
652 
ScRangeName()653 ScRangeName::ScRangeName() {}
654 
ScRangeName(const ScRangeName & r)655 ScRangeName::ScRangeName(const ScRangeName& r)
656 {
657     for (auto const& it : r.m_Data)
658     {
659         m_Data.insert(std::make_pair(it.first, std::make_unique<ScRangeData>(*it.second)));
660     }
661     // std::map was cloned, so each collection needs its own index to data.
662     maIndexToData.resize( r.maIndexToData.size(), nullptr);
663     for (auto const& itr : m_Data)
664     {
665         size_t nPos = itr.second->GetIndex() - 1;
666         if (nPos >= maIndexToData.size())
667         {
668             OSL_FAIL( "ScRangeName copy-ctor: maIndexToData size doesn't fit");
669             maIndexToData.resize(nPos+1, nullptr);
670         }
671         maIndexToData[nPos] = itr.second.get();
672     }
673 }
674 
findByRange(const ScRange & rRange) const675 const ScRangeData* ScRangeName::findByRange(const ScRange& rRange) const
676 {
677     DataType::const_iterator itr = std::find_if(
678         m_Data.begin(), m_Data.end(), MatchByRange(rRange));
679     return itr == m_Data.end() ? nullptr : itr->second.get();
680 }
681 
findByUpperName(const OUString & rName)682 ScRangeData* ScRangeName::findByUpperName(const OUString& rName)
683 {
684     DataType::iterator itr = m_Data.find(rName);
685     return itr == m_Data.end() ? nullptr : itr->second.get();
686 }
687 
findByUpperName(const OUString & rName) const688 const ScRangeData* ScRangeName::findByUpperName(const OUString& rName) const
689 {
690     DataType::const_iterator itr = m_Data.find(rName);
691     return itr == m_Data.end() ? nullptr : itr->second.get();
692 }
693 
findByIndex(sal_uInt16 i) const694 ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const
695 {
696     if (!i)
697         // index should never be zero.
698         return nullptr;
699 
700     size_t nPos = i - 1;
701     return nPos < maIndexToData.size() ? maIndexToData[nPos] : nullptr;
702 }
703 
UpdateReference(sc::RefUpdateContext & rCxt,SCTAB nLocalTab)704 void ScRangeName::UpdateReference(sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
705 {
706     if (rCxt.meMode == URM_COPY)
707         // Copying cells does not modify named expressions.
708         return;
709 
710     for (auto const& itr : m_Data)
711     {
712         itr.second->UpdateReference(rCxt, nLocalTab);
713     }
714 }
715 
UpdateInsertTab(sc::RefUpdateInsertTabContext & rCxt,SCTAB nLocalTab)716 void ScRangeName::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
717 {
718     for (auto const& itr : m_Data)
719     {
720         itr.second->UpdateInsertTab(rCxt, nLocalTab);
721     }
722 }
723 
UpdateDeleteTab(sc::RefUpdateDeleteTabContext & rCxt,SCTAB nLocalTab)724 void ScRangeName::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
725 {
726     for (auto const& itr : m_Data)
727     {
728         itr.second->UpdateDeleteTab(rCxt, nLocalTab);
729     }
730 }
731 
UpdateMoveTab(sc::RefUpdateMoveTabContext & rCxt,SCTAB nLocalTab)732 void ScRangeName::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
733 {
734     for (auto const& itr : m_Data)
735     {
736         itr.second->UpdateMoveTab(rCxt, nLocalTab);
737     }
738 }
739 
UpdateTranspose(const ScRange & rSource,const ScAddress & rDest)740 void ScRangeName::UpdateTranspose(const ScRange& rSource, const ScAddress& rDest)
741 {
742     for (auto const& itr : m_Data)
743     {
744         itr.second->UpdateTranspose(rSource, rDest);
745     }
746 }
747 
UpdateGrow(const ScRange & rArea,SCCOL nGrowX,SCROW nGrowY)748 void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY)
749 {
750     for (auto const& itr : m_Data)
751     {
752         itr.second->UpdateGrow(rArea, nGrowX, nGrowY);
753     }
754 }
755 
CompileUnresolvedXML(sc::CompileFormulaContext & rCxt)756 void ScRangeName::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt )
757 {
758     for (auto const& itr : m_Data)
759     {
760         itr.second->CompileUnresolvedXML(rCxt);
761     }
762 }
763 
CopyUsedNames(const SCTAB nLocalTab,const SCTAB nOldTab,const SCTAB nNewTab,const ScDocument & rOldDoc,ScDocument & rNewDoc,const bool bGlobalNamesToLocal) const764 void ScRangeName::CopyUsedNames( const SCTAB nLocalTab, const SCTAB nOldTab, const SCTAB nNewTab,
765         const ScDocument& rOldDoc, ScDocument& rNewDoc, const bool bGlobalNamesToLocal ) const
766 {
767     for (auto const& itr : m_Data)
768     {
769         SCTAB nSheet = (nLocalTab < 0) ? nLocalTab : nOldTab;
770         sal_uInt16 nIndex = itr.second->GetIndex();
771         ScAddress aOldPos( itr.second->GetPos());
772         aOldPos.SetTab( nOldTab);
773         ScAddress aNewPos( aOldPos);
774         aNewPos.SetTab( nNewTab);
775         ScRangeData* pRangeData = nullptr;
776         rOldDoc.CopyAdjustRangeName( nSheet, nIndex, pRangeData, rNewDoc, aNewPos, aOldPos, bGlobalNamesToLocal, false);
777     }
778 }
779 
begin() const780 ScRangeName::const_iterator ScRangeName::begin() const
781 {
782     return m_Data.begin();
783 }
784 
end() const785 ScRangeName::const_iterator ScRangeName::end() const
786 {
787     return m_Data.end();
788 }
789 
begin()790 ScRangeName::iterator ScRangeName::begin()
791 {
792     return m_Data.begin();
793 }
794 
end()795 ScRangeName::iterator ScRangeName::end()
796 {
797     return m_Data.end();
798 }
799 
size() const800 size_t ScRangeName::size() const
801 {
802     return m_Data.size();
803 }
804 
empty() const805 bool ScRangeName::empty() const
806 {
807     return m_Data.empty();
808 }
809 
insert(ScRangeData * p,bool bReuseFreeIndex)810 bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex )
811 {
812     if (!p)
813         return false;
814 
815     if (!p->GetIndex())
816     {
817         // Assign a new index.  An index must be unique and is never 0.
818         if (bReuseFreeIndex)
819         {
820             IndexDataType::iterator itr = std::find(
821                     maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(nullptr));
822             if (itr != maIndexToData.end())
823             {
824                 // Empty slot exists.  Re-use it.
825                 size_t nPos = std::distance(maIndexToData.begin(), itr);
826                 p->SetIndex(nPos + 1);
827             }
828             else
829                 // No empty slot.  Append it to the end.
830                 p->SetIndex(maIndexToData.size() + 1);
831         }
832         else
833         {
834             p->SetIndex(maIndexToData.size() + 1);
835         }
836     }
837 
838     OUString aName(p->GetUpperName());
839     erase(aName); // ptr_map won't insert it if a duplicate name exists.
840     pair<DataType::iterator, bool> r =
841         m_Data.insert(std::make_pair(aName, std::unique_ptr<ScRangeData>(p)));
842     if (r.second)
843     {
844         // Data inserted.  Store its index for mapping.
845         size_t nPos = p->GetIndex() - 1;
846         if (nPos >= maIndexToData.size())
847             maIndexToData.resize(nPos+1, nullptr);
848         maIndexToData[nPos] = p;
849     }
850     return r.second;
851 }
852 
erase(const ScRangeData & r)853 void ScRangeName::erase(const ScRangeData& r)
854 {
855     erase(r.GetUpperName());
856 }
857 
erase(const OUString & rName)858 void ScRangeName::erase(const OUString& rName)
859 {
860     DataType::iterator itr = m_Data.find(rName);
861     if (itr != m_Data.end())
862         erase(itr);
863 }
864 
erase(const iterator & itr)865 void ScRangeName::erase(const iterator& itr)
866 {
867     sal_uInt16 nIndex = itr->second->GetIndex();
868     m_Data.erase(itr);
869     OSL_ENSURE( 0 < nIndex && nIndex <= maIndexToData.size(), "ScRangeName::erase: bad index");
870     if (0 < nIndex && nIndex <= maIndexToData.size())
871         maIndexToData[nIndex-1] = nullptr;
872 }
873 
clear()874 void ScRangeName::clear()
875 {
876     m_Data.clear();
877     maIndexToData.clear();
878 }
879 
operator ==(const ScRangeName & r) const880 bool ScRangeName::operator== (const ScRangeName& r) const
881 {
882     return std::equal(m_Data.begin(), m_Data.end(), r.m_Data.begin(), r.m_Data.end(),
883         [](const DataType::value_type& lhs, const DataType::value_type& rhs) {
884             return (lhs.first == rhs.first) && (*lhs.second == *rhs.second);
885         });
886 }
887 
888 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
889