tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / tool / rangenam.cxx
blob051b0a5e77ac062be26d5ce006dd146166be4b12
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
21 #include <memory>
22 #include <unotools/collatorwrapper.hxx>
23 #include <unotools/charclass.hxx>
24 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
25 #include <osl/diagnose.h>
27 #include <token.hxx>
28 #include <tokenarray.hxx>
29 #include <rangenam.hxx>
30 #include <rangeutl.hxx>
31 #include <global.hxx>
32 #include <compiler.hxx>
33 #include <refupdat.hxx>
34 #include <document.hxx>
35 #include <refupdatecontext.hxx>
36 #include <tokenstringcontext.hxx>
38 #include <formula/errorcodes.hxx>
40 using namespace formula;
41 using ::std::pair;
43 // ScRangeData
45 ScRangeData::ScRangeData( ScDocument& rDok,
46 const OUString& rName,
47 const OUString& rSymbol,
48 const ScAddress& rAddress,
49 Type nType,
50 const FormulaGrammar::Grammar eGrammar ) :
51 aName ( rName ),
52 aUpperName ( ScGlobal::getCharClass().uppercase( rName ) ),
53 aPos ( rAddress ),
54 eType ( nType ),
55 rDoc ( rDok ),
56 eTempGrammar( eGrammar ),
57 nIndex ( 0 ),
58 bModified ( false )
60 if (!rSymbol.isEmpty())
62 // Let the compiler set an error on unknown names for a subsequent
63 // CompileUnresolvedXML().
64 const bool bImporting = rDoc.IsImportingXML();
65 CompileRangeData( rSymbol, bImporting);
66 if (bImporting)
67 rDoc.CheckLinkFormulaNeedingCheck( *pCode);
69 else
71 // #i63513#/#i65690# don't leave pCode as NULL.
72 // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
73 // to ensure same behavior if unnecessary copying is left out.
75 pCode.reset( new ScTokenArray(rDoc) );
76 pCode->SetFromRangeName(true);
80 ScRangeData::ScRangeData( ScDocument& rDok,
81 const OUString& rName,
82 const ScTokenArray& rArr,
83 const ScAddress& rAddress,
84 Type nType ) :
85 aName ( rName ),
86 aUpperName ( ScGlobal::getCharClass().uppercase( rName ) ),
87 pCode ( new ScTokenArray( rArr ) ),
88 aPos ( rAddress ),
89 eType ( nType ),
90 rDoc ( rDok ),
91 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
92 nIndex ( 0 ),
93 bModified ( false )
95 pCode->SetFromRangeName(true);
96 InitCode();
99 ScRangeData::ScRangeData( ScDocument& rDok,
100 const OUString& rName,
101 const ScAddress& rTarget ) :
102 aName ( rName ),
103 aUpperName ( ScGlobal::getCharClass().uppercase( rName ) ),
104 pCode ( new ScTokenArray(rDok) ),
105 aPos ( rTarget ),
106 eType ( Type::Name ),
107 rDoc ( rDok ),
108 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
109 nIndex ( 0 ),
110 bModified ( false )
112 ScSingleRefData aRefData;
113 aRefData.InitAddress( rTarget );
114 aRefData.SetFlag3D( true );
115 pCode->AddSingleReference( aRefData );
116 pCode->SetFromRangeName(true);
117 ScCompiler aComp( rDoc, aPos, *pCode, rDoc.GetGrammar() );
118 aComp.CompileTokenArray();
119 if ( pCode->GetCodeError() == FormulaError::NONE )
120 eType |= Type::AbsPos;
123 ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* pDocument, const ScAddress* pPos) :
124 aName (rScRangeData.aName),
125 aUpperName (rScRangeData.aUpperName),
126 pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone().release() : new ScTokenArray(*pDocument)), // make real copy (not copy-ctor)
127 aPos (pPos ? *pPos : rScRangeData.aPos),
128 eType (rScRangeData.eType),
129 rDoc (pDocument ? *pDocument : rScRangeData.rDoc),
130 eTempGrammar(rScRangeData.eTempGrammar),
131 nIndex (rScRangeData.nIndex),
132 bModified (rScRangeData.bModified)
134 pCode->SetFromRangeName(true);
137 ScRangeData::~ScRangeData()
141 void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError )
143 if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
145 OSL_FAIL( "ScRangeData::CompileRangeData: unspecified grammar");
146 // Anything is almost as bad as this, but we might have the best choice
147 // if not loading documents.
148 eTempGrammar = FormulaGrammar::GRAM_NATIVE;
151 ScCompiler aComp( rDoc, aPos, eTempGrammar );
152 if (bSetError)
153 aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_NO_BREAK);
154 pCode = aComp.CompileString( rSymbol );
155 pCode->SetFromRangeName(true);
156 if( pCode->GetCodeError() != FormulaError::NONE )
157 return;
159 FormulaTokenArrayPlainIterator aIter(*pCode);
160 FormulaToken* p = aIter.GetNextReference();
161 if( p )
163 // first token is a reference
164 /* FIXME: wouldn't that need a check if it's exactly one reference? */
165 if( p->GetType() == svSingleRef )
166 eType = eType | Type::AbsPos;
167 else
168 eType = eType | Type::AbsArea;
170 // For manual input set an error for an incomplete formula.
171 if (!rDoc.IsImportingXML())
173 aComp.CompileTokenArray();
174 pCode->DelRPN();
178 void ScRangeData::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt )
180 if (pCode->GetCodeError() == FormulaError::NoName)
182 // Reconstruct the symbol/formula and then recompile.
183 OUString aSymbol;
184 rCxt.setGrammar(eTempGrammar);
185 ScCompiler aComp(rCxt, aPos, *pCode);
186 aComp.CreateStringFromTokenArray( aSymbol);
187 // Don't let the compiler set an error for unknown names on final
188 // compile, errors are handled by the interpreter thereafter.
189 CompileRangeData( aSymbol, false);
190 rCxt.getDoc().CheckLinkFormulaNeedingCheck( *pCode);
194 #if DEBUG_FORMULA_COMPILER
195 void ScRangeData::Dump() const
197 cout << "-- ScRangeData" << endl;
198 cout << " name: " << aName << endl;
199 cout << " ref position: (col=" << aPos.Col() << ", row=" << aPos.Row() << ", sheet=" << aPos.Tab() << ")" << endl;
201 if (pCode)
202 pCode->Dump();
204 #endif
206 void ScRangeData::GuessPosition()
208 // set a position that allows "absoluting" of all relative references
209 // in CalcAbsIfRel without errors
211 OSL_ENSURE(aPos == ScAddress(), "position will go lost now");
213 SCCOL nMinCol = 0;
214 SCROW nMinRow = 0;
215 SCTAB nMinTab = 0;
217 formula::FormulaToken* t;
218 formula::FormulaTokenArrayPlainIterator aIter(*pCode);
219 while ( ( t = aIter.GetNextReference() ) != nullptr )
221 ScSingleRefData& rRef1 = *t->GetSingleRef();
222 if ( rRef1.IsColRel() && rRef1.Col() < nMinCol )
223 nMinCol = rRef1.Col();
224 if ( rRef1.IsRowRel() && rRef1.Row() < nMinRow )
225 nMinRow = rRef1.Row();
226 if ( rRef1.IsTabRel() && rRef1.Tab() < nMinTab )
227 nMinTab = rRef1.Tab();
229 if ( t->GetType() == svDoubleRef )
231 ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
232 if ( rRef2.IsColRel() && rRef2.Col() < nMinCol )
233 nMinCol = rRef2.Col();
234 if ( rRef2.IsRowRel() && rRef2.Row() < nMinRow )
235 nMinRow = rRef2.Row();
236 if ( rRef2.IsTabRel() && rRef2.Tab() < nMinTab )
237 nMinTab = rRef2.Tab();
241 aPos = ScAddress( static_cast<SCCOL>(-nMinCol), static_cast<SCROW>(-nMinRow), static_cast<SCTAB>(-nMinTab) );
244 OUString ScRangeData::GetSymbol( const FormulaGrammar::Grammar eGrammar ) const
246 ScCompiler aComp(rDoc, aPos, *pCode, eGrammar);
247 OUString symbol;
248 aComp.CreateStringFromTokenArray( symbol );
249 return symbol;
252 OUString ScRangeData::GetSymbol( const ScAddress& rPos, const FormulaGrammar::Grammar eGrammar ) const
254 OUString aStr;
255 ScCompiler aComp(rDoc, rPos, *pCode, eGrammar);
256 aComp.CreateStringFromTokenArray( aStr );
257 return aStr;
260 void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos )
262 ScTokenArray aTemp( pCode->CloneValue() );
263 ScCompiler aComp(rDoc, rPos, aTemp, formula::FormulaGrammar::GRAM_DEFAULT);
264 aComp.MoveRelWrap();
265 aComp.CreateStringFromTokenArray( rBuffer );
268 void ScRangeData::UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
270 sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt, aPos);
271 bModified = aRes.mbReferenceModified;
272 if (aRes.mbReferenceModified)
273 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
276 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
278 bool bChanged = false;
280 formula::FormulaToken* t;
281 formula::FormulaTokenArrayPlainIterator aIter(*pCode);
283 while ( ( t = aIter.GetNextReference() ) != nullptr )
285 if( t->GetType() != svIndex )
287 SingleDoubleRefModifier aMod( *t );
288 ScComplexRefData& rRef = aMod.Ref();
289 // Update only absolute references
290 if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
291 (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
292 ( t->GetType() == svSingleRef ||
293 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
294 (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
296 ScRange aAbs = rRef.toAbs(rDoc, aPos);
297 // Check if the absolute reference of this range is pointing to the transposed source
298 if (ScRefUpdate::UpdateTranspose(rDoc, rSource, rDest, aAbs) != UR_NOTHING)
300 rRef.SetRange(rDoc.GetSheetLimits(), aAbs, aPos);
301 bChanged = true;
307 bModified = bChanged;
310 void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
312 bool bChanged = false;
314 formula::FormulaToken* t;
315 formula::FormulaTokenArrayPlainIterator aIter(*pCode);
317 while ( ( t = aIter.GetNextReference() ) != nullptr )
319 if( t->GetType() != svIndex )
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()))))
329 ScRange aAbs = rRef.toAbs(rDoc, aPos);
330 if (ScRefUpdate::UpdateGrow(rArea, nGrowX, nGrowY, aAbs) != UR_NOTHING)
332 rRef.SetRange(rDoc.GetSheetLimits(), aAbs, aPos);
333 bChanged = true;
339 bModified = bChanged; // has to be evaluated immediately afterwards
342 bool ScRangeData::operator== (const ScRangeData& rData) const // for Undo
344 if ( nIndex != rData.nIndex ||
345 aName != rData.aName ||
346 aPos != rData.aPos ||
347 eType != rData.eType ) return false;
349 sal_uInt16 nLen = pCode->GetLen();
350 if ( nLen != rData.pCode->GetLen() ) return false;
352 FormulaToken** ppThis = pCode->GetArray();
353 FormulaToken** ppOther = rData.pCode->GetArray();
355 for ( sal_uInt16 i=0; i<nLen; i++ )
356 if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
357 return false;
359 return true;
362 bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
364 bool bRet = false;
365 ScRange aRange;
366 if ( IsReference(aRange) )
367 bRet = ( rBlock == aRange );
368 return bRet;
371 bool ScRangeData::IsReference( ScRange& rRange ) const
373 if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos )) && pCode )
374 return pCode->IsReference(rRange, aPos);
376 return false;
379 bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
381 if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode )
382 return pCode->IsReference(rRange, rPos);
384 return false;
387 bool ScRangeData::IsValidReference( ScRange& rRange ) const
389 if ( (eType & ( Type::AbsArea | Type::RefArea | Type::AbsPos ) ) && pCode )
390 return pCode->IsValidReference(rRange, aPos);
392 return false;
395 void ScRangeData::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
397 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnInsertedTab(rCxt, aPos);
398 if (aRes.mbReferenceModified)
399 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
401 if (rCxt.mnInsertPos <= aPos.Tab())
402 aPos.IncTab(rCxt.mnSheets);
405 void ScRangeData::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
407 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnDeletedTab(rCxt, aPos);
408 if (aRes.mbReferenceModified)
409 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
411 ScRangeUpdater::UpdateDeleteTab( aPos, rCxt);
414 void ScRangeData::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
416 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMovedTab(rCxt, aPos);
417 if (aRes.mbReferenceModified)
418 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
420 aPos.SetTab(rCxt.getNewTab(aPos.Tab()));
423 void ScRangeData::MakeValidName( const ScDocument& rDoc, OUString& rName )
426 // strip leading invalid characters
427 sal_Int32 nPos = 0;
428 sal_Int32 nLen = rName.getLength();
429 while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) )
430 ++nPos;
431 if ( nPos>0 )
432 rName = rName.copy(nPos);
434 // if the first character is an invalid start character, precede with '_'
435 if ( !rName.isEmpty() && !ScCompiler::IsCharFlagAllConventions( rName, 0, ScCharFlags::CharName ) )
436 rName = "_" + rName;
438 // replace invalid with '_'
439 nLen = rName.getLength();
440 for (nPos=0; nPos<nLen; nPos++)
442 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, ScCharFlags::Name) )
443 rName = rName.replaceAt( nPos, 1, u"_" );
446 // Ensure that the proposed name is not a reference under any convention,
447 // same as in IsNameValid()
448 ScAddress aAddr;
449 ScRange aRange;
450 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
452 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
453 // Don't check Parse on VALID, any partial only VALID may result in
454 // #REF! during compile later!
455 while (aRange.Parse(rName, rDoc, details) != ScRefFlags::ZERO ||
456 aAddr.Parse(rName, rDoc, details) != ScRefFlags::ZERO)
458 // Range Parse is partially valid also with invalid sheet name,
459 // Address Parse ditto, during compile name would generate a #REF!
460 if ( rName.indexOf( '.' ) != -1 )
461 rName = rName.replaceFirst( ".", "_" );
462 else
463 rName = "_" + rName;
468 ScRangeData::IsNameValidType ScRangeData::IsNameValid( const OUString& rName, const ScDocument& rDoc )
470 /* XXX If changed, sc/source/filter/ftools/ftools.cxx
471 * ScfTools::ConvertToScDefinedName needs to be changed too. */
472 char const a('.');
473 if (rName.indexOf(a) != -1)
474 return IsNameValidType::NAME_INVALID_BAD_STRING;
475 sal_Int32 nPos = 0;
476 sal_Int32 nLen = rName.getLength();
477 if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::CharName ) )
478 return IsNameValidType::NAME_INVALID_BAD_STRING;
479 while ( nPos < nLen )
481 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, ScCharFlags::Name ) )
482 return IsNameValidType::NAME_INVALID_BAD_STRING;
484 ScAddress aAddr;
485 ScRange aRange;
486 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
488 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
489 // Don't check Parse on VALID, any partial only VALID may result in
490 // #REF! during compile later!
491 if (aRange.Parse(rName, rDoc, details) != ScRefFlags::ZERO ||
492 aAddr.Parse(rName, rDoc, details) != ScRefFlags::ZERO )
494 return IsNameValidType::NAME_INVALID_CELL_REF;
497 return IsNameValidType::NAME_VALID;
500 bool ScRangeData::HasPossibleAddressConflict() const
502 // Similar to part of IsNameValid(), but only check if the name is a valid address.
503 ScAddress aAddr;
504 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
506 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
507 // Don't check Parse on VALID, any partial only VALID may result in
508 // #REF! during compile later!
509 if(aAddr.Parse(aUpperName, rDoc, details) != ScRefFlags::ZERO)
510 return true;
512 return false;
515 FormulaError ScRangeData::GetErrCode() const
517 return pCode ? pCode->GetCodeError() : FormulaError::NONE;
520 bool ScRangeData::HasReferences() const
522 return pCode->HasReferences();
525 sal_uInt32 ScRangeData::GetUnoType() const
527 sal_uInt32 nUnoType = 0;
528 if ( HasType(Type::Criteria) ) nUnoType |= css::sheet::NamedRangeFlag::FILTER_CRITERIA;
529 if ( HasType(Type::PrintArea) ) nUnoType |= css::sheet::NamedRangeFlag::PRINT_AREA;
530 if ( HasType(Type::ColHeader) ) nUnoType |= css::sheet::NamedRangeFlag::COLUMN_HEADER;
531 if ( HasType(Type::RowHeader) ) nUnoType |= css::sheet::NamedRangeFlag::ROW_HEADER;
532 if ( HasType(Type::Hidden) ) nUnoType |= css::sheet::NamedRangeFlag::HIDDEN;
533 return nUnoType;
536 void ScRangeData::ValidateTabRefs()
538 // try to make sure all relative references and the reference position
539 // are within existing tables, so they can be represented as text
540 // (if the range of used tables is more than the existing tables,
541 // the result may still contain invalid tables, because the relative
542 // references aren't changed so formulas stay the same)
544 // find range of used tables
546 SCTAB nMinTab = aPos.Tab();
547 SCTAB nMaxTab = nMinTab;
548 formula::FormulaToken* t;
549 formula::FormulaTokenArrayPlainIterator aIter(*pCode);
550 while ( ( t = aIter.GetNextReference() ) != nullptr )
552 ScSingleRefData& rRef1 = *t->GetSingleRef();
553 ScAddress aAbs = rRef1.toAbs(rDoc, aPos);
554 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
556 if (aAbs.Tab() < nMinTab)
557 nMinTab = aAbs.Tab();
558 if (aAbs.Tab() > nMaxTab)
559 nMaxTab = aAbs.Tab();
561 if ( t->GetType() == svDoubleRef )
563 ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
564 aAbs = rRef2.toAbs(rDoc, aPos);
565 if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
567 if (aAbs.Tab() < nMinTab)
568 nMinTab = aAbs.Tab();
569 if (aAbs.Tab() > nMaxTab)
570 nMaxTab = aAbs.Tab();
575 SCTAB nTabCount = rDoc.GetTableCount();
576 if ( nMaxTab < nTabCount || nMinTab <= 0 )
577 return;
579 // move position and relative tab refs
580 // The formulas that use the name are not changed by this
582 SCTAB nMove = nMinTab;
583 ScAddress aOldPos = aPos;
584 aPos.SetTab( aPos.Tab() - nMove );
586 aIter.Reset();
587 while ( ( t = aIter.GetNextReference() ) != nullptr )
589 switch (t->GetType())
591 case svSingleRef:
593 ScSingleRefData& rRef = *t->GetSingleRef();
594 if (!rRef.IsTabDeleted())
596 ScAddress aAbs = rRef.toAbs(rDoc, aOldPos);
597 rRef.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos);
600 break;
601 case svDoubleRef:
603 ScComplexRefData& rRef = *t->GetDoubleRef();
604 if (!rRef.Ref1.IsTabDeleted())
606 ScAddress aAbs = rRef.Ref1.toAbs(rDoc, aOldPos);
607 rRef.Ref1.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos);
609 if (!rRef.Ref2.IsTabDeleted())
611 ScAddress aAbs = rRef.Ref2.toAbs(rDoc, aOldPos);
612 rRef.Ref2.SetAddress(rDoc.GetSheetLimits(), aAbs, aPos);
615 break;
616 default:
622 void ScRangeData::SetCode( const ScTokenArray& rArr )
624 pCode.reset(new ScTokenArray( rArr ));
625 pCode->SetFromRangeName(true);
626 InitCode();
629 void ScRangeData::InitCode()
631 if( pCode->GetCodeError() == FormulaError::NONE )
633 FormulaToken* p = FormulaTokenArrayPlainIterator(*pCode).GetNextReference();
634 if( p ) // exact one reference at first
636 if( p->GetType() == svSingleRef )
637 eType = eType | Type::AbsPos;
638 else
639 eType = eType | Type::AbsArea;
644 extern "C"
645 int ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
647 return static_cast<int>(ScGlobal::GetCollator().compareString(
648 (*static_cast<const ScRangeData* const *>(p1))->GetName(),
649 (*static_cast<const ScRangeData* const *>(p2))->GetName() ));
652 namespace {
655 * Predicate to check if the name references the specified range.
657 class MatchByRange
659 const ScRange& mrRange;
660 public:
661 explicit MatchByRange(const ScRange& rRange) : mrRange(rRange) {}
662 bool operator() (std::pair<OUString const, std::unique_ptr<ScRangeData>> const& r) const
664 return r.second->IsRangeAtBlock(mrRange);
670 ScRangeName::ScRangeName()
671 : mHasPossibleAddressConflict(false)
672 , mHasPossibleAddressConflictDirty(false)
676 ScRangeName::ScRangeName(const ScRangeName& r)
677 : mHasPossibleAddressConflict( r.mHasPossibleAddressConflict )
678 , mHasPossibleAddressConflictDirty( r.mHasPossibleAddressConflictDirty )
680 for (auto const& it : r.m_Data)
682 m_Data.insert(std::make_pair(it.first, std::make_unique<ScRangeData>(*it.second)));
684 // std::map was cloned, so each collection needs its own index to data.
685 maIndexToData.resize( r.maIndexToData.size(), nullptr);
686 for (auto const& itr : m_Data)
688 size_t nPos = itr.second->GetIndex() - 1;
689 if (nPos >= maIndexToData.size())
691 OSL_FAIL( "ScRangeName copy-ctor: maIndexToData size doesn't fit");
692 maIndexToData.resize(nPos+1, nullptr);
694 maIndexToData[nPos] = itr.second.get();
698 const ScRangeData* ScRangeName::findByRange(const ScRange& rRange) const
700 DataType::const_iterator itr = std::find_if(
701 m_Data.begin(), m_Data.end(), MatchByRange(rRange));
702 return itr == m_Data.end() ? nullptr : itr->second.get();
705 ScRangeData* ScRangeName::findByUpperName(const OUString& rName)
707 DataType::iterator itr = m_Data.find(rName);
708 return itr == m_Data.end() ? nullptr : itr->second.get();
711 const ScRangeData* ScRangeName::findByUpperName(const OUString& rName) const
713 DataType::const_iterator itr = m_Data.find(rName);
714 return itr == m_Data.end() ? nullptr : itr->second.get();
717 ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const
719 if (!i)
720 // index should never be zero.
721 return nullptr;
723 size_t nPos = i - 1;
724 return nPos < maIndexToData.size() ? maIndexToData[nPos] : nullptr;
727 void ScRangeName::UpdateReference(sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
729 if (rCxt.meMode == URM_COPY)
730 // Copying cells does not modify named expressions.
731 return;
733 for (auto const& itr : m_Data)
735 itr.second->UpdateReference(rCxt, nLocalTab);
739 void ScRangeName::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
741 for (auto const& itr : m_Data)
743 itr.second->UpdateInsertTab(rCxt, nLocalTab);
747 void ScRangeName::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
749 for (auto const& itr : m_Data)
751 itr.second->UpdateDeleteTab(rCxt, nLocalTab);
755 void ScRangeName::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
757 for (auto const& itr : m_Data)
759 itr.second->UpdateMoveTab(rCxt, nLocalTab);
763 void ScRangeName::UpdateTranspose(const ScRange& rSource, const ScAddress& rDest)
765 for (auto const& itr : m_Data)
767 itr.second->UpdateTranspose(rSource, rDest);
771 void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY)
773 for (auto const& itr : m_Data)
775 itr.second->UpdateGrow(rArea, nGrowX, nGrowY);
779 void ScRangeName::CompileUnresolvedXML( sc::CompileFormulaContext& rCxt )
781 for (auto const& itr : m_Data)
783 itr.second->CompileUnresolvedXML(rCxt);
787 void ScRangeName::CopyUsedNames( const SCTAB nLocalTab, const SCTAB nOldTab, const SCTAB nNewTab,
788 const ScDocument& rOldDoc, ScDocument& rNewDoc, const bool bGlobalNamesToLocal ) const
790 for (auto const& itr : m_Data)
792 SCTAB nSheet = (nLocalTab < 0) ? nLocalTab : nOldTab;
793 sal_uInt16 nIndex = itr.second->GetIndex();
794 ScAddress aOldPos( itr.second->GetPos());
795 aOldPos.SetTab( nOldTab);
796 ScAddress aNewPos( aOldPos);
797 aNewPos.SetTab( nNewTab);
798 ScRangeData* pRangeData = nullptr;
799 rOldDoc.CopyAdjustRangeName( nSheet, nIndex, pRangeData, rNewDoc, aNewPos, aOldPos, bGlobalNamesToLocal, false);
803 bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex )
805 if (!p)
806 return false;
808 if (!p->GetIndex())
810 // Assign a new index. An index must be unique and is never 0.
811 if (bReuseFreeIndex)
813 IndexDataType::iterator itr = std::find(
814 maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(nullptr));
815 if (itr != maIndexToData.end())
817 // Empty slot exists. Re-use it.
818 size_t nPos = std::distance(maIndexToData.begin(), itr);
819 p->SetIndex(nPos + 1);
821 else
822 // No empty slot. Append it to the end.
823 p->SetIndex(maIndexToData.size() + 1);
825 else
827 p->SetIndex(maIndexToData.size() + 1);
831 OUString aName(p->GetUpperName());
832 erase(aName); // ptr_map won't insert it if a duplicate name exists.
833 pair<DataType::iterator, bool> r =
834 m_Data.insert(std::make_pair(aName, std::unique_ptr<ScRangeData>(p)));
835 if (r.second)
837 // Data inserted. Store its index for mapping.
838 size_t nPos = p->GetIndex() - 1;
839 if (nPos >= maIndexToData.size())
840 maIndexToData.resize(nPos+1, nullptr);
841 maIndexToData[nPos] = p;
842 mHasPossibleAddressConflictDirty = true;
844 return r.second;
847 void ScRangeName::erase(const ScRangeData& r)
849 erase(r.GetUpperName());
852 void ScRangeName::erase(const OUString& rName)
854 DataType::const_iterator itr = m_Data.find(rName);
855 if (itr != m_Data.end())
856 erase(itr);
859 void ScRangeName::erase(const_iterator itr)
861 sal_uInt16 nIndex = itr->second->GetIndex();
862 m_Data.erase(itr);
863 OSL_ENSURE( 0 < nIndex && nIndex <= maIndexToData.size(), "ScRangeName::erase: bad index");
864 if (0 < nIndex && nIndex <= maIndexToData.size())
865 maIndexToData[nIndex-1] = nullptr;
866 if(mHasPossibleAddressConflict)
867 mHasPossibleAddressConflictDirty = true;
870 void ScRangeName::clear()
872 m_Data.clear();
873 maIndexToData.clear();
874 mHasPossibleAddressConflict = false;
875 mHasPossibleAddressConflictDirty = false;
878 void ScRangeName::checkHasPossibleAddressConflict() const
880 mHasPossibleAddressConflict = false;
881 mHasPossibleAddressConflictDirty = false;
882 for (auto const& itr : m_Data)
884 if( itr.second->HasPossibleAddressConflict())
886 mHasPossibleAddressConflict = true;
887 return;
892 bool ScRangeName::operator== (const ScRangeName& r) const
894 return std::equal(m_Data.begin(), m_Data.end(), r.m_Data.begin(), r.m_Data.end(),
895 [](const DataType::value_type& lhs, const DataType::value_type& rhs) {
896 return (lhs.first == rhs.first) && (*lhs.second == *rhs.second);
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */