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 #include "address.hxx" 32 #include "global.hxx" 33 #include "compiler.hxx" 34 #include "document.hxx" 35 #include "externalrefmgr.hxx" 36 37 #include "globstr.hrc" 38 #include <sal/alloca.h> 39 40 #include <com/sun/star/frame/XModel.hpp> 41 #include <com/sun/star/beans/XPropertySet.hpp> 42 #include <com/sun/star/sheet/ExternalLinkInfo.hpp> 43 #include <com/sun/star/sheet/ExternalLinkType.hpp> 44 #include <sfx2/objsh.hxx> 45 #include <tools/urlobj.hxx> 46 using namespace ::com::sun::star; 47 48 //////////////////////////////////////////////////////////////////////////// 49 const ScAddress::Details ScAddress::detailsOOOa1( formula::FormulaGrammar::CONV_OOO, 0, 0 ); 50 51 ScAddress::Details::Details ( const ScDocument* pDoc, 52 const ScAddress & rAddr ) : 53 eConv( pDoc->GetAddressConvention() ), 54 nRow( rAddr.Row() ), 55 nCol( rAddr.Col() ) 56 { 57 } 58 59 //UNUSED2009-05 void ScAddress::Details::SetPos ( const ScDocument* pDoc, 60 //UNUSED2009-05 const ScAddress & rAddr ) 61 //UNUSED2009-05 { 62 //UNUSED2009-05 nRow = rAddr.Row(); 63 //UNUSED2009-05 nCol = rAddr.Col(); 64 //UNUSED2009-05 eConv = pDoc->GetAddressConvention(); 65 //UNUSED2009-05 } 66 67 //////////////////////////////////////////////////////////////////////////// 68 69 #include <iostream> 70 71 /** 72 * Parse from the opening single quote to the closing single quote. Inside 73 * the quotes, a single quote character is encoded by double single-quote 74 * characters. 75 * 76 * @param p pointer to the first character to begin parsing. 77 * @param rName (reference) parsed name within the quotes. If the name is 78 * empty, either the parsing failed or it's an empty quote. 79 * 80 * @return pointer to the character immediately after the closing single 81 * quote. 82 */ 83 static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName ) 84 { 85 rName.Erase(); 86 if (*p != '\'') 87 return p; 88 89 const sal_Unicode* pStart = p; 90 sal_Unicode cPrev = 0; 91 for (++p; *p; ++p) 92 { 93 if (*p == '\'') 94 { 95 if (cPrev == '\'') 96 { 97 // double single-quote equals one single quote. 98 rName += *p; 99 cPrev = 0; 100 continue; 101 } 102 } 103 else if (cPrev == '\'') 104 // We are past the closing quote. We're done! 105 return p; 106 else 107 rName += *p; 108 cPrev = *p; 109 } 110 rName.Erase(); 111 return pStart; 112 } 113 114 static long int 115 sal_Unicode_strtol ( const sal_Unicode* p, 116 const sal_Unicode** pEnd ) 117 { 118 long int accum = 0, prev = 0; 119 bool is_neg = false; 120 121 if( *p == '-' ) 122 { 123 is_neg = true; 124 p++; 125 } 126 else if( *p == '+' ) 127 p++; 128 129 while (CharClass::isAsciiDigit( *p )) 130 { 131 accum = accum * 10 + *p - '0'; 132 if( accum < prev ) 133 { 134 *pEnd = NULL; 135 return 0; 136 } 137 prev = accum; 138 p++; 139 } 140 141 *pEnd = p; 142 return is_neg ? -accum : accum; 143 } 144 145 const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p ) 146 { 147 if ( p ) 148 { 149 while( *p == ' ' ) 150 ++p; 151 } 152 return p; 153 } 154 155 /** Determines the number of sheets an external reference spans and sets 156 rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding 157 bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in 158 cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName 159 is set to rEndTabName. 160 @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not 161 result in the identical file ID. Else <TRUE/>. 162 */ 163 static bool lcl_ScRange_External_TabSpan( 164 ScRange & rRange, 165 sal_uInt16 & rFlags, 166 ScAddress::ExternalInfo* pExtInfo, 167 const String & rExternDocName, 168 const String & rStartTabName, 169 const String & rEndTabName, 170 ScDocument* pDoc ) 171 { 172 if (!rExternDocName.Len()) 173 return !pExtInfo || !pExtInfo->mbExternal; 174 175 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 176 if (pRefMgr->isOwnDocument( rExternDocName)) 177 return !pExtInfo || !pExtInfo->mbExternal; 178 179 sal_uInt16 nFileId = pRefMgr->getExternalFileId( rExternDocName); 180 181 if (pExtInfo) 182 { 183 if (pExtInfo->mbExternal) 184 { 185 if (pExtInfo->mnFileId != nFileId) 186 return false; 187 } 188 else 189 { 190 pExtInfo->mbExternal = true; 191 pExtInfo->maTabName = rStartTabName; 192 pExtInfo->mnFileId = nFileId; 193 } 194 } 195 196 if (!rEndTabName.Len() || rStartTabName == rEndTabName) 197 { 198 rRange.aEnd.SetTab( rRange.aStart.Tab()); 199 return true; 200 } 201 202 SCsTAB nSpan = pRefMgr->getCachedTabSpan( nFileId, rStartTabName, rEndTabName); 203 if (nSpan == -1) 204 rFlags &= ~(SCA_VALID_TAB | SCA_VALID_TAB2); 205 else if (nSpan == 0) 206 rFlags &= ~SCA_VALID_TAB2; 207 else if (nSpan >= 1) 208 rRange.aEnd.SetTab( rRange.aStart.Tab() + nSpan - 1); 209 else // (nSpan < -1) 210 { 211 rRange.aEnd.SetTab( rRange.aStart.Tab() - nSpan - 1); 212 if (pExtInfo) 213 pExtInfo->maTabName = rEndTabName; 214 } 215 return true; 216 } 217 218 /** Returns NULL if the string should be a sheet name, but is invalid. 219 Returns a pointer to the first character after the sheet name, if there was 220 any, else pointer to start. 221 @param pMsoxlQuoteStop 222 Starting _within_ a quoted name, but still may be 3D; quoted name stops 223 at pMsoxlQuoteStop 224 */ 225 static const sal_Unicode * 226 lcl_XL_ParseSheetRef( const sal_Unicode* start, 227 String& rExternTabName, 228 bool allow_3d, 229 const sal_Unicode* pMsoxlQuoteStop ) 230 { 231 String aTabName; 232 const sal_Unicode *p = start; 233 234 // XL only seems to use single quotes for sheet names. 235 if (pMsoxlQuoteStop) 236 { 237 const sal_Unicode* pCurrentStart = p; 238 while (p < pMsoxlQuoteStop) 239 { 240 if (*p == '\'') 241 { 242 // We pre-analyzed the quoting, no checks needed here. 243 if (*++p == '\'') 244 { 245 aTabName.Append( pCurrentStart, 246 sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); 247 pCurrentStart = ++p; 248 } 249 } 250 else if (*p == ':') 251 { 252 break; // while 253 } 254 else 255 ++p; 256 } 257 if (pCurrentStart < p) 258 aTabName.Append( pCurrentStart, sal::static_int_cast<xub_StrLen>( p - pCurrentStart)); 259 if (!aTabName.Len()) 260 return NULL; 261 if (p == pMsoxlQuoteStop) 262 ++p; // position on ! of ...'!... 263 if( *p != '!' && ( !allow_3d || *p != ':' ) ) 264 return (!allow_3d && *p == ':') ? p : start; 265 } 266 else if( *p == '\'') 267 { 268 p = lcl_ParseQuotedName(p, aTabName); 269 if (!aTabName.Len()) 270 return NULL; 271 } 272 else 273 { 274 bool only_digits = sal_True; 275 276 /* 277 * Valid: Normal!a1 278 * Valid: x.y!a1 279 * Invalid: .y!a1 280 * 281 * Some names starting with digits are actually valid, but 282 * unparse quoted. Things are quite tricky: most sheet names 283 * starting with a digit are ok, but not those starting with 284 * "[0-9]*\." or "[0-9]+[eE]". 285 * 286 * Valid: 42!a1 287 * Valid: 4x!a1 288 * Invalid: 1.!a1 289 * Invalid: 1e!a1 290 */ 291 while( 1 ) 292 { 293 const sal_Unicode uc = *p; 294 if( CharClass::isAsciiAlpha( uc ) || uc == '_' ) 295 { 296 if( only_digits && p != start && 297 (uc == 'e' || uc == 'E' ) ) 298 { 299 p = start; 300 break; 301 } 302 only_digits = sal_False; 303 p++; 304 } 305 else if( CharClass::isAsciiDigit( uc )) 306 { 307 p++; 308 } 309 else if( uc == '.' ) 310 { 311 if( only_digits ) // Valid, except after only digits. 312 { 313 p = start; 314 break; 315 } 316 p++; 317 } 318 else if (uc > 127) 319 { 320 // non ASCII character is allowed. 321 ++p; 322 } 323 else 324 break; 325 } 326 327 if( *p != '!' && ( !allow_3d || *p != ':' ) ) 328 return (!allow_3d && *p == ':') ? p : start; 329 330 aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) ); 331 } 332 333 rExternTabName = aTabName; 334 return p; 335 } 336 337 338 const sal_Unicode* ScRange::Parse_XL_Header( 339 const sal_Unicode* p, 340 const ScDocument* pDoc, 341 String& rExternDocName, 342 String& rStartTabName, 343 String& rEndTabName, 344 sal_uInt16& nFlags, 345 bool bOnlyAcceptSingle, 346 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 347 { 348 const sal_Unicode* startTabs, *start = p; 349 sal_uInt16 nSaveFlags = nFlags; 350 351 // Is this an external reference ? 352 rStartTabName.Erase(); 353 rEndTabName.Erase(); 354 rExternDocName.Erase(); 355 const sal_Unicode* pMsoxlQuoteStop = NULL; 356 if (*p == '[') 357 { 358 ++p; 359 // Only single quotes are correct, and a double single quote escapes a 360 // single quote text inside the quoted text. 361 if (*p == '\'') 362 { 363 p = lcl_ParseQuotedName(p, rExternDocName); 364 if (!*p || *p != ']' || !rExternDocName.Len()) 365 { 366 rExternDocName.Erase(); 367 return start; 368 } 369 } 370 else 371 { 372 // non-quoted file name. 373 p = ScGlobal::UnicodeStrChr( start+1, ']' ); 374 if( p == NULL ) 375 return start; 376 rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) ); 377 } 378 ++p; 379 380 if (pExternalLinks && pExternalLinks->hasElements()) 381 { 382 // A numeric "document name" is an index into the sequence. 383 if (CharClass::isAsciiNumeric( rExternDocName)) 384 { 385 sal_Int32 i = rExternDocName.ToInt32(); 386 if (i < 0 || i >= pExternalLinks->getLength()) 387 return start; 388 const sheet::ExternalLinkInfo & rInfo = (*pExternalLinks)[i]; 389 switch (rInfo.Type) 390 { 391 case sheet::ExternalLinkType::DOCUMENT : 392 { 393 rtl::OUString aStr; 394 if (!(rInfo.Data >>= aStr)) 395 { 396 DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i); 397 return NULL; 398 } 399 rExternDocName = aStr; 400 } 401 break; 402 case sheet::ExternalLinkType::SELF : 403 return start; // ??? 404 case sheet::ExternalLinkType::SPECIAL : 405 // silently return nothing (do not assert), caller has to handle this 406 return NULL; 407 default: 408 DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d", 409 rInfo.Type, i); 410 return NULL; 411 } 412 } 413 } 414 rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell()); 415 } 416 else if (*p == '\'') 417 { 418 // Sickness in Excel's ODF msoxl namespace: 419 // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7 or 420 // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11 421 // But, 'Sheet1'!B3 would also be a valid! 422 // Excel does not allow [ and ] characters in sheet names though. 423 p = lcl_ParseQuotedName(p, rExternDocName); 424 if (!*p || *p != '!') 425 { 426 rExternDocName.Erase(); 427 return start; 428 } 429 if (rExternDocName.Len()) 430 { 431 xub_StrLen nOpen = rExternDocName.Search( '['); 432 if (nOpen == STRING_NOTFOUND) 433 rExternDocName.Erase(); 434 else 435 { 436 xub_StrLen nClose = rExternDocName.Search( ']', nOpen+1); 437 if (nClose == STRING_NOTFOUND) 438 rExternDocName.Erase(); 439 else 440 { 441 rExternDocName.Erase( nClose); 442 rExternDocName.Erase( nOpen, 1); 443 pMsoxlQuoteStop = p - 1; // the ' quote char 444 // There may be embedded escaped quotes, just matching the 445 // doc name's length may not work. 446 for (p = start; *p != '['; ++p) 447 ; 448 for ( ; *p != ']'; ++p) 449 ; 450 ++p; 451 } 452 } 453 } 454 if (!rExternDocName.Len()) 455 p = start; 456 } 457 458 startTabs = p; 459 p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop); 460 if( NULL == p ) 461 return start; // invalid tab 462 if (bOnlyAcceptSingle && *p == ':') 463 return NULL; // 3D 464 if( p != startTabs ) 465 { 466 nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE; 467 if( *p == ':' ) // 3d ref 468 { 469 p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop); 470 if( p == NULL ) 471 { 472 nFlags = nSaveFlags; 473 return start; // invalid tab 474 } 475 nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE; 476 } 477 else 478 { 479 // If only one sheet is given, the full reference is still valid, 480 // only the second 3D flag is not set. 481 nFlags |= SCA_VALID_TAB2 | SCA_TAB2_ABSOLUTE; 482 aEnd.SetTab( aStart.Tab() ); 483 } 484 485 if( *p++ != '!' ) 486 { 487 nFlags = nSaveFlags; 488 return start; // syntax error 489 } 490 else 491 p = lcl_eatWhiteSpace( p ); 492 } 493 else 494 { 495 nFlags |= SCA_VALID_TAB | SCA_VALID_TAB2; 496 // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. ); 497 } 498 499 if (rExternDocName.Len()) 500 { 501 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 502 pRefMgr->convertToAbsName( rExternDocName); 503 } 504 else 505 { 506 // Internal reference. 507 if (!rStartTabName.Len()) 508 { 509 nFlags = nSaveFlags; 510 return start; 511 } 512 513 SCTAB nTab; 514 if (!pDoc->GetTable(rStartTabName, nTab)) 515 { 516 // invalid table name. 517 nFlags &= ~SCA_VALID_TAB; 518 nTab = -1; 519 } 520 521 aStart.SetTab(nTab); 522 aEnd.SetTab(nTab); 523 524 if (rEndTabName.Len()) 525 { 526 if (!pDoc->GetTable(rEndTabName, nTab)) 527 { 528 // invalid table name. 529 nFlags &= ~SCA_VALID_TAB2; 530 nTab = -1; 531 } 532 533 aEnd.SetTab(nTab); 534 } 535 } 536 return p; 537 } 538 539 540 static const sal_Unicode* 541 lcl_r1c1_get_col( const sal_Unicode* p, 542 const ScAddress::Details& rDetails, 543 ScAddress* pAddr, sal_uInt16* nFlags ) 544 { 545 const sal_Unicode *pEnd; 546 long int n; 547 bool isRelative; 548 549 if( p[0] == '\0' ) 550 return NULL; 551 552 p++; 553 if( (isRelative = (*p == '[') ) != false ) 554 p++; 555 n = sal_Unicode_strtol( p, &pEnd ); 556 if( NULL == pEnd ) 557 return NULL; 558 559 if( p == pEnd ) // C is a relative ref with offset 0 560 { 561 if( isRelative ) 562 return NULL; 563 n = rDetails.nCol; 564 } 565 else if( isRelative ) 566 { 567 if( *pEnd != ']' ) 568 return NULL; 569 n += rDetails.nCol; 570 pEnd++; 571 } 572 else 573 { 574 *nFlags |= SCA_COL_ABSOLUTE; 575 n--; 576 } 577 578 if( n < 0 || n >= MAXCOLCOUNT ) 579 return NULL; 580 pAddr->SetCol( static_cast<SCCOL>( n ) ); 581 *nFlags |= SCA_VALID_COL; 582 583 return pEnd; 584 } 585 static inline const sal_Unicode* 586 lcl_r1c1_get_row( const sal_Unicode* p, 587 const ScAddress::Details& rDetails, 588 ScAddress* pAddr, sal_uInt16* nFlags ) 589 { 590 const sal_Unicode *pEnd; 591 long int n; 592 bool isRelative; 593 594 if( p[0] == '\0' ) 595 return NULL; 596 597 p++; 598 if( (isRelative = (*p == '[') ) != false ) 599 p++; 600 n = sal_Unicode_strtol( p, &pEnd ); 601 if( NULL == pEnd ) 602 return NULL; 603 604 if( p == pEnd ) // R is a relative ref with offset 0 605 { 606 if( isRelative ) 607 return NULL; 608 n = rDetails.nRow; 609 } 610 else if( isRelative ) 611 { 612 if( *pEnd != ']' ) 613 return NULL; 614 n += rDetails.nRow; 615 pEnd++; 616 } 617 else 618 { 619 *nFlags |= SCA_ROW_ABSOLUTE; 620 n--; 621 } 622 623 if( n < 0 || n >= MAXROWCOUNT ) 624 return NULL; 625 pAddr->SetRow( static_cast<SCROW>( n ) ); 626 *nFlags |= SCA_VALID_ROW; 627 628 return pEnd; 629 } 630 631 static sal_uInt16 632 lcl_ScRange_Parse_XL_R1C1( ScRange& r, 633 const sal_Unicode* p, 634 ScDocument* pDoc, 635 const ScAddress::Details& rDetails, 636 bool bOnlyAcceptSingle, 637 ScAddress::ExternalInfo* pExtInfo ) 638 { 639 const sal_Unicode* pTmp = NULL; 640 String aExternDocName, aStartTabName, aEndTabName; 641 sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB; 642 // Keep in mind that nFlags2 gets left-shifted by 4 bits before being merged. 643 sal_uInt16 nFlags2 = SCA_VALID_TAB; 644 645 #if 0 646 { 647 ByteString aStr(p, RTL_TEXTENCODING_UTF8); 648 aStr.Append(static_cast< char >(0)); 649 std::cerr << "parse::XL::R1C1 \'" << aStr.GetBuffer() << '\'' << std::endl; 650 } 651 #endif 652 p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, 653 aEndTabName, nFlags, bOnlyAcceptSingle, NULL ); 654 655 if (aExternDocName.Len() > 0) 656 lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, 657 aStartTabName, aEndTabName, pDoc); 658 659 if( NULL == p ) 660 return 0; 661 662 if( *p == 'R' || *p == 'r' ) 663 { 664 if( NULL == (p = lcl_r1c1_get_row( p, rDetails, &r.aStart, &nFlags )) ) 665 goto failed; 666 667 if( *p != 'C' && *p != 'c' ) // full row R# 668 { 669 if( p[0] != ':' || (p[1] != 'R' && p[1] != 'r' ) || 670 NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 ))) 671 { 672 // Only the initial row number is given, or the second row 673 // number is invalid. Fallback to just the initial R 674 nFlags |= (nFlags << 4); 675 r.aEnd.SetRow( r.aStart.Row() ); 676 } 677 else 678 { 679 // Full row range successfully parsed. 680 nFlags |= (nFlags2 << 4); 681 p = pTmp; 682 } 683 684 if (p && p[0] != 0) 685 { 686 // any trailing invalid character must invalidate the whole address. 687 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 688 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 689 return nFlags; 690 } 691 692 nFlags |= 693 SCA_VALID_COL | SCA_VALID_COL2 | 694 SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE; 695 r.aStart.SetCol( 0 ); 696 r.aEnd.SetCol( MAXCOL ); 697 698 return bOnlyAcceptSingle ? 0 : nFlags; 699 } 700 else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags ))) 701 goto failed; 702 703 if( p[0] != ':' || 704 (p[1] != 'R' && p[1] != 'r') || 705 NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )) || 706 (*pTmp != 'C' && *pTmp != 'c') || 707 NULL == (pTmp = lcl_r1c1_get_col( pTmp, rDetails, &r.aEnd, &nFlags2 ))) 708 { 709 // single cell reference 710 711 if (p && p[0] != 0) 712 { 713 // any trailing invalid character must invalidate the whole address. 714 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); 715 return nFlags; 716 } 717 718 return bOnlyAcceptSingle ? nFlags : 0; 719 } 720 p = pTmp; 721 722 // double reference 723 724 if (p && p[0] != 0) 725 { 726 // any trailing invalid character must invalidate the whole range. 727 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 728 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 729 return nFlags; 730 } 731 732 nFlags |= (nFlags2 << 4); 733 return bOnlyAcceptSingle ? 0 : nFlags; 734 } 735 else if( *p == 'C' || *p == 'c' ) // full col C# 736 { 737 if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags ))) 738 goto failed; 739 740 if( p[0] != ':' || (p[1] != 'C' && p[1] != 'c') || 741 NULL == (pTmp = lcl_r1c1_get_col( p+1, rDetails, &r.aEnd, &nFlags2 ))) 742 { // Fallback to just the initial C 743 nFlags |= (nFlags << 4); 744 r.aEnd.SetCol( r.aStart.Col() ); 745 } 746 else 747 { 748 nFlags |= (nFlags2 << 4); 749 p = pTmp; 750 } 751 752 if (p && p[0] != 0) 753 { 754 // any trailing invalid character must invalidate the whole address. 755 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 756 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 757 return nFlags; 758 } 759 760 nFlags |= 761 SCA_VALID_ROW | SCA_VALID_ROW2 | 762 SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE; 763 r.aStart.SetRow( 0 ); 764 r.aEnd.SetRow( MAXROW ); 765 766 return bOnlyAcceptSingle ? 0 : nFlags; 767 } 768 769 failed : 770 return 0; 771 } 772 773 static inline const sal_Unicode* 774 lcl_a1_get_col( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags ) 775 { 776 SCCOL nCol; 777 778 if( *p == '$' ) 779 *nFlags |= SCA_COL_ABSOLUTE, p++; 780 781 if( !CharClass::isAsciiAlpha( *p ) ) 782 return NULL; 783 784 nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' ); 785 while (nCol <= MAXCOL && CharClass::isAsciiAlpha(*p)) 786 nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' ); 787 if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) ) 788 return NULL; 789 790 *nFlags |= SCA_VALID_COL; 791 pAddr->SetCol( nCol ); 792 793 return p; 794 } 795 796 static inline const sal_Unicode* 797 lcl_a1_get_row( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags ) 798 { 799 const sal_Unicode *pEnd; 800 long int n; 801 802 if( *p == '$' ) 803 *nFlags |= SCA_ROW_ABSOLUTE, p++; 804 805 n = sal_Unicode_strtol( p, &pEnd ) - 1; 806 if( NULL == pEnd || p == pEnd || n < 0 || n > MAXROW ) 807 return NULL; 808 809 *nFlags |= SCA_VALID_ROW; 810 pAddr->SetRow( static_cast<SCROW>(n) ); 811 812 return pEnd; 813 } 814 815 static sal_uInt16 816 lcl_ScRange_Parse_XL_A1( ScRange& r, 817 const sal_Unicode* p, 818 ScDocument* pDoc, 819 bool bOnlyAcceptSingle, 820 ScAddress::ExternalInfo* pExtInfo, 821 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 822 { 823 const sal_Unicode* tmp1, *tmp2; 824 String aExternDocName, aStartTabName, aEndTabName; // for external link table 825 sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB; 826 827 #if 0 828 { 829 ByteString aStr(p, RTL_TEXTENCODING_UTF8); 830 aStr.Append(static_cast< char >(0)); 831 std::cerr << "parse::XL::A1 \'" << aStr.GetBuffer() << '\'' << std::endl; 832 } 833 #endif 834 p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName, 835 aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks ); 836 837 if (aExternDocName.Len() > 0) 838 lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName, 839 aStartTabName, aEndTabName, pDoc); 840 841 if( NULL == p ) 842 return 0; 843 844 tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags ); 845 if( tmp1 == NULL ) // Is it a row only reference 3:5 846 { 847 if( bOnlyAcceptSingle ) // by definition full row refs are ranges 848 return 0; 849 850 tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags ); 851 852 tmp1 = lcl_eatWhiteSpace( tmp1 ); 853 if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2) 854 return 0; 855 856 tmp1 = lcl_eatWhiteSpace( tmp1 ); 857 tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); 858 if( !tmp2 ) 859 return 0; 860 861 r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL ); 862 nFlags |= 863 SCA_VALID_COL | SCA_VALID_COL2 | 864 SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE; 865 nFlags |= (nFlags2 << 4); 866 return nFlags; 867 } 868 869 tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags ); 870 if( tmp2 == NULL ) // check for col only reference F:H 871 { 872 if( bOnlyAcceptSingle ) // by definition full col refs are ranges 873 return 0; 874 875 tmp1 = lcl_eatWhiteSpace( tmp1 ); 876 if( *tmp1++ != ':' ) // Even a singleton requires ':' (eg F:F) 877 return 0; 878 879 tmp1 = lcl_eatWhiteSpace( tmp1 ); 880 tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 ); 881 if( !tmp2 ) 882 return 0; 883 884 r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW ); 885 nFlags |= 886 SCA_VALID_ROW | SCA_VALID_ROW2 | 887 SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE; 888 nFlags |= (nFlags2 << 4); 889 return nFlags; 890 } 891 892 // prepare as if it's a singleton, in case we want to fall back */ 893 r.aEnd.SetCol( r.aStart.Col() ); 894 r.aEnd.SetRow( r.aStart.Row() ); // don't overwrite sheet number as parsed in Parse_XL_Header() 895 896 if ( bOnlyAcceptSingle ) 897 { 898 if ( *tmp2 == 0 ) 899 return nFlags; 900 else 901 { 902 // any trailing invalid character must invalidate the address. 903 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB); 904 return nFlags; 905 } 906 } 907 908 tmp2 = lcl_eatWhiteSpace( tmp2 ); 909 if( *tmp2 != ':' ) 910 { 911 // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is 912 // not. Any trailing invalid character invalidates the range. 913 if (*tmp2 == 0 && (nFlags & SCA_TAB2_3D)) 914 { 915 if (nFlags & SCA_COL_ABSOLUTE) 916 nFlags |= SCA_COL2_ABSOLUTE; 917 if (nFlags & SCA_ROW_ABSOLUTE) 918 nFlags |= SCA_ROW2_ABSOLUTE; 919 } 920 else 921 nFlags &= ~(SCA_VALID | 922 SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 923 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 924 return nFlags; 925 } 926 927 p = tmp2; 928 p = lcl_eatWhiteSpace( p+1 ); 929 tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 ); 930 if( !tmp1 ) // strange, but valid singleton 931 return nFlags; 932 933 tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 ); 934 if( !tmp2 ) // strange, but valid singleton 935 return nFlags; 936 937 if ( *tmp2 != 0 ) 938 { 939 // any trailing invalid character must invalidate the range. 940 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB | 941 SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2); 942 return nFlags; 943 } 944 945 nFlags |= (nFlags2 << 4); 946 return nFlags; 947 } 948 949 /** 950 @param pRange pointer to range where rAddr effectively is *pRange->aEnd, 951 used in conjunction with pExtInfo to determine the tab span 952 of a 3D reference. 953 */ 954 static sal_uInt16 955 lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, 956 ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL ) 957 { 958 sal_uInt16 nRes = 0; 959 String aDocName; // der pure Dokumentenname 960 String aTab; 961 bool bExtDoc = false; 962 bool bExtDocInherited = false; 963 const ScAddress aCurPos(rAddr); 964 965 // Lets see if this is a reference to something in an external file. A 966 // document name is always quoted and has a trailing #. 967 if (*p == '\'') 968 { 969 const sal_Unicode* pStart = p; 970 p = lcl_ParseQuotedName(p, aDocName); 971 if (*p++ == SC_COMPILER_FILE_TAB_SEP) 972 bExtDoc = true; 973 else 974 // This is not a document name. Perhaps a quoted relative table 975 // name. 976 p = pStart; 977 } 978 else if (pExtInfo && pExtInfo->mbExternal) 979 { 980 // This is an external reference. 981 bExtDoc = bExtDocInherited = true; 982 } 983 984 SCCOL nCol = 0; 985 SCROW nRow = 0; 986 SCTAB nTab = 0; 987 sal_uInt16 nBits = SCA_VALID_TAB; 988 const sal_Unicode* q; 989 if ( ScGlobal::FindUnquoted( p, '.') ) 990 { 991 nRes |= SCA_TAB_3D; 992 if ( bExtDoc ) 993 nRes |= SCA_TAB_ABSOLUTE; 994 if (*p == '$') 995 nRes |= SCA_TAB_ABSOLUTE, p++; 996 997 if (*p == '\'') 998 { 999 // Tokens that start at ' can have anything in them until a final 1000 // ' but '' marks an escaped '. We've earlier guaranteed that a 1001 // string containing '' will be surrounded by '. 1002 p = lcl_ParseQuotedName(p, aTab); 1003 } 1004 else 1005 { 1006 while (*p) 1007 { 1008 if( *p == '.') 1009 break; 1010 1011 if( *p == '\'' ) 1012 { 1013 p++; break; 1014 } 1015 aTab += *p++; 1016 } 1017 } 1018 if( *p++ != '.' ) 1019 nBits = 0; 1020 1021 if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab ))) 1022 nBits = 0; 1023 } 1024 else 1025 { 1026 if (bExtDoc && !bExtDocInherited) 1027 return nRes; // After a document a sheet must follow. 1028 nTab = rAddr.Tab(); 1029 } 1030 nRes |= nBits; 1031 1032 q = p; 1033 if (*p) 1034 { 1035 nBits = SCA_VALID_COL; 1036 if (*p == '$') 1037 nBits |= SCA_COL_ABSOLUTE, p++; 1038 1039 if (CharClass::isAsciiAlpha( *p )) 1040 { 1041 nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' ); 1042 while (nCol < MAXCOL && CharClass::isAsciiAlpha(*p)) 1043 nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' ); 1044 } 1045 else 1046 nBits = 0; 1047 1048 if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) ) 1049 nBits = 0; 1050 nRes |= nBits; 1051 if( !nBits ) 1052 p = q; 1053 } 1054 1055 q = p; 1056 if (*p) 1057 { 1058 nBits = SCA_VALID_ROW; 1059 if (*p == '$') 1060 nBits |= SCA_ROW_ABSOLUTE, p++; 1061 if( !CharClass::isAsciiDigit( *p ) ) 1062 { 1063 nBits = 0; 1064 nRow = SCROW(-1); 1065 } 1066 else 1067 { 1068 String aTmp( p ); 1069 long n = aTmp.ToInt32() - 1; 1070 while (CharClass::isAsciiDigit( *p )) 1071 p++; 1072 if( n < 0 || n > MAXROW ) 1073 nBits = 0; 1074 nRow = static_cast<SCROW>(n); 1075 } 1076 nRes |= nBits; 1077 if( !nBits ) 1078 p = q; 1079 } 1080 1081 rAddr.Set( nCol, nRow, nTab ); 1082 1083 if (!*p && bExtDoc) 1084 { 1085 if (!pDoc) 1086 nRes = 0; 1087 else 1088 { 1089 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 1090 1091 // Need document name if inherited. 1092 if (bExtDocInherited) 1093 { 1094 const String* pFileName = pRefMgr->getExternalFileName( pExtInfo->mnFileId); 1095 if (pFileName) 1096 aDocName = *pFileName; 1097 else 1098 nRes = 0; 1099 } 1100 pRefMgr->convertToAbsName(aDocName); 1101 1102 if ((!pExtInfo || !pExtInfo->mbExternal) && pRefMgr->isOwnDocument(aDocName)) 1103 { 1104 if (!pDoc->GetTable( aTab, nTab )) 1105 nRes = 0; 1106 else 1107 { 1108 rAddr.SetTab( nTab); 1109 nRes |= SCA_VALID_TAB; 1110 } 1111 } 1112 else 1113 { 1114 if (!pExtInfo) 1115 nRes = 0; 1116 else 1117 { 1118 if (!pExtInfo->mbExternal) 1119 { 1120 sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName); 1121 1122 pExtInfo->mbExternal = true; 1123 pExtInfo->maTabName = aTab; 1124 pExtInfo->mnFileId = nFileId; 1125 1126 if (pRefMgr->getSingleRefToken(nFileId, aTab, 1127 ScAddress(nCol, nRow, 0), NULL, 1128 &nTab).get()) 1129 { 1130 rAddr.SetTab( nTab); 1131 nRes |= SCA_VALID_TAB; 1132 } 1133 else 1134 nRes = 0; 1135 } 1136 else 1137 { 1138 // This is a call for the second part of the reference, 1139 // we must have the range to adapt tab span. 1140 if (!pRange) 1141 nRes = 0; 1142 else 1143 { 1144 sal_uInt16 nFlags = nRes | SCA_VALID_TAB2; 1145 if (!lcl_ScRange_External_TabSpan( *pRange, nFlags, 1146 pExtInfo, aDocName, 1147 pExtInfo->maTabName, aTab, pDoc)) 1148 nRes &= ~SCA_VALID_TAB; 1149 else 1150 { 1151 if (nFlags & SCA_VALID_TAB2) 1152 { 1153 rAddr.SetTab( pRange->aEnd.Tab()); 1154 nRes |= SCA_VALID_TAB; 1155 } 1156 else 1157 nRes &= ~SCA_VALID_TAB; 1158 } 1159 } 1160 } 1161 } 1162 } 1163 } 1164 } 1165 1166 if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL) 1167 && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) ) 1168 { // no Row, no Tab, but Col => DM (...), B (...) et al 1169 nRes = 0; 1170 } 1171 if( !*p ) 1172 { 1173 sal_uInt16 nMask = nRes & ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ); 1174 if( nMask == ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ) ) 1175 nRes |= SCA_VALID; 1176 } 1177 else 1178 nRes = 0; 1179 return nRes; 1180 } 1181 1182 static sal_uInt16 1183 lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, 1184 const ScAddress::Details& rDetails, 1185 ScAddress::ExternalInfo* pExtInfo = NULL, 1186 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL ) 1187 { 1188 if( !*p ) 1189 return 0; 1190 1191 switch (rDetails.eConv) 1192 { 1193 default : 1194 case formula::FormulaGrammar::CONV_OOO: 1195 { 1196 return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo, NULL ); 1197 } 1198 1199 case formula::FormulaGrammar::CONV_XL_A1: 1200 case formula::FormulaGrammar::CONV_XL_OOX: 1201 { 1202 ScRange r = rAddr; 1203 sal_uInt16 nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, true, pExtInfo, 1204 (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) ); 1205 rAddr = r.aStart; 1206 return nFlags; 1207 } 1208 case formula::FormulaGrammar::CONV_XL_R1C1: 1209 { 1210 ScRange r = rAddr; 1211 sal_uInt16 nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, true, pExtInfo ); 1212 rAddr = r.aStart; 1213 return nFlags; 1214 } 1215 } 1216 } 1217 1218 1219 bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString, 1220 SCTAB nDefTab, ScRefAddress& rRefAddress, 1221 const ScAddress::Details& rDetails, 1222 ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) 1223 { 1224 bool bRet = false; 1225 if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) 1226 { 1227 ScAddress aAddr( 0, 0, nDefTab ); 1228 sal_uInt16 nRes = aAddr.Parse( rRefString, pDoc, rDetails, pExtInfo); 1229 if ( nRes & SCA_VALID ) 1230 { 1231 rRefAddress.Set( aAddr, 1232 ((nRes & SCA_COL_ABSOLUTE) == 0), 1233 ((nRes & SCA_ROW_ABSOLUTE) == 0), 1234 ((nRes & SCA_TAB_ABSOLUTE) == 0)); 1235 bRet = true; 1236 } 1237 } 1238 return bRet; 1239 } 1240 1241 1242 bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, 1243 ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress, 1244 const ScAddress::Details& rDetails, 1245 ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) 1246 { 1247 bool bRet = false; 1248 if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) 1249 { 1250 ScRange aRange( ScAddress( 0, 0, nDefTab)); 1251 sal_uInt16 nRes = aRange.Parse( rRefString, pDoc, rDetails, pExtInfo); 1252 if ( nRes & SCA_VALID ) 1253 { 1254 rStartRefAddress.Set( aRange.aStart, 1255 ((nRes & SCA_COL_ABSOLUTE) == 0), 1256 ((nRes & SCA_ROW_ABSOLUTE) == 0), 1257 ((nRes & SCA_TAB_ABSOLUTE) == 0)); 1258 rEndRefAddress.Set( aRange.aEnd, 1259 ((nRes & SCA_COL2_ABSOLUTE) == 0), 1260 ((nRes & SCA_ROW2_ABSOLUTE) == 0), 1261 ((nRes & SCA_TAB2_ABSOLUTE) == 0)); 1262 bRet = true; 1263 } 1264 } 1265 return bRet; 1266 } 1267 1268 1269 sal_uInt16 ScAddress::Parse( const String& r, ScDocument* pDoc, 1270 const Details& rDetails, 1271 ExternalInfo* pExtInfo, 1272 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 1273 { 1274 return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo, pExternalLinks ); 1275 } 1276 1277 1278 bool ScRange::Intersects( const ScRange& r ) const 1279 { 1280 return !( 1281 Min( aEnd.Col(), r.aEnd.Col() ) < Max( aStart.Col(), r.aStart.Col() ) 1282 || Min( aEnd.Row(), r.aEnd.Row() ) < Max( aStart.Row(), r.aStart.Row() ) 1283 || Min( aEnd.Tab(), r.aEnd.Tab() ) < Max( aStart.Tab(), r.aStart.Tab() ) 1284 ); 1285 } 1286 1287 1288 void ScRange::Justify() 1289 { 1290 SCCOL nTempCol; 1291 if ( aEnd.Col() < (nTempCol = aStart.Col()) ) 1292 { 1293 aStart.SetCol(aEnd.Col()); aEnd.SetCol(nTempCol); 1294 } 1295 SCROW nTempRow; 1296 if ( aEnd.Row() < (nTempRow = aStart.Row()) ) 1297 { 1298 aStart.SetRow(aEnd.Row()); aEnd.SetRow(nTempRow); 1299 } 1300 SCTAB nTempTab; 1301 if ( aEnd.Tab() < (nTempTab = aStart.Tab()) ) 1302 { 1303 aStart.SetTab(aEnd.Tab()); aEnd.SetTab(nTempTab); 1304 } 1305 } 1306 1307 void ScRange::ExtendTo( const ScRange& rRange ) 1308 { 1309 DBG_ASSERT( rRange.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" ); 1310 if( IsValid() ) 1311 { 1312 aStart.SetCol( ::std::min( aStart.Col(), rRange.aStart.Col() ) ); 1313 aStart.SetRow( ::std::min( aStart.Row(), rRange.aStart.Row() ) ); 1314 aStart.SetTab( ::std::min( aStart.Tab(), rRange.aStart.Tab() ) ); 1315 aEnd.SetCol( ::std::max( aEnd.Col(), rRange.aEnd.Col() ) ); 1316 aEnd.SetRow( ::std::max( aEnd.Row(), rRange.aEnd.Row() ) ); 1317 aEnd.SetTab( ::std::max( aEnd.Tab(), rRange.aEnd.Tab() ) ); 1318 } 1319 else 1320 *this = rRange; 1321 } 1322 1323 static sal_uInt16 1324 lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL ) 1325 { 1326 sal_uInt16 nRes1 = 0, nRes2 = 0; 1327 xub_StrLen nPos = ScGlobal::FindUnquoted( r, ':'); 1328 if (nPos != STRING_NOTFOUND) 1329 { 1330 String aTmp( r ); 1331 sal_Unicode* p = aTmp.GetBufferAccess(); 1332 p[ nPos ] = 0; 1333 if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo, NULL ) ) != 0 ) 1334 { 1335 aRange.aEnd = aRange.aStart; // sheet must be initialized identical to first sheet 1336 if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, pExtInfo, &aRange ) ) != 0 ) 1337 { 1338 // PutInOrder / Justify 1339 sal_uInt16 nMask, nBits1, nBits2; 1340 SCCOL nTempCol; 1341 if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) ) 1342 { 1343 aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol); 1344 nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE); 1345 nBits1 = nRes1 & nMask; 1346 nBits2 = nRes2 & nMask; 1347 nRes1 = (nRes1 & ~nMask) | nBits2; 1348 nRes2 = (nRes2 & ~nMask) | nBits1; 1349 } 1350 SCROW nTempRow; 1351 if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) ) 1352 { 1353 aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow); 1354 nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE); 1355 nBits1 = nRes1 & nMask; 1356 nBits2 = nRes2 & nMask; 1357 nRes1 = (nRes1 & ~nMask) | nBits2; 1358 nRes2 = (nRes2 & ~nMask) | nBits1; 1359 } 1360 SCTAB nTempTab; 1361 if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) ) 1362 { 1363 aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab); 1364 nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D); 1365 nBits1 = nRes1 & nMask; 1366 nBits2 = nRes2 & nMask; 1367 nRes1 = (nRes1 & ~nMask) | nBits2; 1368 nRes2 = (nRes2 & ~nMask) | nBits1; 1369 } 1370 if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) 1371 == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D )) 1372 && !(nRes2 & SCA_TAB_3D) ) 1373 nRes2 |= SCA_TAB_ABSOLUTE; 1374 } 1375 else 1376 nRes1 = 0; // #38840# keine Tokens aus halben Sachen 1377 } 1378 } 1379 nRes1 = ( ( nRes1 | nRes2 ) & SCA_VALID ) 1380 | nRes1 1381 | ( ( nRes2 & 0x070F ) << 4 ); 1382 return nRes1; 1383 } 1384 1385 sal_uInt16 ScRange::Parse( const String& r, ScDocument* pDoc, 1386 const ScAddress::Details& rDetails, 1387 ScAddress::ExternalInfo* pExtInfo, 1388 const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks ) 1389 { 1390 if ( r.Len() <= 0 ) 1391 return 0; 1392 1393 switch (rDetails.eConv) 1394 { 1395 default : 1396 case formula::FormulaGrammar::CONV_OOO: 1397 return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo ); 1398 1399 case formula::FormulaGrammar::CONV_XL_A1: 1400 case formula::FormulaGrammar::CONV_XL_OOX: 1401 return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, false, pExtInfo, 1402 (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) ); 1403 1404 case formula::FormulaGrammar::CONV_XL_R1C1: 1405 return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, false, pExtInfo ); 1406 } 1407 } 1408 1409 1410 // Accept a full range, or an address 1411 sal_uInt16 ScRange::ParseAny( const String& r, ScDocument* pDoc, 1412 const ScAddress::Details& rDetails ) 1413 { 1414 sal_uInt16 nRet = Parse( r, pDoc, rDetails ); 1415 const sal_uInt16 nValid = SCA_VALID | SCA_VALID_COL2 | SCA_VALID_ROW2 | 1416 SCA_VALID_TAB2; 1417 1418 if ( (nRet & nValid) != nValid ) 1419 { 1420 ScAddress aAdr; 1421 nRet = aAdr.Parse( r, pDoc, rDetails ); 1422 if ( nRet & SCA_VALID ) 1423 aStart = aEnd = aAdr; 1424 } 1425 return nRet; 1426 } 1427 1428 // Parse only full row references 1429 sal_uInt16 ScRange::ParseCols( const String& rStr, ScDocument* pDoc, 1430 const ScAddress::Details& rDetails ) 1431 { 1432 const sal_Unicode* p = rStr.GetBuffer(); 1433 sal_uInt16 nRes = 0, ignored = 0; 1434 1435 if( NULL == p ) 1436 return 0; 1437 1438 pDoc = NULL; // make compiler shutup we may need this later 1439 1440 switch (rDetails.eConv) 1441 { 1442 default : 1443 case formula::FormulaGrammar::CONV_OOO: // No full col refs in OOO yet, assume XL notation 1444 case formula::FormulaGrammar::CONV_XL_A1: 1445 case formula::FormulaGrammar::CONV_XL_OOX: 1446 if (NULL != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) ) 1447 { 1448 if( p[0] == ':') 1449 { 1450 if( NULL != (p = lcl_a1_get_col( p+1, &aEnd, &ignored ))) 1451 { 1452 nRes = SCA_VALID_COL; 1453 } 1454 } 1455 else 1456 { 1457 aEnd = aStart; 1458 nRes = SCA_VALID_COL; 1459 } 1460 } 1461 break; 1462 1463 case formula::FormulaGrammar::CONV_XL_R1C1: 1464 if ((p[0] == 'C' || p[0] != 'c') && 1465 NULL != (p = lcl_r1c1_get_col( p, rDetails, &aStart, &ignored ))) 1466 { 1467 if( p[0] == ':') 1468 { 1469 if( (p[1] == 'C' || p[1] == 'c') && 1470 NULL != (p = lcl_r1c1_get_col( p+1, rDetails, &aEnd, &ignored ))) 1471 { 1472 nRes = SCA_VALID_COL; 1473 } 1474 } 1475 else 1476 { 1477 aEnd = aStart; 1478 nRes = SCA_VALID_COL; 1479 } 1480 } 1481 break; 1482 } 1483 1484 return (p != NULL && *p == '\0') ? nRes : 0; 1485 } 1486 1487 // Parse only full row references 1488 sal_uInt16 ScRange::ParseRows( const String& rStr, ScDocument* pDoc, 1489 const ScAddress::Details& rDetails ) 1490 { 1491 const sal_Unicode* p = rStr.GetBuffer(); 1492 sal_uInt16 nRes = 0, ignored = 0; 1493 1494 if( NULL == p ) 1495 return 0; 1496 1497 pDoc = NULL; // make compiler shutup we may need this later 1498 1499 switch (rDetails.eConv) 1500 { 1501 default : 1502 case formula::FormulaGrammar::CONV_OOO: // No full row refs in OOO yet, assume XL notation 1503 case formula::FormulaGrammar::CONV_XL_A1: 1504 case formula::FormulaGrammar::CONV_XL_OOX: 1505 if (NULL != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) ) 1506 { 1507 if( p[0] == ':') 1508 { 1509 if( NULL != (p = lcl_a1_get_row( p+1, &aEnd, &ignored ))) 1510 { 1511 nRes = SCA_VALID_COL; 1512 } 1513 } 1514 else 1515 { 1516 aEnd = aStart; 1517 nRes = SCA_VALID_COL; 1518 } 1519 } 1520 break; 1521 1522 case formula::FormulaGrammar::CONV_XL_R1C1: 1523 if ((p[0] == 'R' || p[0] != 'r') && 1524 NULL != (p = lcl_r1c1_get_row( p, rDetails, &aStart, &ignored ))) 1525 { 1526 if( p[0] == ':') 1527 { 1528 if( (p[1] == 'R' || p[1] == 'r') && 1529 NULL != (p = lcl_r1c1_get_row( p+1, rDetails, &aEnd, &ignored ))) 1530 { 1531 nRes = SCA_VALID_COL; 1532 } 1533 } 1534 else 1535 { 1536 aEnd = aStart; 1537 nRes = SCA_VALID_COL; 1538 } 1539 } 1540 break; 1541 } 1542 1543 return (p != NULL && *p == '\0') ? nRes : 0; 1544 } 1545 1546 static inline void 1547 lcl_a1_append_c ( String &r, int nCol, bool bIsAbs ) 1548 { 1549 if( bIsAbs ) 1550 r += '$'; 1551 ScColToAlpha( r, sal::static_int_cast<SCCOL>(nCol) ); 1552 } 1553 1554 static inline void 1555 lcl_a1_append_r ( String &r, int nRow, bool bIsAbs ) 1556 { 1557 if ( bIsAbs ) 1558 r += '$'; 1559 r += String::CreateFromInt32( nRow+1 ); 1560 } 1561 1562 static inline void 1563 lcl_r1c1_append_c ( String &r, int nCol, bool bIsAbs, 1564 const ScAddress::Details& rDetails ) 1565 { 1566 r += 'C'; 1567 if (bIsAbs) 1568 { 1569 r += String::CreateFromInt32( nCol + 1 ); 1570 } 1571 else 1572 { 1573 nCol -= rDetails.nCol; 1574 if (nCol != 0) { 1575 r += '['; 1576 r += String::CreateFromInt32( nCol ); 1577 r += ']'; 1578 } 1579 } 1580 } 1581 static inline void 1582 lcl_r1c1_append_r ( String &r, int nRow, bool bIsAbs, 1583 const ScAddress::Details& rDetails ) 1584 { 1585 r += 'R'; 1586 if (bIsAbs) 1587 { 1588 r += String::CreateFromInt32( nRow + 1 ); 1589 } 1590 else 1591 { 1592 nRow -= rDetails.nRow; 1593 if (nRow != 0) { 1594 r += '['; 1595 r += String::CreateFromInt32( nRow ); 1596 r += ']'; 1597 } 1598 } 1599 } 1600 1601 static String 1602 getFileNameFromDoc( const ScDocument* pDoc ) 1603 { 1604 // TODO : er points at ScGlobal::GetAbsDocName() 1605 // as a better template. Look into it 1606 String sFileName; 1607 SfxObjectShell* pShell; 1608 1609 if( NULL != pDoc && 1610 NULL != (pShell = pDoc->GetDocumentShell() ) ) 1611 { 1612 uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY ); 1613 if( xModel.is() ) 1614 { 1615 if( xModel->getURL().getLength() ) 1616 { 1617 INetURLObject aURL( xModel->getURL() ); 1618 sFileName = aURL.GetLastName(); 1619 } 1620 else 1621 sFileName = pShell->GetTitle(); 1622 } 1623 } 1624 #if 0 1625 { 1626 ByteString aStr( sFileName, RTL_TEXTENCODING_UTF8 ); 1627 aStr.Append(static_cast< char >(0)); 1628 std::cerr << "docname \'" << aStr.GetBuffer() << '\'' << std::endl; 1629 } 1630 #endif 1631 return sFileName; 1632 } 1633 1634 void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, 1635 const Details& rDetails) const 1636 { 1637 r.Erase(); 1638 if( nFlags & SCA_VALID ) 1639 nFlags |= ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ); 1640 if( pDoc && (nFlags & SCA_VALID_TAB ) ) 1641 { 1642 if ( nTab >= pDoc->GetTableCount() ) 1643 { 1644 r = ScGlobal::GetRscString( STR_NOREF_STR ); 1645 return; 1646 } 1647 // if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) ) 1648 if( nFlags & SCA_TAB_3D ) 1649 { 1650 String aTabName, aDocName; 1651 pDoc->GetName( nTab, aTabName ); 1652 // External Reference, same as in ScCompiler::MakeTabStr() 1653 if( aTabName.GetChar(0) == '\'' ) 1654 { // "'Doc'#Tab" 1655 xub_StrLen nPos = ScCompiler::GetDocTabPos( aTabName); 1656 if (nPos != STRING_NOTFOUND) 1657 { 1658 aDocName = aTabName.Copy( 0, nPos + 1 ); 1659 aTabName.Erase( 0, nPos + 1 ); 1660 } 1661 } 1662 else if( nFlags & SCA_FORCE_DOC ) 1663 { 1664 // VBA has an 'external' flag that forces the addition of the 1665 // tab name _and_ the doc name. The VBA code would be 1666 // needlessly complicated if it constructed an actual external 1667 // reference so we add this somewhat cheesy kludge to force the 1668 // addition of the document name even for non-external references 1669 aDocName = getFileNameFromDoc( pDoc ); 1670 } 1671 ScCompiler::CheckTabQuotes( aTabName, rDetails.eConv); 1672 1673 switch( rDetails.eConv ) 1674 { 1675 default : 1676 case formula::FormulaGrammar::CONV_OOO: 1677 r += aDocName; 1678 if( nFlags & SCA_TAB_ABSOLUTE ) 1679 r += '$'; 1680 r += aTabName; 1681 r += '.'; 1682 break; 1683 1684 case formula::FormulaGrammar::CONV_XL_A1: 1685 case formula::FormulaGrammar::CONV_XL_R1C1: 1686 case formula::FormulaGrammar::CONV_XL_OOX: 1687 if (aDocName.Len() > 0) 1688 { 1689 r += '['; 1690 r += aDocName; 1691 r += ']'; 1692 } 1693 r += aTabName; 1694 r += '!'; 1695 break; 1696 } 1697 } 1698 } 1699 switch( rDetails.eConv ) 1700 { 1701 default : 1702 case formula::FormulaGrammar::CONV_OOO: 1703 case formula::FormulaGrammar::CONV_XL_A1: 1704 case formula::FormulaGrammar::CONV_XL_OOX: 1705 if( nFlags & SCA_VALID_COL ) 1706 lcl_a1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE ); 1707 if( nFlags & SCA_VALID_ROW ) 1708 lcl_a1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE ); 1709 break; 1710 1711 case formula::FormulaGrammar::CONV_XL_R1C1: 1712 if( nFlags & SCA_VALID_ROW ) 1713 lcl_r1c1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1714 if( nFlags & SCA_VALID_COL ) 1715 lcl_r1c1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE, rDetails ); 1716 break; 1717 } 1718 } 1719 1720 static void 1721 lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab, 1722 const ScAddress::Details& rDetails, 1723 sal_uInt16 nFlags, 1724 String& rTabName, String& rDocName ) 1725 { 1726 pDoc->GetName( nTab, rTabName ); 1727 rDocName.Erase(); 1728 #if 0 1729 { 1730 ByteString aStr(rTabName, RTL_TEXTENCODING_UTF8); 1731 aStr.Append(static_cast< char >(0)); 1732 std::cerr << "tabname \'" << aStr.GetBuffer() << '\'' << std::endl; 1733 } 1734 #endif 1735 // External reference, same as in ScCompiler::MakeTabStr() 1736 if ( rTabName.GetChar(0) == '\'' ) 1737 { // "'Doc'#Tab" 1738 xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); 1739 if (nPos != STRING_NOTFOUND) 1740 { 1741 rDocName = rTabName.Copy( 0, nPos + 1 ); 1742 rTabName.Erase( 0, nPos + 1 ); 1743 } 1744 } 1745 else if( nFlags & SCA_FORCE_DOC ) 1746 { 1747 // VBA has an 'external' flag that forces the addition of the 1748 // tab name _and_ the doc name. The VBA code would be 1749 // needlessly complicated if it constructed an actual external 1750 // reference so we add this somewhat cheesy kludge to force the 1751 // addition of the document name even for non-external references 1752 rDocName = getFileNameFromDoc( pDoc ); 1753 } 1754 ScCompiler::CheckTabQuotes( rTabName, rDetails.eConv); 1755 } 1756 1757 static void 1758 lcl_ScRange_Format_XL_Header( String& r, const ScRange& rRange, 1759 sal_uInt16 nFlags, ScDocument* pDoc, 1760 const ScAddress::Details& rDetails ) 1761 { 1762 if( nFlags & SCA_TAB_3D ) 1763 { 1764 String aTabName, aDocName; 1765 lcl_Split_DocTab( pDoc, rRange.aStart.Tab(), rDetails, nFlags, 1766 aTabName, aDocName ); 1767 if( aDocName.Len() > 0 ) 1768 { 1769 r += '['; 1770 r += aDocName; 1771 r += ']'; 1772 } 1773 r += aTabName; 1774 1775 if( nFlags & SCA_TAB2_3D ) 1776 { 1777 lcl_Split_DocTab( pDoc, rRange.aEnd.Tab(), rDetails, nFlags, 1778 aTabName, aDocName ); 1779 r += ':'; 1780 r += aTabName; 1781 } 1782 r += '!'; 1783 } 1784 } 1785 1786 void ScRange::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, 1787 const ScAddress::Details& rDetails ) const 1788 { 1789 r.Erase(); 1790 if( !( nFlags & SCA_VALID ) ) 1791 { 1792 r = ScGlobal::GetRscString( STR_NOREF_STR ); 1793 return; 1794 } 1795 1796 #define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask))) 1797 switch( rDetails.eConv ) { 1798 default : 1799 case formula::FormulaGrammar::CONV_OOO: { 1800 sal_Bool bOneTab = (aStart.Tab() == aEnd.Tab()); 1801 if ( !bOneTab ) 1802 nFlags |= SCA_TAB_3D; 1803 aStart.Format( r, nFlags, pDoc, rDetails ); 1804 if( aStart != aEnd || 1805 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1806 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) 1807 { 1808 String aName; 1809 nFlags = ( nFlags & SCA_VALID ) | ( ( nFlags >> 4 ) & 0x070F ); 1810 if ( bOneTab ) 1811 pDoc = NULL; 1812 else 1813 nFlags |= SCA_TAB_3D; 1814 aEnd.Format( aName, nFlags, pDoc, rDetails ); 1815 r += ':'; 1816 r += aName; 1817 } 1818 } 1819 break; 1820 1821 case formula::FormulaGrammar::CONV_XL_A1: 1822 case formula::FormulaGrammar::CONV_XL_OOX: 1823 lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails ); 1824 if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL ) 1825 { 1826 // Full col refs always require 2 rows (2:2) 1827 lcl_a1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE ); 1828 r += ':'; 1829 lcl_a1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE ); 1830 } 1831 else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW ) 1832 { 1833 // Full row refs always require 2 cols (A:A) 1834 lcl_a1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE ); 1835 r += ':'; 1836 lcl_a1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE ); 1837 } 1838 else 1839 { 1840 lcl_a1_append_c ( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE ); 1841 lcl_a1_append_r ( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE ); 1842 if( aStart.Col() != aEnd.Col() || 1843 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1844 aStart.Row() != aEnd.Row() || 1845 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1846 r += ':'; 1847 lcl_a1_append_c ( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE ); 1848 lcl_a1_append_r ( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE ); 1849 } 1850 } 1851 break; 1852 1853 case formula::FormulaGrammar::CONV_XL_R1C1: 1854 lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails ); 1855 if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL ) 1856 { 1857 lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1858 if( aStart.Row() != aEnd.Row() || 1859 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1860 r += ':'; 1861 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails ); 1862 } 1863 } 1864 else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW ) 1865 { 1866 lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails ); 1867 if( aStart.Col() != aEnd.Col() || 1868 absrel_differ( nFlags, SCA_COL_ABSOLUTE )) { 1869 r += ':'; 1870 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails ); 1871 } 1872 } 1873 else 1874 { 1875 lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails ); 1876 lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails ); 1877 if( aStart.Col() != aEnd.Col() || 1878 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) || 1879 aStart.Row() != aEnd.Row() || 1880 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) { 1881 r += ':'; 1882 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails ); 1883 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails ); 1884 } 1885 } 1886 } 1887 #undef absrel_differ 1888 } 1889 1890 bool ScAddress::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc ) 1891 { 1892 SCsTAB nMaxTab = pDoc ? pDoc->GetTableCount() : MAXTAB+1; 1893 dx = Col() + dx; 1894 dy = Row() + dy; 1895 dz = Tab() + dz; 1896 sal_Bool bValid = sal_True; 1897 if( dx < 0 ) 1898 dx = 0, bValid = sal_False; 1899 else if( dx > MAXCOL ) 1900 dx = MAXCOL, bValid =sal_False; 1901 if( dy < 0 ) 1902 dy = 0, bValid = sal_False; 1903 else if( dy > MAXROW ) 1904 dy = MAXROW, bValid =sal_False; 1905 if( dz < 0 ) 1906 dz = 0, bValid = sal_False; 1907 else if( dz >= nMaxTab ) 1908 dz = nMaxTab-1, bValid =sal_False; 1909 Set( dx, dy, dz ); 1910 return bValid; 1911 } 1912 1913 1914 bool ScRange::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc ) 1915 { 1916 // Einfahces &, damit beides ausgefuehrt wird!! 1917 return aStart.Move( dx, dy, dz, pDoc ) & aEnd.Move( dx, dy, dz, pDoc ); 1918 } 1919 1920 1921 String ScAddress::GetColRowString( bool bAbsolute, 1922 const Details& rDetails ) const 1923 { 1924 String aString; 1925 1926 switch( rDetails.eConv ) 1927 { 1928 default : 1929 case formula::FormulaGrammar::CONV_OOO: 1930 case formula::FormulaGrammar::CONV_XL_A1: 1931 case formula::FormulaGrammar::CONV_XL_OOX: 1932 if (bAbsolute) 1933 aString.Append( '$' ); 1934 1935 ScColToAlpha( aString, nCol); 1936 1937 if ( bAbsolute ) 1938 aString.Append( '$' ); 1939 1940 aString += String::CreateFromInt32(nRow+1); 1941 break; 1942 1943 case formula::FormulaGrammar::CONV_XL_R1C1: 1944 lcl_r1c1_append_r ( aString, nRow, bAbsolute, rDetails ); 1945 lcl_r1c1_append_c ( aString, nCol, bAbsolute, rDetails ); 1946 break; 1947 } 1948 1949 return aString; 1950 } 1951 1952 1953 String ScRefAddress::GetRefString( ScDocument* pDoc, SCTAB nActTab, 1954 const ScAddress::Details& rDetails ) const 1955 { 1956 if ( !pDoc ) 1957 return EMPTY_STRING; 1958 if ( Tab()+1 > pDoc->GetTableCount() ) 1959 return ScGlobal::GetRscString( STR_NOREF_STR ); 1960 1961 String aString; 1962 sal_uInt16 nFlags = SCA_VALID; 1963 if ( nActTab != Tab() ) 1964 { 1965 nFlags |= SCA_TAB_3D; 1966 if ( !bRelTab ) 1967 nFlags |= SCA_TAB_ABSOLUTE; 1968 } 1969 if ( !bRelCol ) 1970 nFlags |= SCA_COL_ABSOLUTE; 1971 if ( !bRelRow ) 1972 nFlags |= SCA_ROW_ABSOLUTE; 1973 1974 aAdr.Format( aString, nFlags, pDoc, rDetails ); 1975 1976 return aString; 1977 } 1978 1979 //------------------------------------------------------------------------ 1980 1981 void ScColToAlpha( rtl::OUStringBuffer& rBuf, SCCOL nCol ) 1982 { 1983 if (nCol < 26*26) 1984 { 1985 if (nCol < 26) 1986 rBuf.append( static_cast<sal_Unicode>( 'A' + 1987 static_cast<sal_uInt16>(nCol))); 1988 else 1989 { 1990 rBuf.append( static_cast<sal_Unicode>( 'A' + 1991 (static_cast<sal_uInt16>(nCol) / 26) - 1)); 1992 rBuf.append( static_cast<sal_Unicode>( 'A' + 1993 (static_cast<sal_uInt16>(nCol) % 26))); 1994 } 1995 } 1996 else 1997 { 1998 String aStr; 1999 while (nCol >= 26) 2000 { 2001 SCCOL nC = nCol % 26; 2002 aStr += static_cast<sal_Unicode>( 'A' + 2003 static_cast<sal_uInt16>(nC)); 2004 nCol = sal::static_int_cast<SCCOL>( nCol - nC ); 2005 nCol = nCol / 26 - 1; 2006 } 2007 aStr += static_cast<sal_Unicode>( 'A' + 2008 static_cast<sal_uInt16>(nCol)); 2009 aStr.Reverse(); 2010 rBuf.append( aStr); 2011 } 2012 } 2013 2014 2015 bool AlphaToCol( SCCOL& rCol, const String& rStr) 2016 { 2017 SCCOL nResult = 0; 2018 xub_StrLen nStop = rStr.Len(); 2019 xub_StrLen nPos = 0; 2020 sal_Unicode c; 2021 while (nResult <= MAXCOL && nPos < nStop && (c = rStr.GetChar( nPos)) != 0 && 2022 CharClass::isAsciiAlpha(c)) 2023 { 2024 if (nPos > 0) 2025 nResult = (nResult + 1) * 26; 2026 nResult += ScGlobal::ToUpperAlpha(c) - 'A'; 2027 ++nPos; 2028 } 2029 bool bOk = (ValidCol(nResult) && nPos > 0); 2030 if (bOk) 2031 rCol = nResult; 2032 return bOk; 2033 } 2034