1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 //------------------------------------------------------------------------ 33 34 #include <tools/debug.hxx> 35 #include <string.h> 36 #include <memory> 37 #include <unotools/collatorwrapper.hxx> 38 #include <unotools/transliterationwrapper.hxx> 39 40 #include "token.hxx" 41 #include "tokenarray.hxx" 42 #include "rangenam.hxx" 43 #include "global.hxx" 44 #include "compiler.hxx" 45 #include "rangeutl.hxx" 46 #include "rechead.hxx" 47 #include "refupdat.hxx" 48 #include "document.hxx" 49 50 using namespace formula; 51 52 //======================================================================== 53 // ScRangeData 54 //======================================================================== 55 56 // Interner ctor fuer das Suchen nach einem Index 57 58 ScRangeData::ScRangeData( sal_uInt16 n ) 59 : pCode( NULL ), nIndex( n ), bModified( sal_False ), mnMaxRow(-1), mnMaxCol(-1) 60 {} 61 62 ScRangeData::ScRangeData( ScDocument* pDok, 63 const String& rName, 64 const String& rSymbol, 65 const ScAddress& rAddress, 66 RangeType nType, 67 const FormulaGrammar::Grammar eGrammar ) : 68 aName ( rName ), 69 aUpperName ( ScGlobal::pCharClass->upper( rName ) ), 70 pCode ( NULL ), 71 aPos ( rAddress ), 72 eType ( nType ), 73 pDoc ( pDok ), 74 nIndex ( 0 ), 75 bModified ( sal_False ), 76 mnMaxRow (-1), 77 mnMaxCol (-1) 78 { 79 if (rSymbol.Len() > 0) 80 { 81 ScCompiler aComp( pDoc, aPos ); 82 aComp.SetGrammar(eGrammar); 83 pCode = aComp.CompileString( rSymbol ); 84 if( !pCode->GetCodeError() ) 85 { 86 pCode->Reset(); 87 FormulaToken* p = pCode->GetNextReference(); 88 if( p )// genau eine Referenz als erstes 89 { 90 if( p->GetType() == svSingleRef ) 91 eType = eType | RT_ABSPOS; 92 else 93 eType = eType | RT_ABSAREA; 94 } 95 // ggf. den Fehlercode wg. unvollstaendiger Formel setzen! 96 // Dies ist fuer die manuelle Eingabe 97 aComp.CompileTokenArray(); 98 pCode->DelRPN(); 99 } 100 } 101 else 102 { 103 // #i63513#/#i65690# don't leave pCode as NULL. 104 // Copy ctor default-constructs pCode if it was NULL, so it's initialized here, too, 105 // to ensure same behavior if unnecessary copying is left out. 106 107 pCode = new ScTokenArray(); 108 } 109 } 110 111 ScRangeData::ScRangeData( ScDocument* pDok, 112 const String& rName, 113 const ScTokenArray& rArr, 114 const ScAddress& rAddress, 115 RangeType nType ) : 116 aName ( rName ), 117 aUpperName ( ScGlobal::pCharClass->upper( rName ) ), 118 pCode ( new ScTokenArray( rArr ) ), 119 aPos ( rAddress ), 120 eType ( nType ), 121 pDoc ( pDok ), 122 nIndex ( 0 ), 123 bModified ( sal_False ), 124 mnMaxRow (-1), 125 mnMaxCol (-1) 126 { 127 if( !pCode->GetCodeError() ) 128 { 129 pCode->Reset(); 130 FormulaToken* p = pCode->GetNextReference(); 131 if( p )// genau eine Referenz als erstes 132 { 133 if( p->GetType() == svSingleRef ) 134 eType = eType | RT_ABSPOS; 135 else 136 eType = eType | RT_ABSAREA; 137 } 138 // Die Importfilter haben diesen Test nicht, 139 // da die benannten Bereiche z.T. noch unvollstaendig sind. 140 // if( !pCode->GetCodeLen() ) 141 // { 142 // // ggf. den Fehlercode wg. unvollstaendiger Formel setzen! 143 // ScCompiler aComp( pDok, aPos, *pCode ); 144 // aComp.CompileTokenArray(); 145 // pCode->DelRPN(); 146 // } 147 } 148 } 149 150 ScRangeData::ScRangeData( ScDocument* pDok, 151 const String& rName, 152 const ScAddress& rTarget ) : 153 aName ( rName ), 154 aUpperName ( ScGlobal::pCharClass->upper( rName ) ), 155 pCode ( new ScTokenArray() ), 156 aPos ( rTarget ), 157 eType ( RT_NAME ), 158 pDoc ( pDok ), 159 nIndex ( 0 ), 160 bModified ( sal_False ), 161 mnMaxRow (-1), 162 mnMaxCol (-1) 163 { 164 ScSingleRefData aRefData; 165 aRefData.InitAddress( rTarget ); 166 aRefData.SetFlag3D( sal_True ); 167 pCode->AddSingleReference( aRefData ); 168 ScCompiler aComp( pDoc, aPos, *pCode ); 169 aComp.SetGrammar(pDoc->GetGrammar()); 170 aComp.CompileTokenArray(); 171 if ( !pCode->GetCodeError() ) 172 eType |= RT_ABSPOS; 173 } 174 175 ScRangeData::ScRangeData(const ScRangeData& rScRangeData) : 176 ScDataObject(), 177 aName (rScRangeData.aName), 178 aUpperName (rScRangeData.aUpperName), 179 pCode (rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()), // echte Kopie erzeugen (nicht copy-ctor) 180 aPos (rScRangeData.aPos), 181 eType (rScRangeData.eType), 182 pDoc (rScRangeData.pDoc), 183 nIndex (rScRangeData.nIndex), 184 bModified (rScRangeData.bModified), 185 mnMaxRow (rScRangeData.mnMaxRow), 186 mnMaxCol (rScRangeData.mnMaxCol) 187 {} 188 189 ScRangeData::~ScRangeData() 190 { 191 delete pCode; 192 } 193 194 ScDataObject* ScRangeData::Clone() const 195 { 196 return new ScRangeData(*this); 197 } 198 199 void ScRangeData::GuessPosition() 200 { 201 // setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel 202 // ohne Fehler verabsolutiert werden koennen 203 204 DBG_ASSERT(aPos == ScAddress(), "die Position geht jetzt verloren"); 205 206 SCsCOL nMinCol = 0; 207 SCsROW nMinRow = 0; 208 SCsTAB nMinTab = 0; 209 210 ScToken* t; 211 pCode->Reset(); 212 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 213 { 214 ScSingleRefData& rRef1 = t->GetSingleRef(); 215 if ( rRef1.IsColRel() && rRef1.nRelCol < nMinCol ) 216 nMinCol = rRef1.nRelCol; 217 if ( rRef1.IsRowRel() && rRef1.nRelRow < nMinRow ) 218 nMinRow = rRef1.nRelRow; 219 if ( rRef1.IsTabRel() && rRef1.nRelTab < nMinTab ) 220 nMinTab = rRef1.nRelTab; 221 222 if ( t->GetType() == svDoubleRef ) 223 { 224 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 225 if ( rRef2.IsColRel() && rRef2.nRelCol < nMinCol ) 226 nMinCol = rRef2.nRelCol; 227 if ( rRef2.IsRowRel() && rRef2.nRelRow < nMinRow ) 228 nMinRow = rRef2.nRelRow; 229 if ( rRef2.IsTabRel() && rRef2.nRelTab < nMinTab ) 230 nMinTab = rRef2.nRelTab; 231 } 232 } 233 234 aPos = ScAddress( (SCCOL)(-nMinCol), (SCROW)(-nMinRow), (SCTAB)(-nMinTab) ); 235 236 //! Test 237 // DBG_ERROR(String("Pos ")+String((SCCOL)(-nMinCol))+String("/")+ 238 // String((SCROW)(-nMinRow))+String("/")+String((SCTAB)(-nMinTab))); 239 } 240 241 void ScRangeData::GetSymbol( String& rSymbol, const FormulaGrammar::Grammar eGrammar ) const 242 { 243 ScCompiler aComp(pDoc, aPos, *pCode); 244 aComp.SetGrammar(eGrammar); 245 aComp.CreateStringFromTokenArray( rSymbol ); 246 } 247 248 void ScRangeData::UpdateSymbol( rtl::OUStringBuffer& rBuffer, const ScAddress& rPos, 249 const FormulaGrammar::Grammar eGrammar ) 250 { 251 ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() ); 252 ScCompiler aComp( pDoc, rPos, *pTemp.get()); 253 aComp.SetGrammar(eGrammar); 254 aComp.MoveRelWrap(GetMaxCol(), GetMaxRow()); 255 aComp.CreateStringFromTokenArray( rBuffer ); 256 } 257 258 void ScRangeData::UpdateReference( UpdateRefMode eUpdateRefMode, 259 const ScRange& r, 260 SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 261 { 262 sal_Bool bChanged = sal_False; 263 264 pCode->Reset(); 265 if( pCode->GetNextReference() ) 266 { 267 sal_Bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED); 268 ScCompiler aComp( pDoc, aPos, *pCode ); 269 aComp.SetGrammar(pDoc->GetGrammar()); 270 const sal_Bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r, 271 nDx, nDy, nDz, 272 bChanged, bSharedFormula); 273 if (bSharedFormula) 274 { 275 if (bRelRef) 276 eType = eType | RT_SHAREDMOD; 277 else 278 eType = eType & ~RT_SHAREDMOD; 279 } 280 } 281 282 bModified = bChanged; 283 } 284 285 286 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest ) 287 { 288 sal_Bool bChanged = sal_False; 289 290 ScToken* t; 291 pCode->Reset(); 292 293 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 294 { 295 if( t->GetType() != svIndex ) 296 { 297 SingleDoubleRefModifier aMod( *t ); 298 ScComplexRefData& rRef = aMod.Ref(); 299 if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() && 300 (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) && 301 ( t->GetType() == svSingleRef || 302 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() && 303 (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel())))) 304 { 305 if ( ScRefUpdate::UpdateTranspose( pDoc, rSource, rDest, rRef ) != UR_NOTHING ) 306 bChanged = sal_True; 307 } 308 } 309 } 310 311 bModified = bChanged; 312 } 313 314 void ScRangeData::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) 315 { 316 sal_Bool bChanged = sal_False; 317 318 ScToken* t; 319 pCode->Reset(); 320 321 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 322 { 323 if( t->GetType() != svIndex ) 324 { 325 SingleDoubleRefModifier aMod( *t ); 326 ScComplexRefData& rRef = aMod.Ref(); 327 if (!rRef.Ref1.IsColRel() && !rRef.Ref1.IsRowRel() && 328 (!rRef.Ref1.IsFlag3D() || !rRef.Ref1.IsTabRel()) && 329 ( t->GetType() == svSingleRef || 330 (!rRef.Ref2.IsColRel() && !rRef.Ref2.IsRowRel() && 331 (!rRef.Ref2.IsFlag3D() || !rRef.Ref2.IsTabRel())))) 332 { 333 if ( ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, rRef ) != UR_NOTHING ) 334 bChanged = sal_True; 335 } 336 } 337 } 338 339 bModified = bChanged; // muss direkt hinterher ausgewertet werden 340 } 341 342 sal_Bool ScRangeData::operator== (const ScRangeData& rData) const // fuer Undo 343 { 344 if ( nIndex != rData.nIndex || 345 aName != rData.aName || 346 aPos != rData.aPos || 347 eType != rData.eType ) return sal_False; 348 349 sal_uInt16 nLen = pCode->GetLen(); 350 if ( nLen != rData.pCode->GetLen() ) return sal_False; 351 352 FormulaToken** ppThis = pCode->GetArray(); 353 FormulaToken** ppOther = rData.pCode->GetArray(); 354 355 for ( sal_uInt16 i=0; i<nLen; i++ ) 356 if ( ppThis[i] != ppOther[i] && !(*ppThis[i] == *ppOther[i]) ) 357 return sal_False; 358 359 return sal_True; 360 } 361 362 //UNUSED2009-05 sal_Bool ScRangeData::IsRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const 363 //UNUSED2009-05 { 364 //UNUSED2009-05 sal_Bool bRet = sal_False; 365 //UNUSED2009-05 ScRange aRange; 366 //UNUSED2009-05 if ( IsReference(aRange) ) 367 //UNUSED2009-05 { 368 //UNUSED2009-05 if ( bStartOnly ) 369 //UNUSED2009-05 bRet = ( rPos == aRange.aStart ); 370 //UNUSED2009-05 else 371 //UNUSED2009-05 bRet = ( aRange.In( rPos ) ); 372 //UNUSED2009-05 } 373 //UNUSED2009-05 return bRet; 374 //UNUSED2009-05 } 375 376 sal_Bool ScRangeData::IsRangeAtBlock( const ScRange& rBlock ) const 377 { 378 sal_Bool bRet = sal_False; 379 ScRange aRange; 380 if ( IsReference(aRange) ) 381 bRet = ( rBlock == aRange ); 382 return bRet; 383 } 384 385 sal_Bool ScRangeData::IsReference( ScRange& rRange ) const 386 { 387 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS )) && pCode ) 388 return pCode->IsReference( rRange ); 389 390 return sal_False; 391 } 392 393 sal_Bool ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const 394 { 395 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode ) 396 { 397 ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() ); 398 ScCompiler aComp( pDoc, rPos, *pTemp); 399 aComp.SetGrammar(pDoc->GetGrammar()); 400 aComp.MoveRelWrap(MAXCOL, MAXROW); 401 return pTemp->IsReference( rRange ); 402 } 403 404 return sal_False; 405 } 406 407 sal_Bool ScRangeData::IsValidReference( ScRange& rRange ) const 408 { 409 if ( (eType & ( RT_ABSAREA | RT_REFAREA | RT_ABSPOS ) ) && pCode ) 410 return pCode->IsValidReference( rRange ); 411 412 return sal_False; 413 } 414 415 void ScRangeData::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable) 416 { 417 pCode->Reset(); 418 if( pCode->GetNextReference() ) 419 { 420 ScRangeData* pRangeData = NULL; // must not be dereferenced 421 sal_Bool bChanged; 422 ScCompiler aComp( pDoc, aPos, *pCode); 423 aComp.SetGrammar(pDoc->GetGrammar()); 424 switch (nFlag) 425 { 426 case 1: // einfache InsertTab (doc.cxx) 427 pRangeData = aComp.UpdateInsertTab(nOldTable, sal_True ); // und CopyTab (doc2.cxx) 428 break; 429 case 2: // einfaches delete (doc.cxx) 430 pRangeData = aComp.UpdateDeleteTab(nOldTable, sal_False, sal_True, bChanged); 431 break; 432 case 3: // move (doc2.cxx) 433 { 434 pRangeData = aComp.UpdateMoveTab(nOldTable, nNewTable, sal_True ); 435 } 436 break; 437 default: 438 { 439 DBG_ERROR("ScRangeName::UpdateTabRef: Unknown Flag"); 440 } 441 break; 442 } 443 if (eType&RT_SHARED) 444 { 445 if (pRangeData) 446 eType = eType | RT_SHAREDMOD; 447 else 448 eType = eType & ~RT_SHAREDMOD; 449 } 450 } 451 } 452 453 454 void ScRangeData::MakeValidName( String& rName ) // static 455 { 456 //ScCompiler::InitSymbolsNative(); 457 458 // strip leading invalid characters 459 xub_StrLen nPos = 0; 460 xub_StrLen nLen = rName.Len(); 461 while ( nPos < nLen && !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) ) 462 ++nPos; 463 if ( nPos>0 ) 464 rName.Erase(0,nPos); 465 466 // if the first character is an invalid start character, precede with '_' 467 if ( rName.Len() && !ScCompiler::IsCharFlagAllConventions( rName, 0, SC_COMPILER_C_CHAR_NAME ) ) 468 rName.Insert('_',0); 469 470 // replace invalid with '_' 471 nLen = rName.Len(); 472 for (nPos=0; nPos<nLen; nPos++) 473 { 474 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos, SC_COMPILER_C_NAME) ) 475 rName.SetChar( nPos, '_' ); 476 } 477 478 // Ensure that the proposed name is not a reference under any convention, 479 // same as in IsNameValid() 480 ScAddress aAddr; 481 ScRange aRange; 482 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) 483 { 484 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); 485 // Don't check Parse on VALID, any partial only VALID may result in 486 // #REF! during compile later! 487 while (aRange.Parse( rName, NULL, details) || aAddr.Parse( rName, NULL, details)) 488 { 489 //! Range Parse is partially valid also with invalid sheet name, 490 //! Address Parse dito, during compile name would generate a #REF! 491 if ( rName.SearchAndReplace( '.', '_' ) == STRING_NOTFOUND ) 492 rName.Insert('_',0); 493 } 494 } 495 } 496 497 sal_Bool ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc ) 498 { 499 /* XXX If changed, sc/source/filter/ftools/ftools.cxx 500 * ScfTools::ConvertToScDefinedName needs to be changed too. */ 501 xub_StrLen nPos = 0; 502 xub_StrLen nLen = rName.Len(); 503 if ( !nLen || !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_CHAR_NAME ) ) 504 return sal_False; 505 while ( nPos < nLen ) 506 { 507 if ( !ScCompiler::IsCharFlagAllConventions( rName, nPos++, SC_COMPILER_C_NAME ) ) 508 return sal_False; 509 } 510 ScAddress aAddr; 511 ScRange aRange; 512 for (int nConv = FormulaGrammar::CONV_UNSPECIFIED; ++nConv < FormulaGrammar::CONV_LAST; ) 513 { 514 ScAddress::Details details( static_cast<FormulaGrammar::AddressConvention>( nConv ) ); 515 // Don't check Parse on VALID, any partial only VALID may result in 516 // #REF! during compile later! 517 if (aRange.Parse( rName, pDoc, details) || aAddr.Parse( rName, pDoc, details)) 518 return sal_False; 519 } 520 return sal_True; 521 } 522 523 void ScRangeData::SetMaxRow(SCROW nRow) 524 { 525 mnMaxRow = nRow; 526 } 527 528 SCROW ScRangeData::GetMaxRow() const 529 { 530 return mnMaxRow >= 0 ? mnMaxRow : MAXROW; 531 } 532 533 void ScRangeData::SetMaxCol(SCCOL nCol) 534 { 535 mnMaxCol = nCol; 536 } 537 538 SCCOL ScRangeData::GetMaxCol() const 539 { 540 return mnMaxCol >= 0 ? mnMaxCol : MAXCOL; 541 } 542 543 544 sal_uInt16 ScRangeData::GetErrCode() 545 { 546 return pCode ? pCode->GetCodeError() : 0; 547 } 548 549 sal_Bool ScRangeData::HasReferences() const 550 { 551 pCode->Reset(); 552 return sal_Bool( pCode->GetNextReference() != NULL ); 553 } 554 555 // bei TransferTab von einem in ein anderes Dokument anpassen, 556 // um Referenzen auf die eigene Tabelle mitzubekommen 557 558 void ScRangeData::TransferTabRef( SCTAB nOldTab, SCTAB nNewTab ) 559 { 560 long nTabDiff = (long)nNewTab - nOldTab; 561 long nPosDiff = (long)nNewTab - aPos.Tab(); 562 aPos.SetTab( nNewTab ); 563 ScToken* t; 564 pCode->Reset(); 565 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 566 { 567 ScSingleRefData& rRef1 = t->GetSingleRef(); 568 if ( rRef1.IsTabRel() ) 569 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nPosDiff ); 570 else 571 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab + nTabDiff ); 572 if ( t->GetType() == svDoubleRef ) 573 { 574 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 575 if ( rRef2.IsTabRel() ) 576 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nPosDiff ); 577 else 578 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab + nTabDiff ); 579 } 580 } 581 } 582 583 void ScRangeData::ReplaceRangeNamesInUse( const IndexMap& rMap ) 584 { 585 bool bCompile = false; 586 for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() ) 587 { 588 if ( p->GetOpCode() == ocName ) 589 { 590 const sal_uInt16 nOldIndex = p->GetIndex(); 591 IndexMap::const_iterator itr = rMap.find(nOldIndex); 592 const sal_uInt16 nNewIndex = itr == rMap.end() ? nOldIndex : itr->second; 593 if ( nOldIndex != nNewIndex ) 594 { 595 p->SetIndex( nNewIndex ); 596 bCompile = true; 597 } 598 } 599 } 600 if ( bCompile ) 601 { 602 ScCompiler aComp( pDoc, aPos, *pCode); 603 aComp.SetGrammar(pDoc->GetGrammar()); 604 aComp.CompileTokenArray(); 605 } 606 } 607 608 609 void ScRangeData::ValidateTabRefs() 610 { 611 // try to make sure all relative references and the reference position 612 // are within existing tables, so they can be represented as text 613 // (if the range of used tables is more than the existing tables, 614 // the result may still contain invalid tables, because the relative 615 // references aren't changed so formulas stay the same) 616 617 // find range of used tables 618 619 SCTAB nMinTab = aPos.Tab(); 620 SCTAB nMaxTab = nMinTab; 621 ScToken* t; 622 pCode->Reset(); 623 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 624 { 625 ScSingleRefData& rRef1 = t->GetSingleRef(); 626 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() ) 627 { 628 if ( rRef1.nTab < nMinTab ) 629 nMinTab = rRef1.nTab; 630 if ( rRef1.nTab > nMaxTab ) 631 nMaxTab = rRef1.nTab; 632 } 633 if ( t->GetType() == svDoubleRef ) 634 { 635 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 636 if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() ) 637 { 638 if ( rRef2.nTab < nMinTab ) 639 nMinTab = rRef2.nTab; 640 if ( rRef2.nTab > nMaxTab ) 641 nMaxTab = rRef2.nTab; 642 } 643 } 644 } 645 646 SCTAB nTabCount = pDoc->GetTableCount(); 647 if ( nMaxTab >= nTabCount && nMinTab > 0 ) 648 { 649 // move position and relative tab refs 650 // The formulas that use the name are not changed by this 651 652 SCTAB nMove = nMinTab; 653 aPos.SetTab( aPos.Tab() - nMove ); 654 655 pCode->Reset(); 656 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL ) 657 { 658 ScSingleRefData& rRef1 = t->GetSingleRef(); 659 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() ) 660 rRef1.nTab = sal::static_int_cast<SCsTAB>( rRef1.nTab - nMove ); 661 if ( t->GetType() == svDoubleRef ) 662 { 663 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 664 if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() ) 665 rRef2.nTab = sal::static_int_cast<SCsTAB>( rRef2.nTab - nMove ); 666 } 667 } 668 } 669 } 670 671 672 extern "C" int 673 #ifdef WNT 674 __cdecl 675 #endif 676 ScRangeData_QsortNameCompare( const void* p1, const void* p2 ) 677 { 678 return (int) ScGlobal::GetCollator()->compareString( 679 (*(const ScRangeData**)p1)->GetName(), 680 (*(const ScRangeData**)p2)->GetName() ); 681 } 682 683 684 //======================================================================== 685 // ScRangeName 686 //======================================================================== 687 688 ScRangeName::ScRangeName(const ScRangeName& rScRangeName, ScDocument* pDocument) : 689 ScSortedCollection ( rScRangeName ), 690 pDoc ( pDocument ), 691 nSharedMaxIndex (rScRangeName.nSharedMaxIndex) 692 { 693 for (sal_uInt16 i = 0; i < nCount; i++) 694 { 695 ((ScRangeData*)At(i))->SetDocument(pDocument); 696 ((ScRangeData*)At(i))->SetIndex(((ScRangeData*)rScRangeName.At(i))->GetIndex()); 697 } 698 } 699 700 short ScRangeName::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const 701 { 702 sal_uInt16 i1 = ((ScRangeData*)pKey1)->GetIndex(); 703 sal_uInt16 i2 = ((ScRangeData*)pKey2)->GetIndex(); 704 return (short) i1 - (short) i2; 705 } 706 707 sal_Bool ScRangeName::SearchNameUpper( const String& rUpperName, sal_uInt16& rIndex ) const 708 { 709 // SearchNameUpper must be called with an upper-case search string 710 711 sal_uInt16 i = 0; 712 while (i < nCount) 713 { 714 if ( ((*this)[i])->GetUpperName() == rUpperName ) 715 { 716 rIndex = i; 717 return sal_True; 718 } 719 i++; 720 } 721 return sal_False; 722 } 723 724 sal_Bool ScRangeName::SearchName( const String& rName, sal_uInt16& rIndex ) const 725 { 726 if ( nCount > 0 ) 727 return SearchNameUpper( ScGlobal::pCharClass->upper( rName ), rIndex ); 728 else 729 return sal_False; 730 } 731 732 void ScRangeName::UpdateReference( UpdateRefMode eUpdateRefMode, 733 const ScRange& rRange, 734 SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 735 { 736 for (sal_uInt16 i=0; i<nCount; i++) 737 ((ScRangeData*)pItems[i])->UpdateReference(eUpdateRefMode, rRange, 738 nDx, nDy, nDz); 739 } 740 741 void ScRangeName::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest ) 742 { 743 for (sal_uInt16 i=0; i<nCount; i++) 744 ((ScRangeData*)pItems[i])->UpdateTranspose( rSource, rDest ); 745 } 746 747 void ScRangeName::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) 748 { 749 for (sal_uInt16 i=0; i<nCount; i++) 750 ((ScRangeData*)pItems[i])->UpdateGrow( rArea, nGrowX, nGrowY ); 751 } 752 753 sal_Bool ScRangeName::IsEqual(ScDataObject* pKey1, ScDataObject* pKey2) const 754 { 755 return *(ScRangeData*)pKey1 == *(ScRangeData*)pKey2; 756 } 757 758 sal_Bool ScRangeName::Insert(ScDataObject* pScDataObject) 759 { 760 if (!((ScRangeData*)pScDataObject)->GetIndex()) // schon gesetzt? 761 { 762 ((ScRangeData*)pScDataObject)->SetIndex( GetEntryIndex() ); 763 } 764 765 return ScSortedCollection::Insert(pScDataObject); 766 } 767 768 // Suche nach einem freien Index 769 770 sal_uInt16 ScRangeName::GetEntryIndex() 771 { 772 sal_uInt16 nLast = 0; 773 for ( sal_uInt16 i = 0; i < nCount; i++ ) 774 { 775 sal_uInt16 nIdx = ((ScRangeData*)pItems[i])->GetIndex(); 776 if( nIdx > nLast ) 777 { 778 nLast = nIdx; 779 } 780 } 781 return nLast + 1; 782 } 783 784 ScRangeData* ScRangeName::FindIndex( sal_uInt16 nIndex ) 785 { 786 ScRangeData aDataObj( nIndex ); 787 sal_uInt16 n; 788 if( Search( &aDataObj, n ) ) 789 return (*this)[ n ]; 790 else 791 return NULL; 792 } 793 794 //UNUSED2009-05 ScRangeData* ScRangeName::GetRangeAtCursor( const ScAddress& rPos, sal_Bool bStartOnly ) const 795 //UNUSED2009-05 { 796 //UNUSED2009-05 if ( pItems ) 797 //UNUSED2009-05 { 798 //UNUSED2009-05 for ( sal_uInt16 i = 0; i < nCount; i++ ) 799 //UNUSED2009-05 if ( ((ScRangeData*)pItems[i])->IsRangeAtCursor( rPos, bStartOnly ) ) 800 //UNUSED2009-05 return (ScRangeData*)pItems[i]; 801 //UNUSED2009-05 } 802 //UNUSED2009-05 return NULL; 803 //UNUSED2009-05 } 804 805 ScRangeData* ScRangeName::GetRangeAtBlock( const ScRange& rBlock ) const 806 { 807 if ( pItems ) 808 { 809 for ( sal_uInt16 i = 0; i < nCount; i++ ) 810 if ( ((ScRangeData*)pItems[i])->IsRangeAtBlock( rBlock ) ) 811 return (ScRangeData*)pItems[i]; 812 } 813 return NULL; 814 } 815 816 void ScRangeName::UpdateTabRef(SCTAB nOldTable, sal_uInt16 nFlag, SCTAB nNewTable) 817 { 818 for (sal_uInt16 i=0; i<nCount; i++) 819 ((ScRangeData*)pItems[i])->UpdateTabRef(nOldTable, nFlag, nNewTable); 820 } 821 822 823 824 825