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