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