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