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