1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <unotools/collatorwrapper.hxx>
23 #include <unotools/charclass.hxx>
24 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
25 #include <osl/diagnose.h>
28 #include <tokenarray.hxx>
29 #include <rangenam.hxx>
30 #include <rangeutl.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
;
45 ScRangeData::ScRangeData( ScDocument
& rDok
,
46 const OUString
& rName
,
47 const OUString
& rSymbol
,
48 const ScAddress
& rAddress
,
50 const FormulaGrammar::Grammar eGrammar
) :
52 aUpperName ( ScGlobal::getCharClass().uppercase( rName
) ),
56 eTempGrammar( eGrammar
),
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
);
67 rDoc
.CheckLinkFormulaNeedingCheck( *pCode
);
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
,
86 aUpperName ( ScGlobal::getCharClass().uppercase( rName
) ),
87 pCode ( new ScTokenArray( rArr
) ),
91 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED
),
95 pCode
->SetFromRangeName(true);
99 ScRangeData::ScRangeData( ScDocument
& rDok
,
100 const OUString
& rName
,
101 const ScAddress
& rTarget
) :
103 aUpperName ( ScGlobal::getCharClass().uppercase( rName
) ),
104 pCode ( new ScTokenArray(rDok
) ),
106 eType ( Type::Name
),
108 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED
),
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
);
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
)
159 FormulaTokenArrayPlainIterator
aIter(*pCode
);
160 FormulaToken
* p
= aIter
.GetNextReference();
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
;
168 eType
= eType
| Type::AbsArea
;
170 // For manual input set an error for an incomplete formula.
171 if (!rDoc
.IsImportingXML())
173 aComp
.CompileTokenArray();
178 void ScRangeData::CompileUnresolvedXML( sc::CompileFormulaContext
& rCxt
)
180 if (pCode
->GetCodeError() == FormulaError::NoName
)
182 // Reconstruct the symbol/formula and then recompile.
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
;
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");
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
);
248 aComp
.CreateStringFromTokenArray( symbol
);
252 OUString
ScRangeData::GetSymbol( const ScAddress
& rPos
, const FormulaGrammar::Grammar eGrammar
) const
255 ScCompiler
aComp(rDoc
, rPos
, *pCode
, eGrammar
);
256 aComp
.CreateStringFromTokenArray( 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
);
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
);
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
);
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
]) )
362 bool ScRangeData::IsRangeAtBlock( const ScRange
& rBlock
) const
366 if ( IsReference(aRange
) )
367 bRet
= ( rBlock
== aRange
);
371 bool ScRangeData::IsReference( ScRange
& rRange
) const
373 if ( (eType
& ( Type::AbsArea
| Type::RefArea
| Type::AbsPos
)) && pCode
)
374 return pCode
->IsReference(rRange
, aPos
);
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
);
387 bool ScRangeData::IsValidReference( ScRange
& rRange
) const
389 if ( (eType
& ( Type::AbsArea
| Type::RefArea
| Type::AbsPos
) ) && pCode
)
390 return pCode
->IsValidReference(rRange
, aPos
);
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
428 sal_Int32 nLen
= rName
.getLength();
429 while ( nPos
< nLen
&& !ScCompiler::IsCharFlagAllConventions( rName
, nPos
, ScCharFlags::Name
) )
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
) )
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()
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( ".", "_" );
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. */
473 if (rName
.indexOf(a
) != -1)
474 return IsNameValidType::NAME_INVALID_BAD_STRING
;
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
;
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.
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
)
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
;
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 )
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
);
587 while ( ( t
= aIter
.GetNextReference() ) != nullptr )
589 switch (t
->GetType())
593 ScSingleRefData
& rRef
= *t
->GetSingleRef();
594 if (!rRef
.IsTabDeleted())
596 ScAddress aAbs
= rRef
.toAbs(rDoc
, aOldPos
);
597 rRef
.SetAddress(rDoc
.GetSheetLimits(), aAbs
, aPos
);
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
);
622 void ScRangeData::SetCode( const ScTokenArray
& rArr
)
624 pCode
.reset(new ScTokenArray( rArr
));
625 pCode
->SetFromRangeName(true);
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
;
639 eType
= eType
| Type::AbsArea
;
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() ));
655 * Predicate to check if the name references the specified range.
659 const ScRange
& mrRange
;
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
720 // index should never be zero.
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.
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
)
810 // Assign a new index. An index must be unique and is never 0.
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);
822 // No empty slot. Append it to the end.
823 p
->SetIndex(maIndexToData
.size() + 1);
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
)));
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;
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())
859 void ScRangeName::erase(const_iterator itr
)
861 sal_uInt16 nIndex
= itr
->second
->GetIndex();
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()
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;
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: */