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 // INCLUDE --------------------------------------------------------------- 34 35 #include <tools/debug.hxx> 36 37 #include "rangeutl.hxx" 38 #include "document.hxx" 39 #include "global.hxx" 40 #include "dbcolect.hxx" 41 #include "rangenam.hxx" 42 #include "scresid.hxx" 43 #include "globstr.hrc" 44 #include "convuno.hxx" 45 #include "externalrefmgr.hxx" 46 #include "compiler.hxx" 47 48 using ::rtl::OUString; 49 using ::rtl::OUStringBuffer; 50 using ::formula::FormulaGrammar; 51 using namespace ::com::sun::star; 52 53 //------------------------------------------------------------------------ 54 55 sal_Bool ScRangeUtil::MakeArea( const String& rAreaStr, 56 ScArea& rArea, 57 ScDocument* pDoc, 58 SCTAB nTab, 59 ScAddress::Details const & rDetails ) const 60 { 61 // Eingabe in rAreaStr: "$Tabelle1.$A1:$D17" 62 63 // BROKEN BROKEN BROKEN 64 // but it is only used in the consolidate dialog. Ignore for now. 65 66 sal_Bool nSuccess = sal_False; 67 sal_uInt16 nPointPos = rAreaStr.Search('.'); 68 sal_uInt16 nColonPos = rAreaStr.Search(':'); 69 String aStrArea( rAreaStr ); 70 ScRefAddress startPos; 71 ScRefAddress endPos; 72 73 if ( nColonPos == STRING_NOTFOUND ) 74 if ( nPointPos != STRING_NOTFOUND ) 75 { 76 aStrArea += ':'; 77 aStrArea += rAreaStr.Copy( nPointPos+1 ); // '.' nicht mitkopieren 78 } 79 80 nSuccess = ConvertDoubleRef( pDoc, aStrArea, nTab, startPos, endPos, rDetails ); 81 82 if ( nSuccess ) 83 rArea = ScArea( startPos.Tab(), 84 startPos.Col(), startPos.Row(), 85 endPos.Col(), endPos.Row() ); 86 87 return nSuccess; 88 } 89 90 //------------------------------------------------------------------------ 91 92 void ScRangeUtil::CutPosString( const String& theAreaStr, 93 String& thePosStr ) const 94 { 95 String aPosStr; 96 // BROKEN BROKEN BROKEN 97 // but it is only used in the consolidate dialog. Ignore for now. 98 99 sal_uInt16 nColonPos = theAreaStr.Search(':'); 100 101 if ( nColonPos != STRING_NOTFOUND ) 102 aPosStr = theAreaStr.Copy( 0, nColonPos ); // ':' nicht mitkopieren 103 else 104 aPosStr = theAreaStr; 105 106 thePosStr = aPosStr; 107 } 108 109 //------------------------------------------------------------------------ 110 111 sal_Bool ScRangeUtil::IsAbsTabArea( const String& rAreaStr, 112 ScDocument* pDoc, 113 ScArea*** pppAreas, 114 sal_uInt16* pAreaCount, 115 sal_Bool /* bAcceptCellRef */, 116 ScAddress::Details const & rDetails ) const 117 { 118 DBG_ASSERT( pDoc, "Kein Dokument uebergeben!" ); 119 if ( !pDoc ) 120 return sal_False; 121 122 // BROKEN BROKEN BROKEN 123 // but it is only used in the consolidate dialog. Ignore for now. 124 125 /* 126 * Erwartet wird ein String der Form 127 * "$Tabelle1.$A$1:$Tabelle3.$D$17" 128 * Wenn bAcceptCellRef == sal_True ist, wird auch ein String der Form 129 * "$Tabelle1.$A$1" 130 * akzeptiert. 131 * 132 * als Ergebnis wird ein ScArea-Array angelegt, 133 * welches ueber ppAreas bekannt gegeben wird und auch 134 * wieder geloescht werden muss! 135 */ 136 137 sal_Bool bStrOk = sal_False; 138 String aTempAreaStr(rAreaStr); 139 String aStartPosStr; 140 String aEndPosStr; 141 142 if ( STRING_NOTFOUND == aTempAreaStr.Search(':') ) 143 { 144 aTempAreaStr.Append(':'); 145 aTempAreaStr.Append(rAreaStr); 146 } 147 148 sal_uInt16 nColonPos = aTempAreaStr.Search(':'); 149 150 if ( STRING_NOTFOUND != nColonPos 151 && STRING_NOTFOUND != aTempAreaStr.Search('.') ) 152 { 153 ScRefAddress aStartPos; 154 ScRefAddress aEndPos; 155 156 aStartPosStr = aTempAreaStr.Copy( 0, nColonPos ); 157 aEndPosStr = aTempAreaStr.Copy( nColonPos+1, STRING_LEN ); 158 159 if ( ConvertSingleRef( pDoc, aStartPosStr, 0, aStartPos, rDetails ) ) 160 { 161 if ( ConvertSingleRef( pDoc, aEndPosStr, aStartPos.Tab(), aEndPos, rDetails ) ) 162 { 163 aStartPos.SetRelCol( sal_False ); 164 aStartPos.SetRelRow( sal_False ); 165 aStartPos.SetRelTab( sal_False ); 166 aEndPos.SetRelCol( sal_False ); 167 aEndPos.SetRelRow( sal_False ); 168 aEndPos.SetRelTab( sal_False ); 169 170 bStrOk = sal_True; 171 172 if ( pppAreas && pAreaCount ) // Array zurueckgegeben? 173 { 174 SCTAB nStartTab = aStartPos.Tab(); 175 SCTAB nEndTab = aEndPos.Tab(); 176 sal_uInt16 nTabCount = static_cast<sal_uInt16>(nEndTab-nStartTab+1); 177 ScArea** theAreas = new ScArea*[nTabCount]; 178 SCTAB nTab = 0; 179 sal_uInt16 i = 0; 180 ScArea theArea( 0, aStartPos.Col(), aStartPos.Row(), 181 aEndPos.Col(), aEndPos.Row() ); 182 183 nTab = nStartTab; 184 for ( i=0; i<nTabCount; i++ ) 185 { 186 theAreas[i] = new ScArea( theArea ); 187 theAreas[i]->nTab = nTab; 188 nTab++; 189 } 190 *pppAreas = theAreas; 191 *pAreaCount = nTabCount; 192 } 193 } 194 } 195 } 196 197 return bStrOk; 198 } 199 200 //------------------------------------------------------------------------ 201 202 sal_Bool ScRangeUtil::IsAbsArea( const String& rAreaStr, 203 ScDocument* pDoc, 204 SCTAB nTab, 205 String* pCompleteStr, 206 ScRefAddress* pStartPos, 207 ScRefAddress* pEndPos, 208 ScAddress::Details const & rDetails ) const 209 { 210 sal_Bool bIsAbsArea = sal_False; 211 ScRefAddress startPos; 212 ScRefAddress endPos; 213 214 bIsAbsArea = ConvertDoubleRef( pDoc, rAreaStr, nTab, startPos, endPos, rDetails ); 215 216 if ( bIsAbsArea ) 217 { 218 startPos.SetRelCol( sal_False ); 219 startPos.SetRelRow( sal_False ); 220 startPos.SetRelTab( sal_False ); 221 endPos .SetRelCol( sal_False ); 222 endPos .SetRelRow( sal_False ); 223 endPos .SetRelTab( sal_False ); 224 225 if ( pCompleteStr ) 226 { 227 *pCompleteStr = startPos.GetRefString( pDoc, MAXTAB+1, rDetails ); 228 *pCompleteStr += ':'; 229 *pCompleteStr += endPos .GetRefString( pDoc, nTab, rDetails ); 230 } 231 232 if ( pStartPos && pEndPos ) 233 { 234 *pStartPos = startPos; 235 *pEndPos = endPos; 236 } 237 } 238 239 return bIsAbsArea; 240 } 241 242 //------------------------------------------------------------------------ 243 244 sal_Bool ScRangeUtil::IsAbsPos( const String& rPosStr, 245 ScDocument* pDoc, 246 SCTAB nTab, 247 String* pCompleteStr, 248 ScRefAddress* pPosTripel, 249 ScAddress::Details const & rDetails ) const 250 { 251 sal_Bool bIsAbsPos = sal_False; 252 ScRefAddress thePos; 253 254 bIsAbsPos = ConvertSingleRef( pDoc, rPosStr, nTab, thePos, rDetails ); 255 thePos.SetRelCol( sal_False ); 256 thePos.SetRelRow( sal_False ); 257 thePos.SetRelTab( sal_False ); 258 259 if ( bIsAbsPos ) 260 { 261 if ( pPosTripel ) 262 *pPosTripel = thePos; 263 if ( pCompleteStr ) 264 *pCompleteStr = thePos.GetRefString( pDoc, MAXTAB+1, rDetails ); 265 } 266 267 return bIsAbsPos; 268 } 269 270 //------------------------------------------------------------------------ 271 272 sal_Bool ScRangeUtil::MakeRangeFromName ( 273 const String& rName, 274 ScDocument* pDoc, 275 SCTAB nCurTab, 276 ScRange& rRange, 277 RutlNameScope eScope, 278 ScAddress::Details const & rDetails ) const 279 { 280 sal_Bool bResult=sal_False; 281 ScRangeUtil aRangeUtil; 282 SCTAB nTab = 0; 283 SCCOL nColStart = 0; 284 SCCOL nColEnd = 0; 285 SCROW nRowStart = 0; 286 SCROW nRowEnd = 0; 287 288 if( eScope==RUTL_NAMES ) 289 { 290 ScRangeName& rRangeNames = *(pDoc->GetRangeName()); 291 sal_uInt16 nAt = 0; 292 293 if ( rRangeNames.SearchName( rName, nAt ) ) 294 { 295 ScRangeData* pData = rRangeNames[nAt]; 296 String aStrArea; 297 ScRefAddress aStartPos; 298 ScRefAddress aEndPos; 299 300 pData->GetSymbol( aStrArea ); 301 302 if ( IsAbsArea( aStrArea, pDoc, nCurTab, 303 NULL, &aStartPos, &aEndPos, rDetails ) ) 304 { 305 nTab = aStartPos.Tab(); 306 nColStart = aStartPos.Col(); 307 nRowStart = aStartPos.Row(); 308 nColEnd = aEndPos.Col(); 309 nRowEnd = aEndPos.Row(); 310 bResult = sal_True; 311 } 312 else 313 { 314 CutPosString( aStrArea, aStrArea ); 315 316 if ( IsAbsPos( aStrArea, pDoc, nCurTab, 317 NULL, &aStartPos, rDetails ) ) 318 { 319 nTab = aStartPos.Tab(); 320 nColStart = nColEnd = aStartPos.Col(); 321 nRowStart = nRowEnd = aStartPos.Row(); 322 bResult = sal_True; 323 } 324 } 325 } 326 } 327 else if( eScope==RUTL_DBASE ) 328 { 329 ScDBCollection& rDbNames = *(pDoc->GetDBCollection()); 330 sal_uInt16 nAt = 0; 331 332 if ( rDbNames.SearchName( rName, nAt ) ) 333 { 334 ScDBData* pData = rDbNames[nAt]; 335 336 pData->GetArea( nTab, nColStart, nRowStart, 337 nColEnd, nRowEnd ); 338 bResult = sal_True; 339 } 340 } 341 else 342 { 343 DBG_ERROR( "ScRangeUtil::MakeRangeFromName" ); 344 } 345 346 if( bResult ) 347 { 348 rRange = ScRange( nColStart, nRowStart, nTab, nColEnd, nRowEnd, nTab ); 349 } 350 351 return bResult; 352 } 353 354 //======================================================================== 355 356 void ScRangeStringConverter::AssignString( 357 OUString& rString, 358 const OUString& rNewStr, 359 sal_Bool bAppendStr, 360 sal_Unicode cSeperator) 361 { 362 if( bAppendStr ) 363 { 364 if( rNewStr.getLength() ) 365 { 366 if( rString.getLength() ) 367 rString += rtl::OUString(cSeperator); 368 rString += rNewStr; 369 } 370 } 371 else 372 rString = rNewStr; 373 } 374 375 sal_Int32 ScRangeStringConverter::IndexOf( 376 const OUString& rString, 377 sal_Unicode cSearchChar, 378 sal_Int32 nOffset, 379 sal_Unicode cQuote ) 380 { 381 sal_Int32 nLength = rString.getLength(); 382 sal_Int32 nIndex = nOffset; 383 sal_Bool bQuoted = sal_False; 384 sal_Bool bExitLoop = sal_False; 385 386 while( !bExitLoop && (nIndex < nLength) ) 387 { 388 sal_Unicode cCode = rString[ nIndex ]; 389 bExitLoop = (cCode == cSearchChar) && !bQuoted; 390 bQuoted = (bQuoted != (cCode == cQuote)); 391 if( !bExitLoop ) 392 nIndex++; 393 } 394 return (nIndex < nLength) ? nIndex : -1; 395 } 396 397 sal_Int32 ScRangeStringConverter::IndexOfDifferent( 398 const OUString& rString, 399 sal_Unicode cSearchChar, 400 sal_Int32 nOffset ) 401 { 402 sal_Int32 nLength = rString.getLength(); 403 sal_Int32 nIndex = nOffset; 404 sal_Bool bExitLoop = sal_False; 405 406 while( !bExitLoop && (nIndex < nLength) ) 407 { 408 bExitLoop = (rString[ nIndex ] != cSearchChar); 409 if( !bExitLoop ) 410 nIndex++; 411 } 412 return (nIndex < nLength) ? nIndex : -1; 413 } 414 415 void ScRangeStringConverter::GetTokenByOffset( 416 OUString& rToken, 417 const OUString& rString, 418 sal_Int32& nOffset, 419 sal_Unicode cSeperator, 420 sal_Unicode cQuote) 421 { 422 sal_Int32 nLength = rString.getLength(); 423 if( nOffset >= nLength ) 424 { 425 rToken = OUString(); 426 nOffset = -1; 427 } 428 else 429 { 430 sal_Int32 nTokenEnd = IndexOf( rString, cSeperator, nOffset, cQuote ); 431 if( nTokenEnd < 0 ) 432 nTokenEnd = nLength; 433 rToken = rString.copy( nOffset, nTokenEnd - nOffset ); 434 435 sal_Int32 nNextBegin = IndexOfDifferent( rString, cSeperator, nTokenEnd ); 436 nOffset = (nNextBegin < 0) ? nLength : nNextBegin; 437 } 438 } 439 440 void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode /* cQuote */) 441 { 442 // quote character is always "'" 443 String aQuotedTab(rTabName); 444 ScCompiler::CheckTabQuotes(aQuotedTab, ::formula::FormulaGrammar::CONV_OOO); 445 rBuf.append(aQuotedTab); 446 } 447 448 sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote ) 449 { 450 OUString sToken; 451 sal_Int32 nCount = 0; 452 sal_Int32 nOffset = 0; 453 while( nOffset >= 0 ) 454 { 455 GetTokenByOffset( sToken, rString, nOffset, cQuote, cSeperator ); 456 if( nOffset >= 0 ) 457 nCount++; 458 } 459 return nCount; 460 } 461 462 //___________________________________________________________________ 463 464 sal_Bool ScRangeStringConverter::GetAddressFromString( 465 ScAddress& rAddress, 466 const OUString& rAddressStr, 467 const ScDocument* pDocument, 468 FormulaGrammar::AddressConvention eConv, 469 sal_Int32& nOffset, 470 sal_Unicode cSeperator, 471 sal_Unicode cQuote ) 472 { 473 OUString sToken; 474 GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote ); 475 if( nOffset >= 0 ) 476 { 477 if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID) 478 return true; 479 } 480 return sal_False; 481 } 482 483 sal_Bool ScRangeStringConverter::GetRangeFromString( 484 ScRange& rRange, 485 const OUString& rRangeStr, 486 const ScDocument* pDocument, 487 FormulaGrammar::AddressConvention eConv, 488 sal_Int32& nOffset, 489 sal_Unicode cSeperator, 490 sal_Unicode cQuote ) 491 { 492 OUString sToken; 493 sal_Bool bResult(sal_False); 494 GetTokenByOffset( sToken, rRangeStr, nOffset, cSeperator, cQuote ); 495 if( nOffset >= 0 ) 496 { 497 sal_Int32 nIndex = IndexOf( sToken, ':', 0, cQuote ); 498 String aUIString(sToken); 499 500 if( nIndex < 0 ) 501 { 502 if ( aUIString.GetChar(0) == (sal_Unicode) '.' ) 503 aUIString.Erase( 0, 1 ); 504 bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID); 505 rRange.aEnd = rRange.aStart; 506 } 507 else 508 { 509 if ( aUIString.GetChar(0) == (sal_Unicode) '.' ) 510 { 511 aUIString.Erase( 0, 1 ); 512 --nIndex; 513 } 514 515 if ( nIndex < aUIString.Len() - 1 && 516 aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' ) 517 aUIString.Erase( (xub_StrLen)nIndex + 1, 1 ); 518 519 bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID); 520 521 // #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet. 522 // This isn't parsed by ScRange, so try to parse the two Addresses then. 523 if (!bResult) 524 { 525 bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument), 526 eConv) & SCA_VALID) == SCA_VALID) && 527 ((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument), 528 eConv) & SCA_VALID) == SCA_VALID); 529 } 530 } 531 } 532 return bResult; 533 } 534 535 sal_Bool ScRangeStringConverter::GetRangeListFromString( 536 ScRangeList& rRangeList, 537 const OUString& rRangeListStr, 538 const ScDocument* pDocument, 539 FormulaGrammar::AddressConvention eConv, 540 sal_Unicode cSeperator, 541 sal_Unicode cQuote ) 542 { 543 sal_Bool bRet = sal_True; 544 DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" ); 545 sal_Int32 nOffset = 0; 546 while( nOffset >= 0 ) 547 { 548 ScRange* pRange = new ScRange; 549 if( GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) ) 550 rRangeList.Insert( pRange, LIST_APPEND ); 551 else if (nOffset > -1) 552 bRet = sal_False; 553 } 554 return bRet; 555 } 556 557 558 //___________________________________________________________________ 559 560 sal_Bool ScRangeStringConverter::GetAreaFromString( 561 ScArea& rArea, 562 const OUString& rRangeStr, 563 const ScDocument* pDocument, 564 FormulaGrammar::AddressConvention eConv, 565 sal_Int32& nOffset, 566 sal_Unicode cSeperator, 567 sal_Unicode cQuote ) 568 { 569 ScRange aScRange; 570 sal_Bool bResult(sal_False); 571 if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) ) 572 { 573 rArea.nTab = aScRange.aStart.Tab(); 574 rArea.nColStart = aScRange.aStart.Col(); 575 rArea.nRowStart = aScRange.aStart.Row(); 576 rArea.nColEnd = aScRange.aEnd.Col(); 577 rArea.nRowEnd = aScRange.aEnd.Row(); 578 bResult = sal_True; 579 } 580 return bResult; 581 } 582 583 584 //___________________________________________________________________ 585 586 sal_Bool ScRangeStringConverter::GetAddressFromString( 587 table::CellAddress& rAddress, 588 const OUString& rAddressStr, 589 const ScDocument* pDocument, 590 FormulaGrammar::AddressConvention eConv, 591 sal_Int32& nOffset, 592 sal_Unicode cSeperator, 593 sal_Unicode cQuote ) 594 { 595 ScAddress aScAddress; 596 sal_Bool bResult(sal_False); 597 if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) ) 598 { 599 ScUnoConversion::FillApiAddress( rAddress, aScAddress ); 600 bResult = sal_True; 601 } 602 return bResult; 603 } 604 605 sal_Bool ScRangeStringConverter::GetRangeFromString( 606 table::CellRangeAddress& rRange, 607 const OUString& rRangeStr, 608 const ScDocument* pDocument, 609 FormulaGrammar::AddressConvention eConv, 610 sal_Int32& nOffset, 611 sal_Unicode cSeperator, 612 sal_Unicode cQuote ) 613 { 614 ScRange aScRange; 615 sal_Bool bResult(sal_False); 616 if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) ) 617 { 618 ScUnoConversion::FillApiRange( rRange, aScRange ); 619 bResult = sal_True; 620 } 621 return bResult; 622 } 623 624 sal_Bool ScRangeStringConverter::GetRangeListFromString( 625 uno::Sequence< table::CellRangeAddress >& rRangeSeq, 626 const OUString& rRangeListStr, 627 const ScDocument* pDocument, 628 FormulaGrammar::AddressConvention eConv, 629 sal_Unicode cSeperator, 630 sal_Unicode cQuote ) 631 { 632 sal_Bool bRet = sal_True; 633 DBG_ASSERT( rRangeListStr.getLength(), "ScXMLConverter::GetRangeListFromString - empty string!" ); 634 table::CellRangeAddress aRange; 635 sal_Int32 nOffset = 0; 636 while( nOffset >= 0 ) 637 { 638 if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) ) 639 { 640 rRangeSeq.realloc( rRangeSeq.getLength() + 1 ); 641 rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange; 642 } 643 else 644 bRet = sal_False; 645 } 646 return bRet; 647 } 648 649 650 //___________________________________________________________________ 651 652 void ScRangeStringConverter::GetStringFromAddress( 653 OUString& rString, 654 const ScAddress& rAddress, 655 const ScDocument* pDocument, 656 FormulaGrammar::AddressConvention eConv, 657 sal_Unicode cSeperator, 658 sal_Bool bAppendStr, 659 sal_uInt16 nFormatFlags ) 660 { 661 if (pDocument && pDocument->HasTable(rAddress.Tab())) 662 { 663 String sAddress; 664 rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv ); 665 AssignString( rString, sAddress, bAppendStr, cSeperator ); 666 } 667 } 668 669 void ScRangeStringConverter::GetStringFromRange( 670 OUString& rString, 671 const ScRange& rRange, 672 const ScDocument* pDocument, 673 FormulaGrammar::AddressConvention eConv, 674 sal_Unicode cSeperator, 675 sal_Bool bAppendStr, 676 sal_uInt16 nFormatFlags ) 677 { 678 if (pDocument && pDocument->HasTable(rRange.aStart.Tab())) 679 { 680 ScAddress aStartAddress( rRange.aStart ); 681 ScAddress aEndAddress( rRange.aEnd ); 682 String sStartAddress; 683 String sEndAddress; 684 aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv ); 685 aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv ); 686 OUString sOUStartAddress( sStartAddress ); 687 sOUStartAddress += OUString(':'); 688 sOUStartAddress += OUString( sEndAddress ); 689 AssignString( rString, sOUStartAddress, bAppendStr, cSeperator ); 690 } 691 } 692 693 void ScRangeStringConverter::GetStringFromRangeList( 694 OUString& rString, 695 const ScRangeList* pRangeList, 696 const ScDocument* pDocument, 697 FormulaGrammar::AddressConvention eConv, 698 sal_Unicode cSeperator, 699 sal_uInt16 nFormatFlags ) 700 { 701 OUString sRangeListStr; 702 if( pRangeList ) 703 { 704 sal_Int32 nCount = pRangeList->Count(); 705 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) 706 { 707 const ScRange* pRange = pRangeList->GetObject( nIndex ); 708 if( pRange ) 709 GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags ); 710 } 711 } 712 rString = sRangeListStr; 713 } 714 715 716 //___________________________________________________________________ 717 718 void ScRangeStringConverter::GetStringFromArea( 719 OUString& rString, 720 const ScArea& rArea, 721 const ScDocument* pDocument, 722 FormulaGrammar::AddressConvention eConv, 723 sal_Unicode cSeperator, 724 sal_Bool bAppendStr, 725 sal_uInt16 nFormatFlags ) 726 { 727 ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab ); 728 GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags ); 729 } 730 731 732 //___________________________________________________________________ 733 734 void ScRangeStringConverter::GetStringFromAddress( 735 OUString& rString, 736 const table::CellAddress& rAddress, 737 const ScDocument* pDocument, 738 FormulaGrammar::AddressConvention eConv, 739 sal_Unicode cSeperator, 740 sal_Bool bAppendStr, 741 sal_uInt16 nFormatFlags ) 742 { 743 ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet ); 744 GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags ); 745 } 746 747 void ScRangeStringConverter::GetStringFromRange( 748 OUString& rString, 749 const table::CellRangeAddress& rRange, 750 const ScDocument* pDocument, 751 FormulaGrammar::AddressConvention eConv, 752 sal_Unicode cSeperator, 753 sal_Bool bAppendStr, 754 sal_uInt16 nFormatFlags ) 755 { 756 ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet, 757 static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet ); 758 GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags ); 759 } 760 761 void ScRangeStringConverter::GetStringFromRangeList( 762 OUString& rString, 763 const uno::Sequence< table::CellRangeAddress >& rRangeSeq, 764 const ScDocument* pDocument, 765 FormulaGrammar::AddressConvention eConv, 766 sal_Unicode cSeperator, 767 sal_uInt16 nFormatFlags ) 768 { 769 OUString sRangeListStr; 770 sal_Int32 nCount = rRangeSeq.getLength(); 771 for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) 772 { 773 const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ]; 774 GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags ); 775 } 776 rString = sRangeListStr; 777 } 778 779 static void lcl_appendCellAddress( 780 rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell, 781 const ScAddress::ExternalInfo& rExtInfo) 782 { 783 if (rExtInfo.mbExternal) 784 { 785 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 786 const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId, true); 787 if (!pFilePath) 788 return; 789 790 sal_Unicode cQuote = '\''; 791 rBuf.append(cQuote); 792 rBuf.append(*pFilePath); 793 rBuf.append(cQuote); 794 rBuf.append(sal_Unicode('#')); 795 rBuf.append(sal_Unicode('$')); 796 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName); 797 rBuf.append(sal_Unicode('.')); 798 799 String aAddr; 800 rCell.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO); 801 rBuf.append(aAddr); 802 } 803 else 804 { 805 String aAddr; 806 rCell.Format(aAddr, SCA_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO); 807 rBuf.append(aAddr); 808 } 809 } 810 811 static void lcl_appendCellRangeAddress( 812 rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2, 813 const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2) 814 { 815 if (rExtInfo1.mbExternal) 816 { 817 DBG_ASSERT(rExtInfo2.mbExternal, "2nd address is not external!?"); 818 DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses."); 819 820 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 821 const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId, true); 822 if (!pFilePath) 823 return; 824 825 sal_Unicode cQuote = '\''; 826 rBuf.append(cQuote); 827 rBuf.append(*pFilePath); 828 rBuf.append(cQuote); 829 rBuf.append(sal_Unicode('#')); 830 rBuf.append(sal_Unicode('$')); 831 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo1.maTabName); 832 rBuf.append(sal_Unicode('.')); 833 834 String aAddr; 835 rCell1.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO); 836 rBuf.append(aAddr); 837 838 rBuf.appendAscii(":"); 839 840 if (rExtInfo1.maTabName != rExtInfo2.maTabName) 841 { 842 rBuf.append(sal_Unicode('$')); 843 ScRangeStringConverter::AppendTableName(rBuf, rExtInfo2.maTabName); 844 rBuf.append(sal_Unicode('.')); 845 } 846 847 rCell2.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO); 848 rBuf.append(aAddr); 849 } 850 else 851 { 852 ScRange aRange; 853 aRange.aStart = rCell1; 854 aRange.aEnd = rCell2; 855 String aAddr; 856 aRange.Format(aAddr, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO); 857 rBuf.append(aAddr); 858 } 859 } 860 861 void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc ) 862 { 863 const sal_Unicode cSep = ' '; 864 const sal_Unicode cQuote = '\''; 865 866 OUStringBuffer aRetStr; 867 sal_Int32 nOffset = 0; 868 bool bFirst = true; 869 870 while (nOffset >= 0) 871 { 872 OUString aToken; 873 GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote); 874 if (nOffset < 0) 875 break; 876 877 sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote); 878 if (nSepPos >= 0) 879 { 880 // Cell range 881 OUString aBeginCell = aToken.copy(0, nSepPos); 882 OUString aEndCell = aToken.copy(nSepPos+1); 883 884 if (!aBeginCell.getLength() || !aEndCell.getLength()) 885 // both cell addresses must exist for this to work. 886 continue; 887 888 sal_Int32 nEndCellDotPos = aEndCell.indexOf('.'); 889 if (nEndCellDotPos <= 0) 890 { 891 // initialize buffer with table name... 892 sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote); 893 OUStringBuffer aBuf = aBeginCell.copy(0, nDotPos); 894 895 if (nEndCellDotPos == 0) 896 { 897 // workaround for old syntax (probably pre-chart2 age?) 898 // e.g. Sheet1.A1:.B2 899 aBuf.append(aEndCell); 900 } 901 else if (nEndCellDotPos < 0) 902 { 903 // sheet name in the end cell is omitted (e.g. Sheet2.A1:B2). 904 aBuf.append(sal_Unicode('.')); 905 aBuf.append(aEndCell); 906 } 907 aEndCell = aBuf.makeStringAndClear(); 908 } 909 910 ScAddress::ExternalInfo aExtInfo1, aExtInfo2; 911 ScAddress aCell1, aCell2; 912 rtl::OUString aBuf; 913 sal_uInt16 nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1); 914 if ((nRet & SCA_VALID) != SCA_VALID) 915 // first cell is invalid. 916 continue; 917 918 nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2); 919 if ((nRet & SCA_VALID) != SCA_VALID) 920 // second cell is invalid. 921 continue; 922 923 if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal) 924 // external info inconsistency. 925 continue; 926 927 // All looks good! 928 929 if (bFirst) 930 bFirst = false; 931 else 932 aRetStr.appendAscii(";"); 933 934 lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2); 935 } 936 else 937 { 938 // Chart always saves ranges using CONV_OOO convention. 939 ScAddress::ExternalInfo aExtInfo; 940 ScAddress aCell; 941 sal_uInt16 nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo); 942 if ((nRet & SCA_VALID) != SCA_VALID) 943 continue; 944 945 // Looks good! 946 947 if (bFirst) 948 bFirst = false; 949 else 950 aRetStr.appendAscii(";"); 951 952 lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo); 953 } 954 } 955 956 rString = aRetStr.makeStringAndClear(); 957 } 958 959 //======================================================================== 960 961 ScArea::ScArea( SCTAB tab, 962 SCCOL colStart, SCROW rowStart, 963 SCCOL colEnd, SCROW rowEnd ) : 964 nTab ( tab ), 965 nColStart( colStart ), nRowStart( rowStart ), 966 nColEnd ( colEnd ), nRowEnd ( rowEnd ) 967 { 968 } 969 970 //------------------------------------------------------------------------ 971 972 ScArea::ScArea( const ScArea& r ) : 973 nTab ( r.nTab ), 974 nColStart( r.nColStart ), nRowStart( r.nRowStart ), 975 nColEnd ( r.nColEnd ), nRowEnd ( r.nRowEnd ) 976 { 977 } 978 979 //------------------------------------------------------------------------ 980 981 ScArea& ScArea::operator=( const ScArea& r ) 982 { 983 nTab = r.nTab; 984 nColStart = r.nColStart; 985 nRowStart = r.nRowStart; 986 nColEnd = r.nColEnd; 987 nRowEnd = r.nRowEnd; 988 return *this; 989 } 990 991 //------------------------------------------------------------------------ 992 993 sal_Bool ScArea::operator==( const ScArea& r ) const 994 { 995 return ( (nTab == r.nTab) 996 && (nColStart == r.nColStart) 997 && (nRowStart == r.nRowStart) 998 && (nColEnd == r.nColEnd) 999 && (nRowEnd == r.nRowEnd) ); 1000 } 1001 1002 //------------------------------------------------------------------------ 1003 1004 ScAreaNameIterator::ScAreaNameIterator( ScDocument* pDoc ) : 1005 aStrNoName( ScGlobal::GetRscString(STR_DB_NONAME) ) 1006 { 1007 pRangeName = pDoc->GetRangeName(); 1008 pDBCollection = pDoc->GetDBCollection(); 1009 nPos = 0; 1010 bFirstPass = sal_True; 1011 } 1012 1013 sal_Bool ScAreaNameIterator::Next( String& rName, ScRange& rRange ) 1014 { 1015 for (;;) 1016 { 1017 if ( bFirstPass ) // erst Bereichsnamen 1018 { 1019 if ( pRangeName && nPos < pRangeName->GetCount() ) 1020 { 1021 ScRangeData* pData = (*pRangeName)[nPos++]; 1022 if ( pData && pData->IsValidReference(rRange) ) 1023 { 1024 rName = pData->GetName(); 1025 return sal_True; // gefunden 1026 } 1027 } 1028 else 1029 { 1030 bFirstPass = sal_False; 1031 nPos = 0; 1032 } 1033 } 1034 if ( !bFirstPass ) // dann DB-Bereiche 1035 { 1036 if ( pDBCollection && nPos < pDBCollection->GetCount() ) 1037 { 1038 ScDBData* pData = (*pDBCollection)[nPos++]; 1039 if (pData && pData->GetName() != aStrNoName) 1040 { 1041 pData->GetArea( rRange ); 1042 rName = pData->GetName(); 1043 return sal_True; // gefunden 1044 } 1045 } 1046 else 1047 return sal_False; // gibt nichts mehr 1048 } 1049 } 1050 } 1051 1052 1053 1054 1055