Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / tool / rangenam.cxx
blob6130c614a1385c3d2cbea18e9d7de41f69d6df75
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 <boost/scoped_ptr.hpp>
23 #include <unotools/collatorwrapper.hxx>
24 #include <unotools/transliterationwrapper.hxx>
25 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
27 #include "token.hxx"
28 #include "tokenarray.hxx"
29 #include "rangenam.hxx"
30 #include "global.hxx"
31 #include "compiler.hxx"
32 #include "rangeutl.hxx"
33 #include "rechead.hxx"
34 #include "refupdat.hxx"
35 #include "document.hxx"
36 #include "refupdatecontext.hxx"
38 #include "formula/errorcodes.hxx"
40 using namespace formula;
41 using ::std::pair;
42 using ::std::unary_function;
44 // ScRangeData
46 ScRangeData::ScRangeData( ScDocument* pDok,
47 const OUString& rName,
48 const OUString& rSymbol,
49 const ScAddress& rAddress,
50 RangeType nType,
51 const FormulaGrammar::Grammar eGrammar ) :
52 aName ( rName ),
53 aUpperName ( ScGlobal::pCharClass->uppercase( rName ) ),
54 pCode ( NULL ),
55 aPos ( rAddress ),
56 eType ( nType ),
57 pDoc ( pDok ),
58 eTempGrammar( eGrammar ),
59 nIndex ( 0 ),
60 bModified ( false ),
61 mnMaxRow (-1),
62 mnMaxCol (-1)
64 if (!rSymbol.isEmpty())
65 CompileRangeData( rSymbol, pDoc->IsImportingXML());
66 // Let the compiler set an error on unknown names for a subsequent
67 // CompileUnresolvedXML().
68 else
70 // #i63513#/#i65690# don't leave pCode as NULL.
71 // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too,
72 // to ensure same behavior if unnecessary copying is left out.
74 pCode = new ScTokenArray();
78 ScRangeData::ScRangeData( ScDocument* pDok,
79 const OUString& rName,
80 const ScTokenArray& rArr,
81 const ScAddress& rAddress,
82 RangeType nType ) :
83 aName ( rName ),
84 aUpperName ( ScGlobal::pCharClass->uppercase( rName ) ),
85 pCode ( new ScTokenArray( rArr ) ),
86 aPos ( rAddress ),
87 eType ( nType ),
88 pDoc ( pDok ),
89 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
90 nIndex ( 0 ),
91 bModified ( false ),
92 mnMaxRow (-1),
93 mnMaxCol (-1)
95 InitCode();
98 ScRangeData::ScRangeData( ScDocument* pDok,
99 const OUString& rName,
100 const ScAddress& rTarget ) :
101 aName ( rName ),
102 aUpperName ( ScGlobal::pCharClass->uppercase( rName ) ),
103 pCode ( new ScTokenArray() ),
104 aPos ( rTarget ),
105 eType ( RT_NAME ),
106 pDoc ( pDok ),
107 eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
108 nIndex ( 0 ),
109 bModified ( false ),
110 mnMaxRow (-1),
111 mnMaxCol (-1)
113 ScSingleRefData aRefData;
114 aRefData.InitAddress( rTarget );
115 aRefData.SetFlag3D( sal_True );
116 pCode->AddSingleReference( aRefData );
117 ScCompiler aComp( pDoc, aPos, *pCode );
118 aComp.SetGrammar(pDoc->GetGrammar());
119 aComp.CompileTokenArray();
120 if ( !pCode->GetCodeError() )
121 eType |= RT_ABSPOS;
124 ScRangeData::ScRangeData(const ScRangeData& rScRangeData, ScDocument* pDocument) :
125 aName (rScRangeData.aName),
126 aUpperName (rScRangeData.aUpperName),
127 pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()), // make real copy (not copy-ctor)
128 aPos (rScRangeData.aPos),
129 eType (rScRangeData.eType),
130 pDoc (pDocument ? pDocument : rScRangeData.pDoc),
131 eTempGrammar(rScRangeData.eTempGrammar),
132 nIndex (rScRangeData.nIndex),
133 bModified (rScRangeData.bModified),
134 mnMaxRow (rScRangeData.mnMaxRow),
135 mnMaxCol (rScRangeData.mnMaxCol)
138 ScRangeData::~ScRangeData()
140 delete pCode;
143 void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError )
145 if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
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;
153 ScCompiler aComp( pDoc, aPos );
154 aComp.SetGrammar( eTempGrammar);
155 if (bSetError)
156 aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_NO_BREAK);
157 ScTokenArray* pNewCode = aComp.CompileString( rSymbol );
158 SAL_WNODEPRECATED_DECLARATIONS_PUSH
159 ::std::auto_ptr<ScTokenArray> pOldCode( pCode); // old pCode will be deleted
160 SAL_WNODEPRECATED_DECLARATIONS_POP
161 pCode = pNewCode;
162 if( !pCode->GetCodeError() )
164 pCode->Reset();
165 FormulaToken* p = pCode->GetNextReference();
166 if( p )
168 // first token is a reference
169 /* FIXME: wouldn't that need a check if it's exactly one reference? */
170 if( p->GetType() == svSingleRef )
171 eType = eType | RT_ABSPOS;
172 else
173 eType = eType | RT_ABSAREA;
175 // For manual input set an error for an incomplete formula.
176 if (!pDoc->IsImportingXML())
178 aComp.CompileTokenArray();
179 pCode->DelRPN();
184 void ScRangeData::CompileUnresolvedXML()
186 if (pCode->GetCodeError() == errNoName)
188 // Reconstruct the symbol/formula and then recompile.
189 OUString aSymbol;
190 ScCompiler aComp( pDoc, aPos, *pCode);
191 aComp.SetGrammar( eTempGrammar);
192 aComp.CreateStringFromTokenArray( aSymbol);
193 // Don't let the compiler set an error for unknown names on final
194 // compile, errors are handled by the interpreter thereafter.
195 CompileRangeData( aSymbol, false);
199 #if DEBUG_FORMULA_COMPILER
200 void ScRangeData::Dump() const
202 cout << "-- ScRangeData" << endl;
203 cout << " name: " << aName << endl;
204 cout << " ref position: (col=" << aPos.Col() << ", row=" << aPos.Row() << ", sheet=" << aPos.Tab() << ")" << endl;
206 if (pCode)
207 pCode->Dump();
209 #endif
211 void ScRangeData::GuessPosition()
213 // set a position that allows "absoluting" of all relative references
214 // in CalcAbsIfRel without errors
216 OSL_ENSURE(aPos == ScAddress(), "position will go lost now");
218 SCsCOL nMinCol = 0;
219 SCsROW nMinRow = 0;
220 SCsTAB nMinTab = 0;
222 ScToken* t;
223 pCode->Reset();
224 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
226 ScSingleRefData& rRef1 = t->GetSingleRef();
227 if ( rRef1.IsColRel() && rRef1.Col() < nMinCol )
228 nMinCol = rRef1.Col();
229 if ( rRef1.IsRowRel() && rRef1.Row() < nMinRow )
230 nMinRow = rRef1.Row();
231 if ( rRef1.IsTabRel() && rRef1.Tab() < nMinTab )
232 nMinTab = rRef1.Tab();
234 if ( t->GetType() == svDoubleRef )
236 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
237 if ( rRef2.IsColRel() && rRef2.Col() < nMinCol )
238 nMinCol = rRef2.Col();
239 if ( rRef2.IsRowRel() && rRef2.Row() < nMinRow )
240 nMinRow = rRef2.Row();
241 if ( rRef2.IsTabRel() && rRef2.Tab() < nMinTab )
242 nMinTab = rRef2.Tab();
246 aPos = ScAddress( (SCCOL)(-nMinCol), (SCROW)(-nMinRow), (SCTAB)(-nMinTab) );
249 void ScRangeData::GetSymbol( OUString& rSymbol, const FormulaGrammar::Grammar eGrammar ) const
251 ScCompiler aComp(pDoc, aPos, *pCode);
252 aComp.SetGrammar(eGrammar);
253 aComp.CreateStringFromTokenArray( rSymbol );
256 void ScRangeData::GetSymbol( OUString& rSymbol, const ScAddress& rPos, const FormulaGrammar::Grammar eGrammar ) const
258 OUString aStr;
259 ScCompiler aComp(pDoc, rPos, *pCode);
260 aComp.SetGrammar(eGrammar);
261 aComp.CreateStringFromTokenArray( aStr );
262 rSymbol = aStr;
265 void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos,
266 const FormulaGrammar::Grammar eGrammar )
268 SAL_WNODEPRECATED_DECLARATIONS_PUSH
269 ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() );
270 SAL_WNODEPRECATED_DECLARATIONS_POP
271 ScCompiler aComp( pDoc, rPos, *pTemp.get());
272 aComp.SetGrammar(eGrammar);
273 aComp.MoveRelWrap(GetMaxCol(), GetMaxRow());
274 aComp.CreateStringFromTokenArray( rBuffer );
277 void ScRangeData::UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
279 sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt, aPos);
280 bModified = aRes.mbReferenceModified;
281 if (aRes.mbReferenceModified)
282 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
285 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
287 bool bChanged = false;
289 ScToken* t;
290 pCode->Reset();
292 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
294 if( t->GetType() != svIndex )
296 SingleDoubleRefModifier aMod( *t );
297 ScComplexRefData& rRef = aMod.Ref();
298 if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
299 (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
300 ( t->GetType() == svSingleRef ||
301 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
302 (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
304 ScRange aAbs = rRef.toAbs(aPos);
305 if (ScRefUpdate::UpdateTranspose(pDoc, rSource, rDest, aAbs) != UR_NOTHING)
307 rRef.SetRange(aAbs, aPos);
308 bChanged = true;
314 bModified = bChanged;
317 void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
319 bool bChanged = false;
321 ScToken* t;
322 pCode->Reset();
324 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
326 if( t->GetType() != svIndex )
328 SingleDoubleRefModifier aMod( *t );
329 ScComplexRefData& rRef = aMod.Ref();
330 if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() &&
331 (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) &&
332 ( t->GetType() == svSingleRef ||
333 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() &&
334 (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel()))))
336 ScRange aAbs = rRef.toAbs(aPos);
337 if (ScRefUpdate::UpdateGrow(rArea, nGrowX, nGrowY, aAbs) != UR_NOTHING)
339 rRef.SetRange(aAbs, aPos);
340 bChanged = true;
346 bModified = bChanged; // has to be evaluated immediately afterwards
349 bool ScRangeData::operator== (const ScRangeData& rData) const // for Undo
351 if ( nIndex != rData.nIndex ||
352 aName != rData.aName ||
353 aPos != rData.aPos ||
354 eType != rData.eType ) return false;
356 sal_uInt16 nLen = pCode->GetLen();
357 if ( nLen != rData.pCode->GetLen() ) return false;
359 FormulaToken** ppThis = pCode->GetArray();
360 FormulaToken** ppOther = rData.pCode->GetArray();
362 for ( sal_uInt16 i=0; i<nLen; i++ )
363 if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) )
364 return false;
366 return true;
369 bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const
371 bool bRet = false;
372 ScRange aRange;
373 if ( IsReference(aRange) )
374 bRet = ( rBlock == aRange );
375 return bRet;
378 bool ScRangeData::IsReference( ScRange& rRange ) const
380 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode )
381 return pCode->IsReference(rRange, aPos);
383 return false;
386 bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const
388 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
389 return pCode->IsReference(rRange, rPos);
391 return false;
394 bool ScRangeData::IsValidReference( ScRange& rRange ) const
396 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode )
397 return pCode->IsValidReference(rRange, aPos);
399 return false;
402 void ScRangeData::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
404 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnInsertedTab(rCxt, aPos);
405 if (aRes.mbReferenceModified)
406 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
408 if (rCxt.mnInsertPos <= aPos.Tab())
409 aPos.IncTab(rCxt.mnSheets);
412 void ScRangeData::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
414 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnDeletedTab(rCxt, aPos);
415 if (aRes.mbReferenceModified)
416 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
418 if (rCxt.mnDeletePos <= aPos.Tab())
419 aPos.IncTab(-rCxt.mnSheets);
422 void ScRangeData::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
424 sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMovedTab(rCxt, aPos);
425 if (aRes.mbReferenceModified)
426 rCxt.maUpdatedNames.setUpdatedName(nLocalTab, nIndex);
428 aPos.SetTab(rCxt.getNewTab(aPos.Tab()));
431 void ScRangeData::MakeValidName( OUString& rName )
434 // strip leading invalid characters
435 xub_StrLen nPos = 0;
436 sal_Int32 nLen = rName.getLength();
437 while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
438 ++nPos;
439 if ( nPos>0 )
440 rName = rName.copy(nPos);
442 // if the first character is an invalid start character, precede with '_'
443 if ( !rName.isEmpty() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) )
444 rName = "_" + rName;
446 // replace invalid with '_'
447 nLen = rName.getLength();
448 for (nPos=0; nPos<nLen; nPos++)
450 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) )
451 rName = rName.replaceAt( nPos, 1, "_" );
454 // Ensure that the proposed name is not a reference under any convention,
455 // same as in IsNameValid()
456 ScAddress aAddr;
457 ScRange aRange;
458 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
460 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
461 // Don't check Parse on VALID, any partial only VALID may result in
462 // #REF! during compile later!
463 while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details))
465 //! Range Parse is partially valid also with invalid sheet name,
466 //! Address Parse dito, during compile name would generate a #REF!
467 if ( rName.indexOf( '.' ) == -1 )
468 rName = rName.replaceFirst( ".", "_" );
469 else
470 rName = "_" + rName;
475 bool ScRangeData::IsNameValid( const OUString& rName, ScDocument* pDoc )
477 /* XXX If changed, sc/source/filter/ftools/ftools.cxx
478 * ScfTools::ConvertToScDefinedName needs to be changed too. */
479 sal_Char a('.');
480 if (rName.indexOf(a) != -1)
481 return false;
482 xub_StrLen nPos = 0;
483 sal_Int32 nLen = rName.getLength();
484 if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) )
485 return false;
486 while ( nPos < nLen )
488 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) )
489 return false;
491 ScAddress aAddr;
492 ScRange aRange;
493 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; )
495 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) );
496 // Don't check Parse on VALID, any partial only VALID may result in
497 // #REF! during compile later!
498 if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details))
499 return false;
501 return true;
504 SCROW ScRangeData::GetMaxRow() const
506 return mnMaxRow >= 0 ? mnMaxRow : MAXROW;
509 SCCOL ScRangeData::GetMaxCol() const
511 return mnMaxCol >= 0 ? mnMaxCol : MAXCOL;
514 sal_uInt16 ScRangeData::GetErrCode() const
516 return pCode ? pCode->GetCodeError() : 0;
519 bool ScRangeData::HasReferences() const
521 return pCode->HasReferences();
524 sal_uInt32 ScRangeData::GetUnoType() const
526 sal_uInt32 nUnoType = 0;
527 if ( HasType(RT_CRITERIA) ) nUnoType |= com::sun::star::sheet::NamedRangeFlag::FILTER_CRITERIA;
528 if ( HasType(RT_PRINTAREA) ) nUnoType |= com::sun::star::sheet::NamedRangeFlag::PRINT_AREA;
529 if ( HasType(RT_COLHEADER) ) nUnoType |= com::sun::star::sheet::NamedRangeFlag::COLUMN_HEADER;
530 if ( HasType(RT_ROWHEADER) ) nUnoType |= com::sun::star::sheet::NamedRangeFlag::ROW_HEADER;
531 return nUnoType;
534 void ScRangeData::ValidateTabRefs()
536 // try to make sure all relative references and the reference position
537 // are within existing tables, so they can be represented as text
538 // (if the range of used tables is more than the existing tables,
539 // the result may still contain invalid tables, because the relative
540 // references aren't changed so formulas stay the same)
542 // find range of used tables
544 SCTAB nMinTab = aPos.Tab();
545 SCTAB nMaxTab = nMinTab;
546 ScToken* t;
547 pCode->Reset();
548 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
550 ScSingleRefData& rRef1 = t->GetSingleRef();
551 ScAddress aAbs = rRef1.toAbs(aPos);
552 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
554 if (aAbs.Tab() < nMinTab)
555 nMinTab = aAbs.Tab();
556 if (aAbs.Tab() > nMaxTab)
557 nMaxTab = aAbs.Tab();
559 if ( t->GetType() == svDoubleRef )
561 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
562 aAbs = rRef2.toAbs(aPos);
563 if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
565 if (aAbs.Tab() < nMinTab)
566 nMinTab = aAbs.Tab();
567 if (aAbs.Tab() > nMaxTab)
568 nMaxTab = aAbs.Tab();
573 SCTAB nTabCount = pDoc->GetTableCount();
574 if ( nMaxTab >= nTabCount && nMinTab > 0 )
576 // move position and relative tab refs
577 // The formulas that use the name are not changed by this
579 SCTAB nMove = nMinTab;
580 ScAddress aOldPos = aPos;
581 aPos.SetTab( aPos.Tab() - nMove );
583 pCode->Reset();
584 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
586 switch (t->GetType())
588 case svSingleRef:
590 ScSingleRefData& rRef = t->GetSingleRef();
591 if (!rRef.IsTabDeleted())
593 ScAddress aAbs = rRef.toAbs(aOldPos);
594 rRef.SetAddress(aAbs, aPos);
597 break;
598 case svDoubleRef:
600 ScComplexRefData& rRef = t->GetDoubleRef();
601 if (!rRef.Ref1.IsTabDeleted())
603 ScAddress aAbs = rRef.Ref1.toAbs(aOldPos);
604 rRef.Ref1.SetAddress(aAbs, aPos);
606 if (!rRef.Ref2.IsTabDeleted())
608 ScAddress aAbs = rRef.Ref2.toAbs(aOldPos);
609 rRef.Ref2.SetAddress(aAbs, aPos);
612 break;
613 default:
620 void ScRangeData::SetCode( ScTokenArray& rArr )
622 boost::scoped_ptr<ScTokenArray> pOldCode( pCode); // old pCode will be deleted
623 pCode = new ScTokenArray( rArr );
624 InitCode();
627 void ScRangeData::InitCode()
629 if( !pCode->GetCodeError() )
631 pCode->Reset();
632 FormulaToken* p = pCode->GetNextReference();
633 if( p ) // exact one reference at first
635 if( p->GetType() == svSingleRef )
636 eType = eType | RT_ABSPOS;
637 else
638 eType = eType | RT_ABSAREA;
643 extern "C"
644 int SAL_CALL ScRangeData_QsortNameCompare( const void* p1, const void* p2 )
646 return (int) ScGlobal::GetCollator()->compareString(
647 (*(const ScRangeData**)p1)->GetName(),
648 (*(const ScRangeData**)p2)->GetName() );
651 bool operator<(const ScRangeData& left, const ScRangeData& right)
653 return left.GetName() < right.GetName();
656 namespace {
659 * Predicate to check if the name references the specified range.
661 class MatchByRange : public unary_function<ScRangeData, bool>
663 const ScRange& mrRange;
664 public:
665 MatchByRange(const ScRange& rRange) : mrRange(rRange) {}
666 template < typename Pair >
667 bool operator() ( Pair const& r) const
669 return r.second->IsRangeAtBlock(mrRange);
675 ScRangeName::ScRangeName() {}
677 ScRangeName::ScRangeName(const ScRangeName& r) :
678 maData(r.maData)
680 // boost::ptr_set clones and deletes, so each collection needs its own
681 // index to data.
682 maIndexToData.resize( r.maIndexToData.size(), NULL);
683 DataType::const_iterator itr = maData.begin(), itrEnd = maData.end();
684 for (; itr != itrEnd; ++itr)
686 size_t nPos = itr->second->GetIndex() - 1;
687 if (nPos >= maIndexToData.size())
689 OSL_FAIL( "ScRangeName copy-ctor: maIndexToData size doesn't fit");
690 maIndexToData.resize(nPos+1, NULL);
692 maIndexToData[nPos] = const_cast<ScRangeData*>(itr->second);
696 const ScRangeData* ScRangeName::findByRange(const ScRange& rRange) const
698 DataType::const_iterator itr = std::find_if(
699 maData.begin(), maData.end(), MatchByRange(rRange));
700 return itr == maData.end() ? NULL : itr->second;
703 ScRangeData* ScRangeName::findByUpperName(const OUString& rName)
705 DataType::iterator itr = maData.find(rName);
706 return itr == maData.end() ? NULL : itr->second;
709 const ScRangeData* ScRangeName::findByUpperName(const OUString& rName) const
711 DataType::const_iterator itr = maData.find(rName);
712 return itr == maData.end() ? NULL : itr->second;
715 ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const
717 if (!i)
718 // index should never be zero.
719 return NULL;
721 size_t nPos = i - 1;
722 return nPos < maIndexToData.size() ? maIndexToData[nPos] : NULL;
725 void ScRangeName::UpdateReference(sc::RefUpdateContext& rCxt, SCTAB nLocalTab )
727 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
728 for (; itr != itrEnd; ++itr)
729 itr->second->UpdateReference(rCxt, nLocalTab);
732 void ScRangeName::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt, SCTAB nLocalTab )
734 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
735 for (; itr != itrEnd; ++itr)
736 itr->second->UpdateInsertTab(rCxt, nLocalTab);
739 void ScRangeName::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt, SCTAB nLocalTab )
741 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
742 for (; itr != itrEnd; ++itr)
743 itr->second->UpdateDeleteTab(rCxt, nLocalTab);
746 void ScRangeName::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nLocalTab )
748 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
749 for (; itr != itrEnd; ++itr)
750 itr->second->UpdateMoveTab(rCxt, nLocalTab);
753 void ScRangeName::UpdateTranspose(const ScRange& rSource, const ScAddress& rDest)
755 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
756 for (; itr != itrEnd; ++itr)
757 itr->second->UpdateTranspose(rSource, rDest);
760 void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY)
762 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
763 for (; itr != itrEnd; ++itr)
764 itr->second->UpdateGrow(rArea, nGrowX, nGrowY);
767 void ScRangeName::CompileUnresolvedXML()
769 DataType::iterator itr = maData.begin(), itrEnd = maData.end();
770 for (; itr != itrEnd; ++itr)
771 itr->second->CompileUnresolvedXML();
774 ScRangeName::const_iterator ScRangeName::begin() const
776 return maData.begin();
779 ScRangeName::const_iterator ScRangeName::end() const
781 return maData.end();
784 ScRangeName::iterator ScRangeName::begin()
786 return maData.begin();
789 ScRangeName::iterator ScRangeName::end()
791 return maData.end();
794 size_t ScRangeName::size() const
796 return maData.size();
799 bool ScRangeName::empty() const
801 return maData.empty();
804 bool ScRangeName::insert(ScRangeData* p)
806 if (!p)
807 return false;
809 if (!p->GetIndex())
811 // Assign a new index. An index must be unique and is never 0.
812 IndexDataType::iterator itr = std::find(
813 maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(NULL));
814 if (itr != maIndexToData.end())
816 // Empty slot exists. Re-use it.
817 size_t nPos = std::distance(maIndexToData.begin(), itr);
818 p->SetIndex(nPos + 1);
820 else
821 // No empty slot. Append it to the end.
822 p->SetIndex(maIndexToData.size() + 1);
825 OUString aName(p->GetUpperName());
826 erase(aName); // ptr_map won't insert it if a duplicate name exists.
827 pair<DataType::iterator, bool> r = maData.insert(aName, p);
828 if (r.second)
830 // Data inserted. Store its index for mapping.
831 size_t nPos = p->GetIndex() - 1;
832 if (nPos >= maIndexToData.size())
833 maIndexToData.resize(nPos+1, NULL);
834 maIndexToData[nPos] = p;
836 return r.second;
839 void ScRangeName::erase(const ScRangeData& r)
841 erase(r.GetUpperName());
844 void ScRangeName::erase(const OUString& rName)
846 DataType::iterator itr = maData.find(rName);
847 if (itr != maData.end())
848 erase(itr);
851 void ScRangeName::erase(const iterator& itr)
853 sal_uInt16 nIndex = itr->second->GetIndex();
854 maData.erase(itr);
855 OSL_ENSURE( 0 < nIndex && nIndex <= maIndexToData.size(), "ScRangeName::erase: bad index");
856 if (0 < nIndex && nIndex <= maIndexToData.size())
857 maIndexToData[nIndex-1] = NULL;
860 void ScRangeName::clear()
862 maData.clear();
863 maIndexToData.clear();
866 bool ScRangeName::operator== (const ScRangeName& r) const
868 return maData == r.maData;
871 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */