1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_svl.hxx" 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <float.h> 29 // #include <math.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <tools/debug.hxx> 33 #include <i18npool/mslangid.hxx> 34 #include <rtl/math.hxx> 35 #include <rtl/instance.hxx> 36 #include <unotools/charclass.hxx> 37 #include <unotools/calendarwrapper.hxx> 38 #include <unotools/nativenumberwrapper.hxx> 39 #include <com/sun/star/i18n/CalendarFieldIndex.hpp> 40 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> 41 #include <com/sun/star/i18n/CalendarDisplayCode.hpp> 42 #include <com/sun/star/i18n/AmPmValue.hpp> 43 44 #define _ZFORMAT_CXX 45 #include <svl/zformat.hxx> 46 #include <zforscan.hxx> 47 48 #include "zforfind.hxx" 49 #include <svl/zforlist.hxx> 50 #include "numhead.hxx" 51 #include <unotools/digitgroupingiterator.hxx> 52 #include <svl/nfsymbol.hxx> 53 54 #include <cmath> 55 56 using namespace svt; 57 58 namespace { 59 struct Gregorian 60 : public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> { 61 const ::rtl::OUString operator () () { 62 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian")); 63 } 64 }; 65 66 const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary... 67 const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value. 68 69 } 70 71 const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0 72 const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0 73 const sal_uInt16 _MAX_FRACTION_PREC = 3; 74 const double D_EPS = 1.0E-2; 75 76 const double _D_MAX_D_BY_100 = 1.7E306; 77 const double _D_MIN_M_BY_1000 = 2.3E-305; 78 79 static sal_uInt8 cCharWidths[ 128-32 ] = { 80 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1, 81 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2, 82 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3, 83 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2, 84 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2, 85 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1 86 }; 87 88 // static 89 xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c ) 90 { 91 if( c >= 32 ) 92 { 93 sal_uInt16 n = 2; // Default fuer Zeichen > 128 (HACK!) 94 if( c <= 127 ) 95 n = cCharWidths[ c - 32 ]; 96 while( n-- ) 97 r.Insert( ' ', nPos++ ); 98 } 99 return nPos; 100 } 101 102 static long GetPrecExp( double fAbsVal ) 103 { 104 DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" ); 105 if ( fAbsVal < 1e-7 || fAbsVal > 1e7 ) 106 { // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7 107 return (long) floor( log10( fAbsVal ) ) + 1; 108 } 109 else 110 { 111 long nPrecExp = 1; 112 while( fAbsVal < 1 ) 113 { 114 fAbsVal *= 10; 115 nPrecExp--; 116 } 117 while( fAbsVal >= 10 ) 118 { 119 fAbsVal /= 10; 120 nPrecExp++; 121 } 122 return nPrecExp; 123 } 124 } 125 126 const sal_uInt16 nNewCurrencyVersionId = 0x434E; // "NC" 127 const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment 128 const sal_uInt16 nNewStandardFlagVersionId = 0x4653; // "SF" 129 130 /***********************Funktion SvNumberformatInfo******************************/ 131 132 void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz ) 133 { 134 for (sal_uInt16 i = 0; i < nAnz; i++) 135 { 136 sStrArray[i] = rNumFor.sStrArray[i]; 137 nTypeArray[i] = rNumFor.nTypeArray[i]; 138 } 139 eScannedType = rNumFor.eScannedType; 140 bThousand = rNumFor.bThousand; 141 nThousand = rNumFor.nThousand; 142 nCntPre = rNumFor.nCntPre; 143 nCntPost = rNumFor.nCntPost; 144 nCntExp = rNumFor.nCntExp; 145 } 146 147 void ImpSvNumberformatInfo::Save(SvStream& rStream, sal_uInt16 nAnz) const 148 { 149 for (sal_uInt16 i = 0; i < nAnz; i++) 150 { 151 rStream.WriteByteString( sStrArray[i], rStream.GetStreamCharSet() ); 152 short nType = nTypeArray[i]; 153 switch ( nType ) 154 { // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR 155 case NF_SYMBOLTYPE_CURRENCY : 156 rStream << short( NF_SYMBOLTYPE_STRING ); 157 break; 158 case NF_SYMBOLTYPE_CURRDEL : 159 case NF_SYMBOLTYPE_CURREXT : 160 rStream << short(0); // werden ignoriert (hoffentlich..) 161 break; 162 default: 163 if ( nType > NF_KEY_LASTKEYWORD_SO5 ) 164 rStream << short( NF_SYMBOLTYPE_STRING ); // all new keywords are string 165 else 166 rStream << nType; 167 } 168 169 } 170 rStream << eScannedType << bThousand << nThousand 171 << nCntPre << nCntPost << nCntExp; 172 } 173 174 void ImpSvNumberformatInfo::Load(SvStream& rStream, sal_uInt16 nAnz) 175 { 176 for (sal_uInt16 i = 0; i < nAnz; i++) 177 { 178 SvNumberformat::LoadString( rStream, sStrArray[i] ); 179 rStream >> nTypeArray[i]; 180 } 181 rStream >> eScannedType >> bThousand >> nThousand 182 >> nCntPre >> nCntPost >> nCntExp; 183 } 184 185 186 //============================================================================ 187 188 // static 189 sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, sal_Bool bDate ) 190 { 191 sal_uInt8 nNatNum = 0; 192 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. 193 eLang &= 0x03FF; // 10 bit primary language 194 if ( bDate ) 195 { 196 if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN ) 197 nNatNum = 9; 198 else if ( nDBNum <= 3 ) 199 nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3 200 } 201 else 202 { 203 switch ( nDBNum ) 204 { 205 case 1: 206 switch ( eLang ) 207 { 208 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 4; break; 209 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break; 210 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 1; break; 211 } 212 break; 213 case 2: 214 switch ( eLang ) 215 { 216 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 5; break; 217 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break; 218 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 2; break; 219 } 220 break; 221 case 3: 222 switch ( eLang ) 223 { 224 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 6; break; 225 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break; 226 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 3; break; 227 } 228 break; 229 case 4: 230 switch ( eLang ) 231 { 232 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break; 233 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 9; break; 234 } 235 break; 236 } 237 } 238 return nNatNum; 239 } 240 241 242 // static 243 sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, sal_Bool bDate ) 244 { 245 sal_uInt8 nDBNum = 0; 246 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. 247 eLang &= 0x03FF; // 10 bit primary language 248 if ( bDate ) 249 { 250 if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN ) 251 nDBNum = 4; 252 else if ( nNatNum <= 3 ) 253 nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3 254 } 255 else 256 { 257 switch ( nNatNum ) 258 { 259 case 1: 260 switch ( eLang ) 261 { 262 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break; 263 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 1; break; 264 } 265 break; 266 case 2: 267 switch ( eLang ) 268 { 269 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 2; break; 270 } 271 break; 272 case 3: 273 switch ( eLang ) 274 { 275 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 3; break; 276 } 277 break; 278 case 4: 279 switch ( eLang ) 280 { 281 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 1; break; 282 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break; 283 } 284 break; 285 case 5: 286 switch ( eLang ) 287 { 288 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 2; break; 289 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break; 290 } 291 break; 292 case 6: 293 switch ( eLang ) 294 { 295 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 3; break; 296 } 297 break; 298 case 7: 299 switch ( eLang ) 300 { 301 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break; 302 } 303 break; 304 case 8: 305 break; 306 case 9: 307 switch ( eLang ) 308 { 309 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 4; break; 310 } 311 break; 312 case 10: 313 break; 314 case 11: 315 break; 316 } 317 } 318 return nDBNum; 319 } 320 321 /***********************Funktionen SvNumFor******************************/ 322 323 ImpSvNumFor::ImpSvNumFor() 324 { 325 nAnzStrings = 0; 326 aI.nTypeArray = NULL; 327 aI.sStrArray = NULL; 328 aI.eScannedType = NUMBERFORMAT_UNDEFINED; 329 aI.bThousand = sal_False; 330 aI.nThousand = 0; 331 aI.nCntPre = 0; 332 aI.nCntPost = 0; 333 aI.nCntExp = 0; 334 pColor = NULL; 335 } 336 337 ImpSvNumFor::~ImpSvNumFor() 338 { 339 for (sal_uInt16 i = 0; i < nAnzStrings; i++) 340 aI.sStrArray[i].Erase(); 341 delete [] aI.sStrArray; 342 delete [] aI.nTypeArray; 343 } 344 345 void ImpSvNumFor::Enlarge(sal_uInt16 nAnz) 346 { 347 if ( nAnzStrings != nAnz ) 348 { 349 if ( aI.nTypeArray ) 350 delete [] aI.nTypeArray; 351 if ( aI.sStrArray ) 352 delete [] aI.sStrArray; 353 nAnzStrings = nAnz; 354 if ( nAnz ) 355 { 356 aI.nTypeArray = new short[nAnz]; 357 aI.sStrArray = new String[nAnz]; 358 } 359 else 360 { 361 aI.nTypeArray = NULL; 362 aI.sStrArray = NULL; 363 } 364 } 365 } 366 367 void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc ) 368 { 369 Enlarge( rNumFor.nAnzStrings ); 370 aI.Copy( rNumFor.aI, nAnzStrings ); 371 sColorName = rNumFor.sColorName; 372 if ( pSc ) 373 pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents 374 else 375 pColor = rNumFor.pColor; 376 aNatNum = rNumFor.aNatNum; 377 } 378 379 void ImpSvNumFor::Save(SvStream& rStream) const 380 { 381 rStream << nAnzStrings; 382 aI.Save(rStream, nAnzStrings); 383 rStream.WriteByteString( sColorName, rStream.GetStreamCharSet() ); 384 } 385 386 void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc, 387 String& rLoadedColorName ) 388 { 389 sal_uInt16 nAnz; 390 rStream >> nAnz; //! noch nicht direkt nAnzStrings wg. Enlarge 391 Enlarge( nAnz ); 392 aI.Load( rStream, nAnz ); 393 rStream.ReadByteString( sColorName, rStream.GetStreamCharSet() ); 394 rLoadedColorName = sColorName; 395 pColor = rSc.GetColor(sColorName); 396 } 397 398 399 sal_Bool ImpSvNumFor::HasNewCurrency() const 400 { 401 for ( sal_uInt16 j=0; j<nAnzStrings; j++ ) 402 { 403 if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) 404 return sal_True; 405 } 406 return sal_False; 407 } 408 409 bool ImpSvNumFor::HasTextFormatCode() const 410 { 411 return aI.eScannedType == NUMBERFORMAT_TEXT; 412 } 413 414 sal_Bool ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol, 415 String& rExtension ) const 416 { 417 for ( sal_uInt16 j=0; j<nAnzStrings; j++ ) 418 { 419 if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) 420 { 421 rSymbol = aI.sStrArray[j]; 422 if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT ) 423 rExtension = aI.sStrArray[j+1]; 424 else 425 rExtension.Erase(); 426 return sal_True; 427 } 428 } 429 //! kein Erase an rSymbol, rExtension 430 return sal_False; 431 } 432 433 434 void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const 435 { 436 sal_uInt16 j; 437 sal_uInt16 nCnt = 0; 438 for ( j=0; j<nAnzStrings; j++ ) 439 { 440 switch ( aI.nTypeArray[j] ) 441 { 442 case NF_SYMBOLTYPE_CURRENCY : 443 case NF_SYMBOLTYPE_CURRDEL : 444 case NF_SYMBOLTYPE_CURREXT : 445 nCnt++; 446 break; 447 } 448 } 449 rStream << nCnt; 450 for ( j=0; j<nAnzStrings; j++ ) 451 { 452 switch ( aI.nTypeArray[j] ) 453 { 454 case NF_SYMBOLTYPE_CURRENCY : 455 case NF_SYMBOLTYPE_CURRDEL : 456 case NF_SYMBOLTYPE_CURREXT : 457 rStream << j << aI.nTypeArray[j]; 458 break; 459 } 460 } 461 } 462 463 464 void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream ) 465 { 466 sal_uInt16 nCnt; 467 rStream >> nCnt; 468 for ( sal_uInt16 j=0; j<nCnt; j++ ) 469 { 470 sal_uInt16 nPos; 471 short nType; 472 rStream >> nPos >> nType; 473 if ( nPos < nAnzStrings ) 474 aI.nTypeArray[nPos] = nType; 475 } 476 } 477 478 479 /***********************Funktionen SvNumberformat************************/ 480 481 enum BracketFormatSymbolType 482 { 483 BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string 484 BRACKET_SYMBOLTYPE_COLOR = -2, // color 485 BRACKET_SYMBOLTYPE_ERROR = -3, // error 486 BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers 487 BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible. 488 BRACKET_SYMBOLTYPE_DBNUM3 = -6, 489 BRACKET_SYMBOLTYPE_DBNUM4 = -7, 490 BRACKET_SYMBOLTYPE_DBNUM5 = -8, 491 BRACKET_SYMBOLTYPE_DBNUM6 = -9, 492 BRACKET_SYMBOLTYPE_DBNUM7 = -10, 493 BRACKET_SYMBOLTYPE_DBNUM8 = -11, 494 BRACKET_SYMBOLTYPE_DBNUM9 = -12, 495 BRACKET_SYMBOLTYPE_LOCALE = -13, 496 BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII 497 BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent 498 BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ... 499 BRACKET_SYMBOLTYPE_NATNUM3 = -17, 500 BRACKET_SYMBOLTYPE_NATNUM4 = -18, 501 BRACKET_SYMBOLTYPE_NATNUM5 = -19, 502 BRACKET_SYMBOLTYPE_NATNUM6 = -20, 503 BRACKET_SYMBOLTYPE_NATNUM7 = -21, 504 BRACKET_SYMBOLTYPE_NATNUM8 = -22, 505 BRACKET_SYMBOLTYPE_NATNUM9 = -23, 506 BRACKET_SYMBOLTYPE_NATNUM10 = -24, 507 BRACKET_SYMBOLTYPE_NATNUM11 = -25, 508 BRACKET_SYMBOLTYPE_NATNUM12 = -26, 509 BRACKET_SYMBOLTYPE_NATNUM13 = -27, 510 BRACKET_SYMBOLTYPE_NATNUM14 = -28, 511 BRACKET_SYMBOLTYPE_NATNUM15 = -29, 512 BRACKET_SYMBOLTYPE_NATNUM16 = -30, 513 BRACKET_SYMBOLTYPE_NATNUM17 = -31, 514 BRACKET_SYMBOLTYPE_NATNUM18 = -32, 515 BRACKET_SYMBOLTYPE_NATNUM19 = -33 516 }; 517 518 SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge ) 519 : 520 rScan(rSc), 521 eLnge(eLge), 522 nNewStandardDefined(0), 523 bStarFlag( sal_False ) 524 { 525 } 526 527 void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat ) 528 { 529 sFormatstring = rFormat.sFormatstring; 530 eType = rFormat.eType; 531 eLnge = rFormat.eLnge; 532 fLimit1 = rFormat.fLimit1; 533 fLimit2 = rFormat.fLimit2; 534 eOp1 = rFormat.eOp1; 535 eOp2 = rFormat.eOp2; 536 bStandard = rFormat.bStandard; 537 bIsUsed = rFormat.bIsUsed; 538 sComment = rFormat.sComment; 539 nNewStandardDefined = rFormat.nNewStandardDefined; 540 541 // #121103# when copying between documents, get color pointers from own scanner 542 ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL; 543 544 for (sal_uInt16 i = 0; i < 4; i++) 545 NumFor[i].Copy(rFormat.NumFor[i], pColorSc); 546 } 547 548 SvNumberformat::SvNumberformat( SvNumberformat& rFormat ) 549 : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag ) 550 { 551 ImpCopyNumberformat( rFormat ); 552 } 553 554 SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc ) 555 : rScan(rSc), bStarFlag( rFormat.bStarFlag ) 556 { 557 ImpCopyNumberformat( rFormat ); 558 } 559 560 561 sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType ) 562 { 563 if ( nSymbolType > 0 ) 564 return sal_True; // conditions 565 switch ( nSymbolType ) 566 { 567 case BRACKET_SYMBOLTYPE_COLOR : 568 case BRACKET_SYMBOLTYPE_DBNUM1 : 569 case BRACKET_SYMBOLTYPE_DBNUM2 : 570 case BRACKET_SYMBOLTYPE_DBNUM3 : 571 case BRACKET_SYMBOLTYPE_DBNUM4 : 572 case BRACKET_SYMBOLTYPE_DBNUM5 : 573 case BRACKET_SYMBOLTYPE_DBNUM6 : 574 case BRACKET_SYMBOLTYPE_DBNUM7 : 575 case BRACKET_SYMBOLTYPE_DBNUM8 : 576 case BRACKET_SYMBOLTYPE_DBNUM9 : 577 case BRACKET_SYMBOLTYPE_LOCALE : 578 case BRACKET_SYMBOLTYPE_NATNUM0 : 579 case BRACKET_SYMBOLTYPE_NATNUM1 : 580 case BRACKET_SYMBOLTYPE_NATNUM2 : 581 case BRACKET_SYMBOLTYPE_NATNUM3 : 582 case BRACKET_SYMBOLTYPE_NATNUM4 : 583 case BRACKET_SYMBOLTYPE_NATNUM5 : 584 case BRACKET_SYMBOLTYPE_NATNUM6 : 585 case BRACKET_SYMBOLTYPE_NATNUM7 : 586 case BRACKET_SYMBOLTYPE_NATNUM8 : 587 case BRACKET_SYMBOLTYPE_NATNUM9 : 588 case BRACKET_SYMBOLTYPE_NATNUM10 : 589 case BRACKET_SYMBOLTYPE_NATNUM11 : 590 case BRACKET_SYMBOLTYPE_NATNUM12 : 591 case BRACKET_SYMBOLTYPE_NATNUM13 : 592 case BRACKET_SYMBOLTYPE_NATNUM14 : 593 case BRACKET_SYMBOLTYPE_NATNUM15 : 594 case BRACKET_SYMBOLTYPE_NATNUM16 : 595 case BRACKET_SYMBOLTYPE_NATNUM17 : 596 case BRACKET_SYMBOLTYPE_NATNUM18 : 597 case BRACKET_SYMBOLTYPE_NATNUM19 : 598 return sal_True; 599 } 600 return sal_False; 601 } 602 603 604 SvNumberformat::SvNumberformat(String& rString, 605 ImpSvNumberformatScan* pSc, 606 ImpSvNumberInputScan* pISc, 607 xub_StrLen& nCheckPos, 608 LanguageType& eLan, 609 sal_Bool bStan) 610 : 611 rScan(*pSc), 612 nNewStandardDefined(0), 613 bStarFlag( sal_False ) 614 { 615 // If the group (AKA thousand) separator is a Non-Breaking Space (French) 616 // replace all occurences by a simple space. 617 // The tokens will be changed to the LocaleData separator again later on. 618 const sal_Unicode cNBSp = 0xA0; 619 const String& rThSep = GetFormatter().GetNumThousandSep(); 620 if ( rThSep.GetChar(0) == cNBSp && rThSep.Len() == 1 ) 621 { 622 xub_StrLen nIndex = 0; 623 do 624 nIndex = rString.SearchAndReplace( cNBSp, ' ', nIndex ); 625 while ( nIndex != STRING_NOTFOUND ); 626 } 627 628 if (rScan.GetConvertMode()) 629 { 630 eLnge = rScan.GetNewLnge(); 631 eLan = eLnge; // Wechsel auch zurueckgeben 632 } 633 else 634 eLnge = eLan; 635 bStandard = bStan; 636 bIsUsed = sal_False; 637 fLimit1 = 0.0; 638 fLimit2 = 0.0; 639 eOp1 = NUMBERFORMAT_OP_NO; 640 eOp2 = NUMBERFORMAT_OP_NO; 641 eType = NUMBERFORMAT_DEFINED; 642 643 sal_Bool bCancel = sal_False; 644 sal_Bool bCondition = sal_False; 645 short eSymbolType; 646 xub_StrLen nPos = 0; 647 xub_StrLen nPosOld; 648 nCheckPos = 0; 649 String aComment; 650 651 // Split into 4 sub formats 652 sal_uInt16 nIndex; 653 for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ ) 654 { 655 // Original language/country may have to be reestablished 656 if (rScan.GetConvertMode()) 657 (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge()); 658 659 String sStr; 660 nPosOld = nPos; // Start position of substring 661 // first get bracketed prefixes; e.g. conditions, color 662 do 663 { 664 eSymbolType = ImpNextSymbol(rString, nPos, sStr); 665 if (eSymbolType > 0) // condition 666 { 667 if ( nIndex == 0 && !bCondition ) 668 { 669 bCondition = sal_True; 670 eOp1 = (SvNumberformatLimitOps) eSymbolType; 671 } 672 else if ( nIndex == 1 && bCondition ) 673 eOp2 = (SvNumberformatLimitOps) eSymbolType; 674 else // error 675 { 676 bCancel = sal_True; // break for 677 nCheckPos = nPosOld; 678 } 679 if (!bCancel) 680 { 681 double fNumber; 682 xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr); 683 if (nAnzChars > 0) 684 { 685 short F_Type = NUMBERFORMAT_UNDEFINED; 686 if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) || 687 ( F_Type != NUMBERFORMAT_NUMBER && 688 F_Type != NUMBERFORMAT_SCIENTIFIC) ) 689 { 690 fNumber = 0.0; 691 nPos = nPos - nAnzChars; 692 rString.Erase(nPos, nAnzChars); 693 rString.Insert('0',nPos); 694 nPos++; 695 } 696 } 697 else 698 { 699 fNumber = 0.0; 700 rString.Insert('0',nPos++); 701 } 702 if (nIndex == 0) 703 fLimit1 = fNumber; 704 else 705 fLimit2 = fNumber; 706 if ( rString.GetChar(nPos) == ']' ) 707 nPos++; 708 else 709 { 710 bCancel = sal_True; // break for 711 nCheckPos = nPos; 712 } 713 } 714 nPosOld = nPos; // position before string 715 } 716 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) 717 { 718 switch ( eSymbolType ) 719 { 720 case BRACKET_SYMBOLTYPE_COLOR : 721 { 722 if ( NumFor[nIndex].GetColor() != NULL ) 723 { // error, more than one color 724 bCancel = sal_True; // break for 725 nCheckPos = nPosOld; 726 } 727 else 728 { 729 Color* pColor = pSc->GetColor( sStr); 730 NumFor[nIndex].SetColor( pColor, sStr); 731 if (pColor == NULL) 732 { // error 733 bCancel = sal_True; // break for 734 nCheckPos = nPosOld; 735 } 736 } 737 } 738 break; 739 case BRACKET_SYMBOLTYPE_NATNUM0 : 740 case BRACKET_SYMBOLTYPE_NATNUM1 : 741 case BRACKET_SYMBOLTYPE_NATNUM2 : 742 case BRACKET_SYMBOLTYPE_NATNUM3 : 743 case BRACKET_SYMBOLTYPE_NATNUM4 : 744 case BRACKET_SYMBOLTYPE_NATNUM5 : 745 case BRACKET_SYMBOLTYPE_NATNUM6 : 746 case BRACKET_SYMBOLTYPE_NATNUM7 : 747 case BRACKET_SYMBOLTYPE_NATNUM8 : 748 case BRACKET_SYMBOLTYPE_NATNUM9 : 749 case BRACKET_SYMBOLTYPE_NATNUM10 : 750 case BRACKET_SYMBOLTYPE_NATNUM11 : 751 case BRACKET_SYMBOLTYPE_NATNUM12 : 752 case BRACKET_SYMBOLTYPE_NATNUM13 : 753 case BRACKET_SYMBOLTYPE_NATNUM14 : 754 case BRACKET_SYMBOLTYPE_NATNUM15 : 755 case BRACKET_SYMBOLTYPE_NATNUM16 : 756 case BRACKET_SYMBOLTYPE_NATNUM17 : 757 case BRACKET_SYMBOLTYPE_NATNUM18 : 758 case BRACKET_SYMBOLTYPE_NATNUM19 : 759 { 760 if ( NumFor[nIndex].GetNatNum().IsSet() ) 761 { 762 bCancel = sal_True; // break for 763 nCheckPos = nPosOld; 764 } 765 else 766 { 767 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) ); 768 //! eSymbolType is negative 769 sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0)); 770 sStr += String::CreateFromInt32( nNum ); 771 NumFor[nIndex].SetNatNumNum( nNum, sal_False ); 772 } 773 } 774 break; 775 case BRACKET_SYMBOLTYPE_DBNUM1 : 776 case BRACKET_SYMBOLTYPE_DBNUM2 : 777 case BRACKET_SYMBOLTYPE_DBNUM3 : 778 case BRACKET_SYMBOLTYPE_DBNUM4 : 779 case BRACKET_SYMBOLTYPE_DBNUM5 : 780 case BRACKET_SYMBOLTYPE_DBNUM6 : 781 case BRACKET_SYMBOLTYPE_DBNUM7 : 782 case BRACKET_SYMBOLTYPE_DBNUM8 : 783 case BRACKET_SYMBOLTYPE_DBNUM9 : 784 { 785 if ( NumFor[nIndex].GetNatNum().IsSet() ) 786 { 787 bCancel = sal_True; // break for 788 nCheckPos = nPosOld; 789 } 790 else 791 { 792 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) ); 793 //! eSymbolType is negative 794 sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1)); 795 sStr += static_cast< sal_Unicode >('0' + nNum); 796 NumFor[nIndex].SetNatNumNum( nNum, sal_True ); 797 } 798 } 799 break; 800 case BRACKET_SYMBOLTYPE_LOCALE : 801 { 802 if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ) 803 { 804 bCancel = sal_True; // break for 805 nCheckPos = nPosOld; 806 } 807 else 808 { 809 xub_StrLen nTmp = 2; 810 LanguageType eLang = ImpGetLanguageType( sStr, nTmp ); 811 if ( eLang == LANGUAGE_DONTKNOW ) 812 { 813 bCancel = sal_True; // break for 814 nCheckPos = nPosOld; 815 } 816 else 817 { 818 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) ); 819 sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii(); 820 NumFor[nIndex].SetNatNumLang( eLang ); 821 } 822 } 823 } 824 break; 825 } 826 if ( !bCancel ) 827 { 828 rString.Erase(nPosOld,nPos-nPosOld); 829 rString.Insert(sStr,nPosOld); 830 nPos = nPosOld + sStr.Len(); 831 rString.Insert(']', nPos); 832 rString.Insert('[', nPosOld); 833 nPos += 2; 834 nPosOld = nPos; // position before string 835 } 836 } 837 } while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ); 838 839 // The remaining format code string 840 if ( !bCancel ) 841 { 842 if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT) 843 { 844 if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO) 845 eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0 846 else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO) 847 eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0 848 if (sStr.Len() == 0) 849 { // empty sub format 850 } 851 else 852 { 853 xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment ); 854 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 855 if (nAnz == 0) // error 856 nStrPos = 1; 857 if (nStrPos == 0) // ok 858 { 859 // e.g. Thai T speciality 860 if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet()) 861 { 862 String aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum")); 863 aNat += String::CreateFromInt32( pSc->GetNatNumModifier()); 864 aNat += ']'; 865 sStr.Insert( aNat, 0); 866 NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), sal_False ); 867 } 868 // #i53826# #i42727# For the Thai T speciality we need 869 // to freeze the locale and immunize it against 870 // conversions during exports, just in case we want to 871 // save to Xcl. This disables the feature of being able 872 // to convert a NatNum to another locale. You can't 873 // have both. 874 // FIXME: implement a specialized export conversion 875 // that works on tokens (have to tokenize all first) 876 // and doesn't use the format string and 877 // PutandConvertEntry() to LANGUAGE_ENGLISH_US in 878 // sc/source/filter/excel/xestyle.cxx 879 // XclExpNumFmtBuffer::WriteFormatRecord(). 880 LanguageType eLanguage; 881 if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 && 882 ((eLanguage = 883 MsLangId::getRealLanguage( eLan)) 884 == LANGUAGE_THAI) && 885 NumFor[nIndex].GetNatNum().GetLang() == 886 LANGUAGE_DONTKNOW) 887 { 888 String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-")); 889 aLID += String::CreateFromInt32( sal_Int32( 890 eLanguage), 16 ).ToUpperAscii(); 891 aLID += ']'; 892 sStr.Insert( aLID, 0); 893 NumFor[nIndex].SetNatNumLang( eLanguage); 894 } 895 rString.Erase(nPosOld,nPos-nPosOld); 896 rString.Insert(sStr,nPosOld); 897 nPos = nPosOld + sStr.Len(); 898 if (nPos < rString.Len()) 899 { 900 rString.Insert(';',nPos); 901 nPos++; 902 } 903 NumFor[nIndex].Enlarge(nAnz); 904 pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz); 905 // type check 906 if (nIndex == 0) 907 eType = (short) NumFor[nIndex].Info().eScannedType; 908 else if (nIndex == 3) 909 { // #77026# Everything recognized IS text 910 NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT; 911 } 912 else if ( (short) NumFor[nIndex].Info().eScannedType != 913 eType) 914 eType = NUMBERFORMAT_DEFINED; 915 } 916 else 917 { 918 nCheckPos = nPosOld + nStrPos; // error in string 919 bCancel = sal_True; // break for 920 } 921 } 922 } 923 else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error 924 { 925 nCheckPos = nPosOld; 926 bCancel = sal_True; 927 } 928 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) 929 { 930 nCheckPos = nPosOld+1; // error, prefix in string 931 bCancel = sal_True; // break for 932 } 933 } 934 if ( bCancel && !nCheckPos ) 935 nCheckPos = 1; // nCheckPos is used as an error condition 936 if ( !bCancel ) 937 { 938 if ( NumFor[nIndex].GetNatNum().IsSet() && 939 NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW ) 940 NumFor[nIndex].SetNatNumLang( eLan ); 941 } 942 if (rString.Len() == nPos) 943 { 944 if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT && 945 rString.GetChar(nPos-1) == ';' ) 946 { // #83510# A 4th subformat explicitly specified to be empty 947 // hides any text. Need the type here for HasTextFormat() 948 NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT; 949 } 950 bCancel = sal_True; 951 } 952 if ( NumFor[nIndex].GetNatNum().IsSet() ) 953 NumFor[nIndex].SetNatNumDate( 954 (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 ); 955 } 956 957 if ( bCondition && !nCheckPos ) 958 { 959 if ( nIndex == 1 && NumFor[0].GetnAnz() == 0 && 960 rString.GetChar(rString.Len()-1) != ';' ) 961 { // No format code => GENERAL but not if specified empty 962 String aAdd( pSc->GetStandardName() ); 963 String aTmp; 964 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 965 { 966 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 967 if ( nAnz ) 968 { 969 NumFor[0].Enlarge(nAnz); 970 pSc->CopyInfo( &(NumFor[0].Info()), nAnz ); 971 rString += aAdd; 972 } 973 } 974 } 975 else if ( nIndex == 1 && NumFor[nIndex].GetnAnz() == 0 && 976 rString.GetChar(rString.Len()-1) != ';' && 977 (NumFor[0].GetnAnz() > 1 || (NumFor[0].GetnAnz() == 1 && 978 NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) ) 979 { // No trailing second subformat => GENERAL but not if specified empty 980 // and not if first subformat is GENERAL 981 String aAdd( pSc->GetStandardName() ); 982 String aTmp; 983 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 984 { 985 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 986 if ( nAnz ) 987 { 988 NumFor[nIndex].Enlarge(nAnz); 989 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz ); 990 rString += ';'; 991 rString += aAdd; 992 } 993 } 994 } 995 else if ( nIndex == 2 && NumFor[nIndex].GetnAnz() == 0 && 996 rString.GetChar(rString.Len()-1) != ';' && 997 eOp2 != NUMBERFORMAT_OP_NO ) 998 { // No trailing third subformat => GENERAL but not if specified empty 999 String aAdd( pSc->GetStandardName() ); 1000 String aTmp; 1001 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 1002 { 1003 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 1004 if ( nAnz ) 1005 { 1006 NumFor[nIndex].Enlarge(nAnz); 1007 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz ); 1008 rString += ';'; 1009 rString += aAdd; 1010 } 1011 } 1012 } 1013 } 1014 sFormatstring = rString; 1015 if ( aComment.Len() ) 1016 { 1017 SetComment( aComment ); // setzt sComment und sFormatstring 1018 rString = sFormatstring; // geaenderten sFormatstring uebernehmen 1019 } 1020 if (NumFor[2].GetnAnz() == 0 && // kein 3. Teilstring 1021 eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO && 1022 fLimit1 == 0.0 && fLimit2 == 0.0) 1023 eOp1 = NUMBERFORMAT_OP_GE; // 0 zum ersten Format dazu 1024 1025 } 1026 1027 SvNumberformat::~SvNumberformat() 1028 { 1029 } 1030 1031 //--------------------------------------------------------------------------- 1032 // Next_Symbol 1033 //--------------------------------------------------------------------------- 1034 // Zerlegt die Eingabe in Symbole fuer die weitere 1035 // Verarbeitung (Turing-Maschine). 1036 //--------------------------------------------------------------------------- 1037 // Ausgangs Zustand = SsStart 1038 //---------------+-------------------+-----------------------+--------------- 1039 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand 1040 //---------------+-------------------+-----------------------+--------------- 1041 // SsStart | ; | Pos-- | SsGetString 1042 // | [ | Symbol += Zeichen | SsGetBracketed 1043 // | ] | Fehler | SsStop 1044 // | BLANK | | 1045 // | Sonst | Symbol += Zeichen | SsGetString 1046 //---------------+-------------------+-----------------------+--------------- 1047 // SsGetString | ; | | SsStop 1048 // | Sonst | Symbol+=Zeichen | 1049 //---------------+-------------------+-----------------------+--------------- 1050 // SsGetBracketed| <, > = | del [ | 1051 // | | Symbol += Zeichen | SsGetCon 1052 // | BLANK | | 1053 // | h, H, m, M, s, S | Symbol += Zeichen | SsGetTime 1054 // | sonst | del [ | 1055 // | | Symbol += Zeichen | SsGetPrefix 1056 //---------------+-------------------+-----------------------+--------------- 1057 // SsGetTime | ] | Symbol += Zeichen | SsGetString 1058 // | h, H, m, M, s, S | Symbol += Zeichen, * | SsGetString 1059 // | sonst | del [; Symbol+=Zeichen| SsGetPrefix 1060 //---------------+-------------------+-----------------------+--------------- 1061 // SsGetPrefix | ] | | SsStop 1062 // | sonst | Symbol += Zeichen | 1063 //---------------+-------------------+-----------------------+--------------- 1064 // SsGetCon | >, = | Symbol+=Zeichen | 1065 // | ] | | SsStop 1066 // | sonst | Fehler | SsStop 1067 //---------------+-------------------+-----------------------+--------------- 1068 // * : Sonderbedingung 1069 1070 enum ScanState 1071 { 1072 SsStop, 1073 SsStart, 1074 SsGetCon, // condition 1075 SsGetString, // format string 1076 SsGetPrefix, // color or NatNumN 1077 SsGetTime, // [HH] for time 1078 SsGetBracketed // any [...] not decided yet 1079 }; 1080 1081 1082 // read a string until ']' and delete spaces in input 1083 // static 1084 xub_StrLen SvNumberformat::ImpGetNumber(String& rString, 1085 xub_StrLen& nPos, 1086 String& sSymbol) 1087 { 1088 xub_StrLen nStartPos = nPos; 1089 sal_Unicode cToken; 1090 xub_StrLen nLen = rString.Len(); 1091 sSymbol.Erase(); 1092 while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') ) 1093 { 1094 if (cToken == ' ') 1095 { // delete spaces 1096 rString.Erase(nPos,1); 1097 nLen--; 1098 } 1099 else 1100 { 1101 nPos++; 1102 sSymbol += cToken; 1103 } 1104 } 1105 return nPos - nStartPos; 1106 } 1107 1108 1109 // static 1110 LanguageType SvNumberformat::ImpGetLanguageType( const String& rString, 1111 xub_StrLen& nPos ) 1112 { 1113 sal_Int32 nNum = 0; 1114 sal_Unicode cToken = 0; 1115 xub_StrLen nLen = rString.Len(); 1116 while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') ) 1117 { 1118 if ( '0' <= cToken && cToken <= '9' ) 1119 { 1120 nNum *= 16; 1121 nNum += cToken - '0'; 1122 } 1123 else if ( 'a' <= cToken && cToken <= 'f' ) 1124 { 1125 nNum *= 16; 1126 nNum += cToken - 'a' + 10; 1127 } 1128 else if ( 'A' <= cToken && cToken <= 'F' ) 1129 { 1130 nNum *= 16; 1131 nNum += cToken - 'A' + 10; 1132 } 1133 else 1134 return LANGUAGE_DONTKNOW; 1135 ++nPos; 1136 } 1137 return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum : 1138 LANGUAGE_DONTKNOW; 1139 } 1140 1141 sal_Bool IsSingleSymbol(String& rString, xub_StrLen nPos){ 1142 sal_Bool ret = sal_False; 1143 while(nPos > 0){ 1144 if(rString.GetChar(nPos) == '*' || rString.GetChar(nPos) == '\\' || rString.GetChar(nPos) == '_'){ 1145 ret = !ret; 1146 nPos--; 1147 } 1148 else 1149 return ret; 1150 } 1151 return ret; 1152 } 1153 1154 short SvNumberformat::ImpNextSymbol(String& rString, 1155 xub_StrLen& nPos, 1156 String& sSymbol) 1157 { 1158 short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1159 sal_Unicode cToken; 1160 sal_Unicode cLetter = ' '; // Zwischenergebnis 1161 xub_StrLen nLen = rString.Len(); 1162 ScanState eState = SsStart; 1163 sSymbol.Erase(); 1164 const NfKeywordTable & rKeywords = rScan.GetKeywords(); 1165 while (nPos < nLen && eState != SsStop) 1166 { 1167 cToken = rString.GetChar(nPos); 1168 nPos++; 1169 switch (eState) 1170 { 1171 case SsStart: 1172 { 1173 if (cToken == '[') 1174 { 1175 eState = SsGetBracketed; 1176 sSymbol += cToken; 1177 } 1178 else if (cToken == ';') 1179 { 1180 eState = SsGetString; 1181 nPos--; 1182 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1183 } 1184 else if (cToken == ']') 1185 { 1186 eState = SsStop; 1187 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1188 } 1189 else if (cToken == ' ') // Skip Blanks 1190 { 1191 rString.Erase(nPos-1,1); 1192 nPos--; 1193 nLen--; 1194 } 1195 else 1196 { 1197 sSymbol += cToken; 1198 eState = SsGetString; 1199 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1200 } 1201 } 1202 break; 1203 case SsGetBracketed: 1204 { 1205 switch (cToken) 1206 { 1207 case '<': 1208 case '>': 1209 case '=': 1210 { 1211 sSymbol.EraseAllChars('['); 1212 sSymbol += cToken; 1213 cLetter = cToken; 1214 eState = SsGetCon; 1215 switch (cToken) 1216 { 1217 case '<': eSymbolType = NUMBERFORMAT_OP_LT; break; 1218 case '>': eSymbolType = NUMBERFORMAT_OP_GT; break; 1219 case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break; 1220 default: break; 1221 } 1222 } 1223 break; 1224 case ' ': 1225 { 1226 rString.Erase(nPos-1,1); 1227 nPos--; 1228 nLen--; 1229 } 1230 break; 1231 case '$' : 1232 { 1233 if ( rString.GetChar(nPos) == '-' ) 1234 { // [$-xxx] locale 1235 sSymbol.EraseAllChars('['); 1236 eSymbolType = BRACKET_SYMBOLTYPE_LOCALE; 1237 eState = SsGetPrefix; 1238 } 1239 else 1240 { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1241 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1242 eState = SsGetString; 1243 } 1244 sSymbol += cToken; 1245 } 1246 break; 1247 case '~' : 1248 { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR 1249 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1250 sSymbol += cToken; 1251 eState = SsGetString; 1252 } 1253 break; 1254 default: 1255 { 1256 static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) ); 1257 static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) ); 1258 String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) ); 1259 String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) ); 1260 sal_Unicode cUpper = aUpperNatNum.GetChar(0); 1261 sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32(); 1262 sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() ); 1263 if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 ) 1264 { 1265 sSymbol.EraseAllChars('['); 1266 sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 ); 1267 nPos += aNatNum.Len()+1; 1268 //! SymbolType is negative 1269 eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum); 1270 eState = SsGetPrefix; 1271 } 1272 else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' ) 1273 { 1274 sSymbol.EraseAllChars('['); 1275 sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 ); 1276 nPos += aDBNum.Len()+1; 1277 //! SymbolType is negative 1278 eSymbolType = sal::static_int_cast< short >( 1279 BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1')); 1280 eState = SsGetPrefix; 1281 } 1282 else if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1283 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1284 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1285 { 1286 sSymbol += cToken; 1287 eState = SsGetTime; 1288 cLetter = cToken; 1289 } 1290 else 1291 { 1292 sSymbol.EraseAllChars('['); 1293 sSymbol += cToken; 1294 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1295 eState = SsGetPrefix; 1296 } 1297 } 1298 break; 1299 } 1300 } 1301 break; 1302 case SsGetString: 1303 { 1304 if (cToken == ';' && (nPos>=2) &&!IsSingleSymbol(rString, nPos-2)) 1305 { 1306 eState = SsStop; 1307 } 1308 else 1309 sSymbol += cToken; 1310 } 1311 break; 1312 case SsGetTime: 1313 { 1314 if (cToken == ']') 1315 { 1316 sSymbol += cToken; 1317 eState = SsGetString; 1318 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1319 } 1320 else 1321 { 1322 sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0); 1323 if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1324 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1325 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1326 { 1327 if (cLetter == cToken) 1328 { 1329 sSymbol += cToken; 1330 cLetter = ' '; 1331 } 1332 else 1333 { 1334 sSymbol.EraseAllChars('['); 1335 sSymbol += cToken; 1336 eState = SsGetPrefix; 1337 } 1338 } 1339 else 1340 { 1341 sSymbol.EraseAllChars('['); 1342 sSymbol += cToken; 1343 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1344 eState = SsGetPrefix; 1345 } 1346 } 1347 } 1348 break; 1349 case SsGetCon: 1350 { 1351 switch (cToken) 1352 { 1353 case '<': 1354 { 1355 eState = SsStop; 1356 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1357 } 1358 break; 1359 case '>': 1360 { 1361 if (cLetter == '<') 1362 { 1363 sSymbol += cToken; 1364 cLetter = ' '; 1365 eState = SsStop; 1366 eSymbolType = NUMBERFORMAT_OP_NE; 1367 } 1368 else 1369 { 1370 eState = SsStop; 1371 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1372 } 1373 } 1374 break; 1375 case '=': 1376 { 1377 if (cLetter == '<') 1378 { 1379 sSymbol += cToken; 1380 cLetter = ' '; 1381 eSymbolType = NUMBERFORMAT_OP_LE; 1382 } 1383 else if (cLetter == '>') 1384 { 1385 sSymbol += cToken; 1386 cLetter = ' '; 1387 eSymbolType = NUMBERFORMAT_OP_GE; 1388 } 1389 else 1390 { 1391 eState = SsStop; 1392 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1393 } 1394 } 1395 break; 1396 case ' ': 1397 { 1398 rString.Erase(nPos-1,1); 1399 nPos--; 1400 nLen--; 1401 } 1402 break; 1403 default: 1404 { 1405 eState = SsStop; 1406 nPos--; 1407 } 1408 break; 1409 } 1410 } 1411 break; 1412 case SsGetPrefix: 1413 { 1414 if (cToken == ']') 1415 eState = SsStop; 1416 else 1417 sSymbol += cToken; 1418 } 1419 break; 1420 default: 1421 break; 1422 } // of switch 1423 } // of while 1424 1425 return eSymbolType; 1426 } 1427 1428 NfHackConversion SvNumberformat::Load( SvStream& rStream, 1429 ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter, 1430 ImpSvNumberInputScan& rISc ) 1431 { 1432 rHdr.StartEntry(); 1433 sal_uInt16 nOp1, nOp2; 1434 SvNumberformat::LoadString( rStream, sFormatstring ); 1435 rStream >> eType >> fLimit1 >> fLimit2 1436 >> nOp1 >> nOp2 >> bStandard >> bIsUsed; 1437 NfHackConversion eHackConversion = NF_CONVERT_NONE; 1438 sal_Bool bOldConvert = sal_False; 1439 LanguageType eOldTmpLang = 0; 1440 LanguageType eOldNewLang = 0; 1441 if ( pHackConverter ) 1442 { // werden nur hierbei gebraucht 1443 bOldConvert = rScan.GetConvertMode(); 1444 eOldTmpLang = rScan.GetTmpLnge(); 1445 eOldNewLang = rScan.GetNewLnge(); 1446 } 1447 String aLoadedColorName; 1448 for (sal_uInt16 i = 0; i < 4; i++) 1449 { 1450 NumFor[i].Load( rStream, rScan, aLoadedColorName ); 1451 if ( pHackConverter && eHackConversion == NF_CONVERT_NONE ) 1452 { 1453 //! HACK! ER 29.07.97 13:52 1454 // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/ 1455 // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert.. 1456 // System-German FARBE nach System-xxx COLOR umsetzen und vice versa, 1457 //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in 1458 //! ImpSvNumberformatScan existierten 1459 if ( aLoadedColorName.Len() && !NumFor[i].GetColor() 1460 && aLoadedColorName != rScan.GetColorString() ) 1461 { 1462 if ( rScan.GetColorString().EqualsAscii( "FARBE" ) ) 1463 { // English -> German 1464 eHackConversion = NF_CONVERT_ENGLISH_GERMAN; 1465 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US ); 1466 rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN ); 1467 } 1468 else 1469 { // German -> English 1470 eHackConversion = NF_CONVERT_GERMAN_ENGLISH; 1471 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN ); 1472 rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US ); 1473 } 1474 String aColorName = NumFor[i].GetColorName(); 1475 const Color* pColor = rScan.GetColor( aColorName ); 1476 if ( !pColor && aLoadedColorName == aColorName ) 1477 eHackConversion = NF_CONVERT_NONE; 1478 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM ); 1479 rScan.SetConvertMode( eOldTmpLang, eOldNewLang ); 1480 rScan.SetConvertMode( bOldConvert ); 1481 } 1482 } 1483 } 1484 eOp1 = (SvNumberformatLimitOps) nOp1; 1485 eOp2 = (SvNumberformatLimitOps) nOp2; 1486 String aComment; // wird nach dem NewCurrency-Geraffel richtig gesetzt 1487 if ( rHdr.BytesLeft() ) 1488 { // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1489 SvNumberformat::LoadString( rStream, aComment ); 1490 rStream >> nNewStandardDefined; 1491 } 1492 1493 xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND; 1494 sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic && 1495 (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND ); 1496 sal_Bool bNewCurrencyLoaded = sal_False; 1497 sal_Bool bNewCurrency = sal_False; 1498 1499 sal_Bool bGoOn = sal_True; 1500 while ( rHdr.BytesLeft() && bGoOn ) 1501 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1502 sal_uInt16 nId; 1503 rStream >> nId; 1504 switch ( nId ) 1505 { 1506 case nNewCurrencyVersionId : 1507 { 1508 bNewCurrencyLoaded = sal_True; 1509 rStream >> bNewCurrency; 1510 if ( bNewCurrency ) 1511 { 1512 for ( sal_uInt16 j=0; j<4; j++ ) 1513 { 1514 NumFor[j].LoadNewCurrencyMap( rStream ); 1515 } 1516 } 1517 } 1518 break; 1519 case nNewStandardFlagVersionId : 1520 rStream >> bStandard; // the real standard flag 1521 break; 1522 default: 1523 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" ); 1524 bGoOn = sal_False; // stop reading unknown stream left over of newer versions 1525 // Would be nice to have multiple read/write headers instead 1526 // but old versions wouldn't know it, TLOT. 1527 } 1528 } 1529 rHdr.EndEntry(); 1530 1531 if ( bNewCurrencyLoaded ) 1532 { 1533 if ( bNewCurrency && bNewCurrencyComment ) 1534 { // original Formatstring und Kommentar wiederherstellen 1535 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1536 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1537 } 1538 } 1539 else if ( bNewCurrencyComment ) 1540 { // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert 1541 // original Formatstring und Kommentar wiederherstellen 1542 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1543 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1544 // Zustaende merken 1545 short nDefined = ( eType & NUMBERFORMAT_DEFINED ); 1546 sal_uInt16 nNewStandard = nNewStandardDefined; 1547 // neu parsen etc. 1548 String aStr( sFormatstring ); 1549 xub_StrLen nCheckPos = 0; 1550 SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc, 1551 nCheckPos, eLnge, bStandard ); 1552 DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" ); 1553 ImpCopyNumberformat( *pFormat ); 1554 delete pFormat; 1555 // Zustaende wiederherstellen 1556 eType |= nDefined; 1557 if ( nNewStandard ) 1558 SetNewStandardDefined( nNewStandard ); 1559 } 1560 SetComment( aComment ); 1561 1562 if ( eHackConversion != NF_CONVERT_NONE ) 1563 { //! und weiter mit dem HACK! 1564 switch ( eHackConversion ) 1565 { 1566 case NF_CONVERT_ENGLISH_GERMAN : 1567 ConvertLanguage( *pHackConverter, 1568 LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True ); 1569 break; 1570 case NF_CONVERT_GERMAN_ENGLISH : 1571 ConvertLanguage( *pHackConverter, 1572 LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True ); 1573 break; 1574 default: 1575 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" ); 1576 } 1577 } 1578 return eHackConversion; 1579 } 1580 1581 void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter, 1582 LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem ) 1583 { 1584 xub_StrLen nCheckPos; 1585 sal_uInt32 nKey; 1586 short nType = eType; 1587 String aFormatString( sFormatstring ); 1588 if ( bSystem ) 1589 rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType, 1590 nKey, eConvertFrom, eConvertTo ); 1591 else 1592 rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType, 1593 nKey, eConvertFrom, eConvertTo ); 1594 const SvNumberformat* pFormat = rConverter.GetEntry( nKey ); 1595 DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" ); 1596 if ( pFormat ) 1597 { 1598 ImpCopyNumberformat( *pFormat ); 1599 // aus Formatter/Scanner uebernommene Werte zuruecksetzen 1600 if ( bSystem ) 1601 eLnge = LANGUAGE_SYSTEM; 1602 // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner 1603 for ( sal_uInt16 i = 0; i < 4; i++ ) 1604 { 1605 String aColorName = NumFor[i].GetColorName(); 1606 Color* pColor = rScan.GetColor( aColorName ); 1607 NumFor[i].SetColor( pColor, aColorName ); 1608 } 1609 } 1610 } 1611 1612 1613 // static 1614 void SvNumberformat::LoadString( SvStream& rStream, String& rStr ) 1615 { 1616 CharSet eStream = rStream.GetStreamCharSet(); 1617 ByteString aStr; 1618 rStream.ReadByteString( aStr ); 1619 sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream ); 1620 if ( aStr.Search( cStream ) == STRING_NOTFOUND ) 1621 { // simple conversion to unicode 1622 rStr = UniString( aStr, eStream ); 1623 } 1624 else 1625 { 1626 sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol(); 1627 register const sal_Char* p = aStr.GetBuffer(); 1628 register const sal_Char* const pEnd = p + aStr.Len(); 1629 register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() ); 1630 while ( p < pEnd ) 1631 { 1632 if ( *p == cStream ) 1633 *pUni = cTarget; 1634 else 1635 *pUni = ByteString::ConvertToUnicode( *p, eStream ); 1636 p++; 1637 pUni++; 1638 } 1639 *pUni = 0; 1640 } 1641 } 1642 1643 1644 void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const 1645 { 1646 String aFormatstring( sFormatstring ); 1647 String aComment( sComment ); 1648 #if NF_COMMENT_IN_FORMATSTRING 1649 // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen 1650 // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung 1651 // (z.B. im Dialog) zu ermoeglichen 1652 SetComment( "", aFormatstring, aComment ); 1653 #endif 1654 1655 sal_Bool bNewCurrency = HasNewCurrency(); 1656 if ( bNewCurrency ) 1657 { // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern 1658 aComment.Insert( cNewCurrencyMagic, 0 ); 1659 aComment.Insert( cNewCurrencyMagic, 0 ); 1660 aComment.Insert( aFormatstring, 1 ); 1661 Build50Formatstring( aFormatstring ); // alten Formatstring generieren 1662 } 1663 1664 // old SO5 versions do behave strange (no output) if standard flag is set 1665 // on formats not prepared for it (not having the following exact types) 1666 sal_Bool bOldStandard = bStandard; 1667 if ( bOldStandard ) 1668 { 1669 switch ( eType ) 1670 { 1671 case NUMBERFORMAT_NUMBER : 1672 case NUMBERFORMAT_DATE : 1673 case NUMBERFORMAT_TIME : 1674 case NUMBERFORMAT_DATETIME : 1675 case NUMBERFORMAT_PERCENT : 1676 case NUMBERFORMAT_SCIENTIFIC : 1677 // ok to save 1678 break; 1679 default: 1680 bOldStandard = sal_False; 1681 } 1682 } 1683 1684 rHdr.StartEntry(); 1685 rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() ); 1686 rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2 1687 << bOldStandard << bIsUsed; 1688 for (sal_uInt16 i = 0; i < 4; i++) 1689 NumFor[i].Save(rStream); 1690 // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1691 rStream.WriteByteString( aComment, rStream.GetStreamCharSet() ); 1692 rStream << nNewStandardDefined; 1693 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR 1694 rStream << nNewCurrencyVersionId; 1695 rStream << bNewCurrency; 1696 if ( bNewCurrency ) 1697 { 1698 for ( sal_uInt16 j=0; j<4; j++ ) 1699 { 1700 NumFor[j].SaveNewCurrencyMap( rStream ); 1701 } 1702 } 1703 1704 // the real standard flag to load with versions >638 if different 1705 if ( bStandard != bOldStandard ) 1706 { 1707 rStream << nNewStandardFlagVersionId; 1708 rStream << bStandard; 1709 } 1710 1711 rHdr.EndEntry(); 1712 } 1713 1714 1715 sal_Bool SvNumberformat::HasNewCurrency() const 1716 { 1717 for ( sal_uInt16 j=0; j<4; j++ ) 1718 { 1719 if ( NumFor[j].HasNewCurrency() ) 1720 return sal_True; 1721 } 1722 return sal_False; 1723 } 1724 1725 bool SvNumberformat::HasTextFormatCode() const 1726 { 1727 for ( sal_uInt16 j=0; j<4; j++ ) 1728 { 1729 if ( NumFor[j].HasTextFormatCode() ) 1730 return true; 1731 } 1732 return false; 1733 } 1734 1735 sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol, 1736 String& rExtension ) const 1737 { 1738 for ( sal_uInt16 j=0; j<4; j++ ) 1739 { 1740 if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) ) 1741 return sal_True; 1742 } 1743 rSymbol.Erase(); 1744 rExtension.Erase(); 1745 return sal_False; 1746 } 1747 1748 1749 // static 1750 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr, 1751 sal_Bool bQuoteSymbol ) 1752 { 1753 String aTmp; 1754 xub_StrLen nStartPos, nPos, nLen; 1755 nLen = rStr.Len(); 1756 nStartPos = 0; 1757 while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND ) 1758 { 1759 xub_StrLen nEnd; 1760 if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen ) 1761 { 1762 aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos ); 1763 nStartPos = nEnd; 1764 } 1765 else 1766 { 1767 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1768 nStartPos = nPos + 2; 1769 xub_StrLen nDash; 1770 nEnd = nStartPos - 1; 1771 do 1772 { 1773 nDash = rStr.Search( '-', ++nEnd ); 1774 } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen ); 1775 xub_StrLen nClose; 1776 nEnd = nStartPos - 1; 1777 do 1778 { 1779 nClose = rStr.Search( ']', ++nEnd ); 1780 } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen ); 1781 nPos = ( nDash < nClose ? nDash : nClose ); 1782 if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' ) 1783 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1784 else 1785 { 1786 aTmp += '"'; 1787 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1788 aTmp += '"'; 1789 } 1790 nStartPos = nClose + 1; 1791 } 1792 } 1793 if ( nLen > nStartPos ) 1794 aTmp += rStr.Copy( nStartPos, nLen - nStartPos ); 1795 return aTmp; 1796 } 1797 1798 1799 void SvNumberformat::Build50Formatstring( String& rStr ) const 1800 { 1801 rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True ); 1802 } 1803 1804 1805 void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString) 1806 { 1807 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 1808 1809 if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16 1810 { 1811 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 1812 OutString = ::rtl::math::doubleToUString( fNumber, 1813 rtl_math_StringFormat_E, nStandardPrec /*2*/, 1814 GetFormatter().GetNumDecimalSep().GetChar(0)); 1815 } 1816 else 1817 ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec); 1818 } 1819 1820 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const 1821 { 1822 // Make sure the precision doesn't go over the maximum allowable precision. 1823 nPrecision = ::std::min(UPPER_PRECISION, nPrecision); 1824 1825 #if 0 1826 { 1827 // debugger test case for ANSI standard correctness 1828 ::rtl::OUString aTest; 1829 // expect 0.00123 OK 1830 aTest = ::rtl::math::doubleToUString( 0.001234567, 1831 rtl_math_StringFormat_G, 3, '.', sal_True ); 1832 // expect 123 OK 1833 aTest = ::rtl::math::doubleToUString( 123.4567, 1834 rtl_math_StringFormat_G, 3, '.', sal_True ); 1835 // expect 123.5 OK 1836 aTest = ::rtl::math::doubleToUString( 123.4567, 1837 rtl_math_StringFormat_G, 4, '.', sal_True ); 1838 // expect 1e+03 (as 999.6 rounded to 3 significant digits results in 1839 // 1000 with an exponent equal to significant digits) 1840 // Currently (24-Jan-2003) we do fail in this case and output 1000 1841 // instead, negligible. 1842 aTest = ::rtl::math::doubleToUString( 999.6, 1843 rtl_math_StringFormat_G, 3, '.', sal_True ); 1844 // expect what? result is 1.2e+004 1845 aTest = ::rtl::math::doubleToUString( 12345.6789, 1846 rtl_math_StringFormat_G, -3, '.', sal_True ); 1847 } 1848 #endif 1849 1850 // We decided to strip trailing zeros unconditionally, since binary 1851 // double-precision rounding error makes it impossible to determine e.g. 1852 // whether 844.10000000000002273737 is what the user has typed, or the 1853 // user has typed 844.1 but IEEE 754 represents it that way internally. 1854 1855 rOutString = ::rtl::math::doubleToUString( rNumber, 1856 rtl_math_StringFormat_F, nPrecision /*2*/, 1857 GetFormatter().GetNumDecimalSep().GetChar(0), true ); 1858 if (rOutString.GetChar(0) == '-' && 1859 rOutString.GetTokenCount('0') == rOutString.Len()) 1860 rOutString.EraseLeadingChars('-'); // nicht -0 1861 1862 ImpTransliterate( rOutString, NumFor[0].GetNatNum() ); 1863 } 1864 1865 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString) 1866 { 1867 sal_Bool bModified = sal_False; 1868 if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100)) 1869 { 1870 if (fNumber == 0.0) 1871 { 1872 OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) ); 1873 return; 1874 } 1875 fNumber *= 100; 1876 bModified = sal_True; 1877 } 1878 1879 if (fNumber == 0.0) 1880 { 1881 OutString = '0'; 1882 return; 1883 } 1884 1885 OutString = ::rtl::math::doubleToUString( fNumber, 1886 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 1887 GetFormatter().GetNumDecimalSep().GetChar(0), sal_True ); 1888 1889 if ( eType & NUMBERFORMAT_PERCENT && bModified) 1890 OutString += '%'; 1891 return; 1892 } 1893 1894 short SvNumberformat::ImpCheckCondition(double& fNumber, 1895 double& fLimit, 1896 SvNumberformatLimitOps eOp) 1897 { 1898 switch(eOp) 1899 { 1900 case NUMBERFORMAT_OP_NO: return -1; 1901 case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit); 1902 case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit); 1903 case NUMBERFORMAT_OP_LT: return (short) (fNumber < fLimit); 1904 case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit); 1905 case NUMBERFORMAT_OP_GT: return (short) (fNumber > fLimit); 1906 case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit); 1907 default: return -1; 1908 } 1909 } 1910 1911 sal_Bool SvNumberformat::GetOutputString(String& sString, 1912 String& OutString, 1913 Color** ppColor) 1914 { 1915 OutString.Erase(); 1916 sal_uInt16 nIx; 1917 if (eType & NUMBERFORMAT_TEXT) 1918 nIx = 0; 1919 else if (NumFor[3].GetnAnz() > 0) 1920 nIx = 3; 1921 else 1922 { 1923 *ppColor = NULL; // no change of color 1924 return sal_False; 1925 } 1926 *ppColor = NumFor[nIx].GetColor(); 1927 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 1928 if (rInfo.eScannedType == NUMBERFORMAT_TEXT) 1929 { 1930 sal_Bool bRes = sal_False; 1931 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 1932 for (sal_uInt16 i = 0; i < nAnz; i++) 1933 { 1934 switch (rInfo.nTypeArray[i]) 1935 { 1936 case NF_SYMBOLTYPE_STAR: 1937 if( bStarFlag ) 1938 { 1939 OutString += (sal_Unicode) 0x1B; 1940 OutString += rInfo.sStrArray[i].GetChar(1); 1941 bRes = sal_True; 1942 } 1943 break; 1944 case NF_SYMBOLTYPE_BLANK: 1945 InsertBlanks( OutString, OutString.Len(), 1946 rInfo.sStrArray[i].GetChar(1) ); 1947 break; 1948 case NF_KEY_GENERAL : // #77026# "General" is the same as "@" 1949 case NF_SYMBOLTYPE_DEL : 1950 OutString += sString; 1951 break; 1952 default: 1953 OutString += rInfo.sStrArray[i]; 1954 } 1955 } 1956 return bRes; 1957 } 1958 return sal_False; 1959 } 1960 /* 1961 void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1, 1962 sal_uLong y0, sal_uLong y1, 1963 sal_uLong& x2,sal_uLong& y2) 1964 { 1965 x2 = ((y0+nPrec)/y1)*x1 - x0; 1966 y2 = ((y0+nPrec)/y1)*y1 - y0; 1967 } 1968 */ 1969 sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y) 1970 { 1971 if (y == 0) 1972 return x; 1973 else 1974 { 1975 sal_uLong z = x%y; 1976 while (z) 1977 { 1978 x = y; 1979 y = z; 1980 z = x%y; 1981 } 1982 return y; 1983 } 1984 } 1985 1986 sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y) 1987 { 1988 if (y == 0) 1989 return x; 1990 else 1991 { 1992 sal_uLong z = x%y; 1993 while ((double)z/(double)y > D_EPS) 1994 { 1995 x = y; 1996 y = z; 1997 z = x%y; 1998 } 1999 return y; 2000 } 2001 } 2002 2003 namespace { 2004 2005 void lcl_GetOutputStringScientific( 2006 double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString) 2007 { 2008 bool bSign = ::rtl::math::isSignBitSet(fNumber); 2009 2010 // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7). 2011 sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0; 2012 if (nPrec && bSign) 2013 // Make room for the negative sign. 2014 --nPrec; 2015 2016 nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals. 2017 2018 rOutString = ::rtl::math::doubleToUString( 2019 fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0)); 2020 } 2021 2022 } 2023 2024 bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const 2025 { 2026 using namespace std; 2027 2028 if (eType != NUMBERFORMAT_NUMBER) 2029 return false; 2030 2031 double fTestNum = fNumber; 2032 bool bSign = ::rtl::math::isSignBitSet(fTestNum); 2033 if (bSign) 2034 fTestNum = -fTestNum; 2035 2036 if (fTestNum < EXP_LOWER_BOUND) 2037 { 2038 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2039 return true; 2040 } 2041 2042 double fExp = log10(fTestNum); 2043 // Values < 1.0 always have one digit before the decimal point. 2044 sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1; 2045 2046 if (nDigitPre > 15) 2047 { 2048 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2049 return true; 2050 } 2051 2052 sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0; 2053 if (nPrec && bSign) 2054 // Subtract the negative sign. 2055 --nPrec; 2056 if (nPrec) 2057 // Subtract the decimal point. 2058 --nPrec; 2059 2060 ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec); 2061 if (rOutString.Len() > nCharCount) 2062 // String still wider than desired. Switch to scientific notation. 2063 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2064 2065 return true; 2066 } 2067 2068 sal_Bool SvNumberformat::GetOutputString(double fNumber, 2069 String& OutString, 2070 Color** ppColor) 2071 { 2072 sal_Bool bRes = sal_False; 2073 OutString.Erase(); // alles loeschen 2074 *ppColor = NULL; // keine Farbaenderung 2075 if (eType & NUMBERFORMAT_LOGICAL) 2076 { 2077 if (fNumber) 2078 OutString = rScan.GetTrueString(); 2079 else 2080 OutString = rScan.GetFalseString(); 2081 return sal_False; 2082 } 2083 if (eType & NUMBERFORMAT_TEXT) 2084 { 2085 ImpGetOutputStandard(fNumber, OutString); 2086 return sal_False; 2087 } 2088 sal_Bool bHadStandard = sal_False; 2089 if (bStandard) // einzelne Standardformate 2090 { 2091 if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine 2092 { 2093 ImpGetOutputInputLine(fNumber, OutString); 2094 return false; 2095 } 2096 switch (eType) 2097 { 2098 case NUMBERFORMAT_NUMBER: // Standardzahlformat 2099 { 2100 if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION) 2101 { 2102 bool bSign = ::rtl::math::isSignBitSet(fNumber); 2103 if (bSign) 2104 fNumber = -fNumber; 2105 ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format. 2106 if (fNumber < EXP_LOWER_BOUND) 2107 { 2108 xub_StrLen nLen = OutString.Len(); 2109 if (!nLen) 2110 return false; 2111 2112 // #i112250# With the 10-decimal limit, small numbers are formatted as "0". 2113 // Switch to scientific in that case, too: 2114 if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0)) 2115 { 2116 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 2117 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 2118 OutString = ::rtl::math::doubleToUString( fNumber, 2119 rtl_math_StringFormat_E, nStandardPrec /*2*/, 2120 GetFormatter().GetNumDecimalSep().GetChar(0), true); 2121 } 2122 } 2123 if (bSign) 2124 OutString.Insert('-', 0); 2125 return false; 2126 } 2127 ImpGetOutputStandard(fNumber, OutString); 2128 bHadStandard = sal_True; 2129 } 2130 break; 2131 case NUMBERFORMAT_DATE: 2132 bRes |= ImpGetDateOutput(fNumber, 0, OutString); 2133 bHadStandard = sal_True; 2134 break; 2135 case NUMBERFORMAT_TIME: 2136 bRes |= ImpGetTimeOutput(fNumber, 0, OutString); 2137 bHadStandard = sal_True; 2138 break; 2139 case NUMBERFORMAT_DATETIME: 2140 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString); 2141 bHadStandard = sal_True; 2142 break; 2143 } 2144 } 2145 if ( !bHadStandard ) 2146 { 2147 sal_uInt16 nIx; // Index des Teilformats 2148 short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1); 2149 if (nCheck == -1 || nCheck == 1) // nur 1 String oder True 2150 nIx = 0; 2151 else 2152 { 2153 nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2); 2154 if (nCheck == -1 || nCheck == 1) 2155 nIx = 1; 2156 else 2157 nIx = 2; 2158 } 2159 if (nIx == 1 && // negatives Format 2160 IsNegativeRealNegative() && fNumber < 0.0) // ohne Vorzeichen 2161 fNumber = -fNumber; // Vorzeichen eliminieren 2162 if(nIx == 0 && 2163 IsNegativeRealNegative2() && fNumber < 0.0) 2164 fNumber = -fNumber; 2165 *ppColor = NumFor[nIx].GetColor(); 2166 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2167 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2168 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED) 2169 return sal_False; // leer => nichts 2170 else if (nAnz == 0) // sonst Standard-Format 2171 { 2172 ImpGetOutputStandard(fNumber, OutString); 2173 return sal_False; 2174 } 2175 switch (rInfo.eScannedType) 2176 { 2177 case NUMBERFORMAT_TEXT: 2178 case NUMBERFORMAT_DEFINED: 2179 { 2180 for (sal_uInt16 i = 0; i < nAnz; i++) 2181 { 2182 switch (rInfo.nTypeArray[i]) 2183 { 2184 case NF_SYMBOLTYPE_STAR: 2185 if( bStarFlag ) 2186 { 2187 OutString += (sal_Unicode) 0x1B; 2188 OutString += rInfo.sStrArray[i].GetChar(1); 2189 bRes = sal_True; 2190 } 2191 break; 2192 case NF_SYMBOLTYPE_BLANK: 2193 InsertBlanks( OutString, OutString.Len(), 2194 rInfo.sStrArray[i].GetChar(1) ); 2195 break; 2196 case NF_SYMBOLTYPE_STRING: 2197 case NF_SYMBOLTYPE_CURRENCY: 2198 OutString += rInfo.sStrArray[i]; 2199 break; 2200 case NF_SYMBOLTYPE_THSEP: 2201 if (rInfo.nThousand == 0) 2202 OutString += rInfo.sStrArray[i]; 2203 break; 2204 default: 2205 break; 2206 } 2207 } 2208 } 2209 break; 2210 case NUMBERFORMAT_DATE: 2211 bRes |= ImpGetDateOutput(fNumber, nIx, OutString); 2212 break; 2213 case NUMBERFORMAT_TIME: 2214 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString); 2215 break; 2216 case NUMBERFORMAT_DATETIME: 2217 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString); 2218 break; 2219 case NUMBERFORMAT_NUMBER: 2220 case NUMBERFORMAT_PERCENT: 2221 case NUMBERFORMAT_CURRENCY: 2222 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString); 2223 break; 2224 case NUMBERFORMAT_FRACTION: 2225 { 2226 String sStr, sFrac, sDiv; // Strings, Wert fuer 2227 sal_uLong nFrac, nDiv; // Vorkommaanteil 2228 // Zaehler und Nenner 2229 sal_Bool bSign = sal_False; 2230 if (fNumber < 0) 2231 { 2232 if (nIx == 0) // nicht in hinteren 2233 bSign = sal_True; // Formaten 2234 fNumber = -fNumber; 2235 } 2236 double fNum = floor(fNumber); // Vorkommateil 2237 fNumber -= fNum; // Nachkommateil 2238 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) 2239 // zu gross 2240 { 2241 OutString = rScan.GetErrorString(); 2242 return sal_False; 2243 } 2244 if (rInfo.nCntExp == 0) 2245 { 2246 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0"); 2247 return sal_False; 2248 } 2249 sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,... 2250 pow(10.0,rInfo.nCntExp))) - 1; 2251 sal_uLong x0, y0, x1, y1; 2252 2253 if (rInfo.nCntExp <= _MAX_FRACTION_PREC) 2254 { 2255 sal_Bool bUpperHalf; 2256 if (fNumber > 0.5) 2257 { 2258 bUpperHalf = sal_True; 2259 fNumber -= (fNumber - 0.5) * 2.0; 2260 } 2261 else 2262 bUpperHalf = sal_False; 2263 // Einstieg in Farey-Serie 2264 // finden: 2265 x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9 2266 if (x0 == 0) // => x0 = 2 2267 { 2268 y0 = 1; 2269 x1 = 1; 2270 y1 = nBasis; 2271 } 2272 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2 2273 { // geht (nBasis ungerade) 2274 y0 = nBasis; 2275 x1 = 1; 2276 y1 = 2; 2277 } 2278 else if (x0 == 1) 2279 { 2280 y0 = nBasis; // 1/n; 1/(n-1) 2281 x1 = 1; 2282 y1 = nBasis - 1; 2283 } 2284 else 2285 { 2286 y0 = nBasis; // z.B. 2/9 2/8 2287 x1 = x0; 2288 y1 = nBasis - 1; 2289 double fUg = (double) x0 / (double) y0; 2290 double fOg = (double) x1 / (double) y1; 2291 sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen 2292 x0 /= nGgt; 2293 y0 /= nGgt; // Einschachteln: 2294 sal_uLong x2 = 0; 2295 sal_uLong y2 = 0; 2296 sal_Bool bStop = sal_False; 2297 while (!bStop) 2298 { 2299 #ifdef GCC 2300 // #i21648# GCC over-optimizes something resulting 2301 // in wrong fTest values throughout the loops. 2302 volatile 2303 #endif 2304 double fTest = (double)x1/(double)y1; 2305 while (!bStop) 2306 { 2307 while (fTest > fOg) 2308 { 2309 x1--; 2310 fTest = (double)x1/(double)y1; 2311 } 2312 while (fTest < fUg && y1 > 1) 2313 { 2314 y1--; 2315 fTest = (double)x1/(double)y1; 2316 } 2317 if (fTest <= fOg) 2318 { 2319 fOg = fTest; 2320 bStop = sal_True; 2321 } 2322 else if (y1 == 1) 2323 bStop = sal_True; 2324 } // of while 2325 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen 2326 x2 = x1 / nGgt; 2327 y2 = y1 / nGgt; 2328 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2 2329 bStop = sal_True; // naechste Farey-Zahl 2330 else 2331 { 2332 y1--; 2333 bStop = sal_False; 2334 } 2335 } // of while 2336 x1 = x2; 2337 y1 = y2; 2338 } // of else 2339 double fup, flow; 2340 flow = (double)x0/(double)y0; 2341 fup = (double)x1/(double)y1; 2342 while (fNumber > fup) 2343 { 2344 sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl 2345 sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0; 2346 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2); 2347 x0 = x1; 2348 y0 = y1; 2349 x1 = x2; 2350 y1 = y2; 2351 flow = fup; 2352 fup = (double)x1/(double)y1; 2353 } 2354 if (fNumber - flow < fup - fNumber) 2355 { 2356 nFrac = x0; 2357 nDiv = y0; 2358 } 2359 else 2360 { 2361 nFrac = x1; 2362 nDiv = y1; 2363 } 2364 if (bUpperHalf) // Original restaur. 2365 { 2366 if (nFrac == 0 && nDiv == 1) // 1/1 2367 fNum += 1.0; 2368 else 2369 nFrac = nDiv - nFrac; 2370 } 2371 } 2372 else // grosse Nenner 2373 { // 0,1234->123/1000 2374 sal_uLong nGgt; 2375 /* 2376 nDiv = nBasis+1; 2377 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2378 pow(10.0,rInfo.nCntExp))); 2379 */ 2380 nDiv = 10000000; 2381 nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0)); 2382 nGgt = ImpGGT(nDiv, nFrac); 2383 if (nGgt > 1) 2384 { 2385 nDiv /= nGgt; 2386 nFrac /= nGgt; 2387 } 2388 if (nDiv > nBasis) 2389 { 2390 nGgt = ImpGGTRound(nDiv, nFrac); 2391 if (nGgt > 1) 2392 { 2393 nDiv /= nGgt; 2394 nFrac /= nGgt; 2395 } 2396 } 2397 if (nDiv > nBasis) 2398 { 2399 nDiv = nBasis; 2400 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2401 pow(10.0,rInfo.nCntExp))); 2402 nGgt = ImpGGTRound(nDiv, nFrac); 2403 if (nGgt > 1) 2404 { 2405 nDiv /= nGgt; 2406 nFrac /= nGgt; 2407 } 2408 } 2409 } 2410 2411 if (rInfo.nCntPre == 0) // unechter Bruch 2412 { 2413 double fNum1 = fNum * (double)nDiv + (double)nFrac; 2414 if (fNum1 > _D_MAX_U_LONG_) 2415 { 2416 OutString = rScan.GetErrorString(); 2417 return sal_False; 2418 } 2419 nFrac = (sal_uLong) floor(fNum1); 2420 sStr.Erase(); 2421 } 2422 else if (fNum == 0.0 && nFrac != 0) 2423 sStr.Erase(); 2424 else 2425 { 2426 char aBuf[100]; 2427 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked) 2428 sStr.AssignAscii( aBuf ); 2429 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 2430 } 2431 if (rInfo.nCntPre > 0 && nFrac == 0) 2432 { 2433 sFrac.Erase(); 2434 sDiv.Erase(); 2435 } 2436 else 2437 { 2438 sFrac = ImpIntToString( nIx, nFrac ); 2439 sDiv = ImpIntToString( nIx, nDiv ); 2440 } 2441 2442 sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw. 2443 xub_StrLen k; // Nenner: 2444 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC); 2445 sal_Bool bCont = sal_True; 2446 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC) 2447 { 2448 if (rInfo.nCntPre > 0 && nFrac == 0) 2449 sDiv.Insert(' ',0); 2450 else 2451 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 ); 2452 if ( j ) 2453 j--; 2454 else 2455 bCont = sal_False; 2456 } 2457 // weiter Zaehler: 2458 if ( !bCont ) 2459 sFrac.Erase(); 2460 else 2461 { 2462 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK); 2463 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK) 2464 { 2465 sFrac.Insert(rInfo.sStrArray[j],0); 2466 if ( j ) 2467 j--; 2468 else 2469 bCont = sal_False; 2470 } 2471 } 2472 // weiter Hauptzahl 2473 if ( !bCont ) 2474 sStr.Erase(); 2475 else 2476 { 2477 k = sStr.Len(); // hinter letzter Ziffer 2478 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, 2479 rInfo.nCntPre); 2480 } 2481 if (bSign && !(nFrac == 0 && fNum == 0.0)) 2482 OutString.Insert('-',0); // nicht -0 2483 OutString += sStr; 2484 OutString += sFrac; 2485 OutString += sDiv; 2486 } 2487 break; 2488 case NUMBERFORMAT_SCIENTIFIC: 2489 { 2490 sal_Bool bSign = sal_False; 2491 if (fNumber < 0) 2492 { 2493 if (nIx == 0) // nicht in hinteren 2494 bSign = sal_True; // Formaten 2495 fNumber = -fNumber; 2496 } 2497 String sStr( ::rtl::math::doubleToUString( fNumber, 2498 rtl_math_StringFormat_E, 2499 rInfo.nCntPre + rInfo.nCntPost - 1, '.' )); 2500 2501 String ExpStr; 2502 short nExpSign = 1; 2503 xub_StrLen nExPos = sStr.Search('E'); 2504 if ( nExPos != STRING_NOTFOUND ) 2505 { 2506 // split into mantisse and exponent and get rid of "E+" or "E-" 2507 xub_StrLen nExpStart = nExPos + 1; 2508 switch ( sStr.GetChar( nExpStart ) ) 2509 { 2510 case '-' : 2511 nExpSign = -1; 2512 // fallthru 2513 case '+' : 2514 ++nExpStart; 2515 break; 2516 } 2517 ExpStr = sStr.Copy( nExpStart ); // part following the "E+" 2518 sStr.Erase( nExPos ); 2519 sStr.EraseAllChars('.'); // cut any decimal delimiter 2520 if ( rInfo.nCntPre != 1 ) // rescale Exp 2521 { 2522 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign; 2523 nExp -= sal_Int32(rInfo.nCntPre)-1; 2524 if ( nExp < 0 ) 2525 { 2526 nExpSign = -1; 2527 nExp = -nExp; 2528 } 2529 else 2530 nExpSign = 1; 2531 ExpStr = String::CreateFromInt32( nExp ); 2532 } 2533 } 2534 sal_uInt16 j = nAnz-1; // last symbol 2535 xub_StrLen k; // position in ExpStr 2536 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP); 2537 2538 xub_StrLen nZeros = 0; // erase leading zeros 2539 while (nZeros < k && ExpStr.GetChar(nZeros) == '0') 2540 ++nZeros; 2541 if (nZeros) 2542 ExpStr.Erase( 0, nZeros); 2543 2544 sal_Bool bCont = sal_True; 2545 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP) 2546 { 2547 const String& rStr = rInfo.sStrArray[j]; 2548 if (nExpSign == -1) 2549 ExpStr.Insert('-',0); 2550 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+') 2551 ExpStr.Insert('+',0); 2552 ExpStr.Insert(rStr.GetChar(0),0); 2553 if ( j ) 2554 j--; 2555 else 2556 bCont = sal_False; 2557 } 2558 // weiter Hauptzahl: 2559 if ( !bCont ) 2560 sStr.Erase(); 2561 else 2562 { 2563 k = sStr.Len(); // hinter letzter Ziffer 2564 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx, 2565 rInfo.nCntPre + 2566 rInfo.nCntPost); 2567 } 2568 if (bSign) 2569 sStr.Insert('-',0); 2570 OutString = sStr; 2571 OutString += ExpStr; 2572 } 2573 break; 2574 } 2575 } 2576 return bRes; 2577 } 2578 2579 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber, 2580 sal_uInt16 nIx, 2581 String& OutString) 2582 { 2583 using namespace ::com::sun::star::i18n; 2584 sal_Bool bCalendarSet = sal_False; 2585 double fNumberOrig = fNumber; 2586 sal_Bool bRes = sal_False; 2587 sal_Bool bSign = sal_False; 2588 if (fNumber < 0.0) 2589 { 2590 fNumber = -fNumber; 2591 if (nIx == 0) 2592 bSign = sal_True; 2593 } 2594 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2595 if (rInfo.bThousand) // []-Format 2596 { 2597 if (fNumber > 1.0E10) // zu gross 2598 { 2599 OutString = rScan.GetErrorString(); 2600 return sal_False; 2601 } 2602 } 2603 else 2604 fNumber -= floor(fNumber); // sonst Datum abtrennen 2605 sal_Bool bInputLine; 2606 xub_StrLen nCntPost; 2607 if ( rScan.GetStandardPrec() == 300 && 2608 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 2609 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 2610 bInputLine = sal_True; 2611 nCntPost = 7; 2612 } 2613 else 2614 { 2615 bInputLine = sal_False; 2616 nCntPost = xub_StrLen(rInfo.nCntPost); 2617 } 2618 if (bSign && !rInfo.bThousand) // kein []-Format 2619 fNumber = 1.0 - fNumber; // "Kehrwert" 2620 double fTime = fNumber * 86400.0; 2621 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 2622 if (bSign && fTime == 0.0) 2623 bSign = sal_False; // nicht -00:00:00 2624 2625 if( floor( fTime ) > _D_MAX_U_LONG_ ) 2626 { 2627 OutString = rScan.GetErrorString(); 2628 return sal_False; 2629 } 2630 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 2631 2632 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 2633 rtl_math_StringFormat_F, int(nCntPost), '.')); 2634 sSecStr.EraseLeadingChars('0'); 2635 sSecStr.EraseLeadingChars('.'); 2636 if ( bInputLine ) 2637 { 2638 sSecStr.EraseTrailingChars('0'); 2639 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 2640 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 2641 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2642 nCntPost = sSecStr.Len(); 2643 } 2644 else 2645 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2646 2647 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 2648 // abarbeiten 2649 sal_uLong nHour, nMin, nSec; 2650 if (!rInfo.bThousand) // kein [] Format 2651 { 2652 nHour = (nSeconds/3600) % 24; 2653 nMin = (nSeconds%3600) / 60; 2654 nSec = nSeconds%60; 2655 } 2656 else if (rInfo.nThousand == 3) // [ss] 2657 { 2658 nHour = 0; 2659 nMin = 0; 2660 nSec = nSeconds; 2661 } 2662 else if (rInfo.nThousand == 2) // [mm]:ss 2663 { 2664 nHour = 0; 2665 nMin = nSeconds / 60; 2666 nSec = nSeconds % 60; 2667 } 2668 else if (rInfo.nThousand == 1) // [hh]:mm:ss 2669 { 2670 nHour = nSeconds / 3600; 2671 nMin = (nSeconds%3600) / 60; 2672 nSec = nSeconds%60; 2673 } 2674 else { 2675 // TODO What should these be set to? 2676 nHour = 0; 2677 nMin = 0; 2678 nSec = 0; 2679 } 2680 2681 sal_Unicode cAmPm = ' '; // a oder p 2682 if (rInfo.nCntExp) // AM/PM 2683 { 2684 if (nHour == 0) 2685 { 2686 nHour = 12; 2687 cAmPm = 'a'; 2688 } 2689 else if (nHour < 12) 2690 cAmPm = 'a'; 2691 else 2692 { 2693 cAmPm = 'p'; 2694 if (nHour > 12) 2695 nHour -= 12; 2696 } 2697 } 2698 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2699 for (sal_uInt16 i = 0; i < nAnz; i++) 2700 { 2701 switch (rInfo.nTypeArray[i]) 2702 { 2703 case NF_SYMBOLTYPE_STAR: 2704 if( bStarFlag ) 2705 { 2706 OutString += (sal_Unicode) 0x1B; 2707 OutString += rInfo.sStrArray[i].GetChar(1); 2708 bRes = sal_True; 2709 } 2710 break; 2711 case NF_SYMBOLTYPE_BLANK: 2712 InsertBlanks( OutString, OutString.Len(), 2713 rInfo.sStrArray[i].GetChar(1) ); 2714 break; 2715 case NF_SYMBOLTYPE_STRING: 2716 case NF_SYMBOLTYPE_CURRENCY: 2717 case NF_SYMBOLTYPE_DATESEP: 2718 case NF_SYMBOLTYPE_TIMESEP: 2719 case NF_SYMBOLTYPE_TIME100SECSEP: 2720 OutString += rInfo.sStrArray[i]; 2721 break; 2722 case NF_SYMBOLTYPE_DIGIT: 2723 { 2724 xub_StrLen nLen = ( bInputLine && i > 0 && 2725 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 2726 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 2727 nCntPost : rInfo.sStrArray[i].Len() ); 2728 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 2729 { 2730 OutString += sSecStr.GetChar(nSecPos); 2731 nSecPos++; 2732 } 2733 } 2734 break; 2735 case NF_KEY_AMPM: // AM/PM 2736 { 2737 if ( !bCalendarSet ) 2738 { 2739 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart(); 2740 fDiff += fNumberOrig; 2741 GetCal().setLocalDateTime( fDiff ); 2742 bCalendarSet = sal_True; 2743 } 2744 if (cAmPm == 'a') 2745 OutString += GetCal().getDisplayName( 2746 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ); 2747 else 2748 OutString += GetCal().getDisplayName( 2749 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ); 2750 } 2751 break; 2752 case NF_KEY_AP: // A/P 2753 { 2754 if (cAmPm == 'a') 2755 OutString += 'a'; 2756 else 2757 OutString += 'p'; 2758 } 2759 break; 2760 case NF_KEY_MI: // M 2761 OutString += ImpIntToString( nIx, nMin ); 2762 break; 2763 case NF_KEY_MMI: // MM 2764 OutString += ImpIntToString( nIx, nMin, 2 ); 2765 break; 2766 case NF_KEY_H: // H 2767 OutString += ImpIntToString( nIx, nHour ); 2768 break; 2769 case NF_KEY_HH: // HH 2770 OutString += ImpIntToString( nIx, nHour, 2 ); 2771 break; 2772 case NF_KEY_S: // S 2773 OutString += ImpIntToString( nIx, nSec ); 2774 break; 2775 case NF_KEY_SS: // SS 2776 OutString += ImpIntToString( nIx, nSec, 2 ); 2777 break; 2778 default: 2779 break; 2780 } 2781 } 2782 if (bSign && rInfo.bThousand) 2783 OutString.Insert('-',0); 2784 return bRes; 2785 } 2786 2787 2788 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const 2789 { 2790 if ( GetCal().getUniqueID() != Gregorian::get() ) 2791 return sal_False; 2792 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2793 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2794 sal_uInt16 i; 2795 for ( i = 0; i < nAnz; i++ ) 2796 { 2797 switch ( rInfo.nTypeArray[i] ) 2798 { 2799 case NF_SYMBOLTYPE_CALENDAR : 2800 return sal_False; 2801 case NF_KEY_EC : 2802 case NF_KEY_EEC : 2803 case NF_KEY_R : 2804 case NF_KEY_RR : 2805 case NF_KEY_AAA : 2806 case NF_KEY_AAAA : 2807 return sal_True; 2808 } 2809 } 2810 return sal_False; 2811 } 2812 2813 2814 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar, 2815 double& fOrgDateTime ) const 2816 { 2817 CalendarWrapper& rCal = GetCal(); 2818 const rtl::OUString &rGregorian = Gregorian::get(); 2819 if ( rCal.getUniqueID() == rGregorian ) 2820 { 2821 using namespace ::com::sun::star::i18n; 2822 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals 2823 = rCal.getAllCalendars( rLoc().getLocale() ); 2824 sal_Int32 nCnt = xCals.getLength(); 2825 if ( nCnt > 1 ) 2826 { 2827 for ( sal_Int32 j=0; j < nCnt; j++ ) 2828 { 2829 if ( xCals[j] != rGregorian ) 2830 { 2831 if ( !rOrgCalendar.Len() ) 2832 { 2833 rOrgCalendar = rCal.getUniqueID(); 2834 fOrgDateTime = rCal.getDateTime(); 2835 } 2836 rCal.loadCalendar( xCals[j], rLoc().getLocale() ); 2837 rCal.setDateTime( fOrgDateTime ); 2838 break; // for 2839 } 2840 } 2841 } 2842 } 2843 } 2844 2845 2846 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar, 2847 double fOrgDateTime ) const 2848 { 2849 CalendarWrapper& rCal = GetCal(); 2850 const rtl::OUString &rGregorian = Gregorian::get(); 2851 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian ) 2852 { 2853 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2854 rCal.setDateTime( fOrgDateTime ); 2855 } 2856 } 2857 2858 2859 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime ) 2860 { 2861 using namespace ::com::sun::star::i18n; 2862 CalendarWrapper& rCal = GetCal(); 2863 const rtl::OUString &rGregorian = Gregorian::get(); 2864 if ( rCal.getUniqueID() != rGregorian ) 2865 { 2866 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2867 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL( 2868 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) ) 2869 { 2870 if ( !rOrgCalendar.Len() ) 2871 { 2872 rOrgCalendar = rCal.getUniqueID(); 2873 fOrgDateTime = rCal.getDateTime(); 2874 } 2875 else if ( rOrgCalendar == String(rGregorian) ) 2876 rOrgCalendar.Erase(); 2877 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2878 rCal.setDateTime( fOrgDateTime ); 2879 return sal_True; 2880 } 2881 } 2882 return sal_False; 2883 } 2884 2885 2886 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar, 2887 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const 2888 { 2889 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2890 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2891 for ( sal_uInt16 i = 0; i < nAnz; i++ ) 2892 { 2893 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR ) 2894 { 2895 CalendarWrapper& rCal = GetCal(); 2896 if ( !rOrgCalendar.Len() ) 2897 { 2898 rOrgCalendar = rCal.getUniqueID(); 2899 fOrgDateTime = rCal.getDateTime(); 2900 } 2901 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2902 rCal.setDateTime( fOrgDateTime ); 2903 return sal_True; 2904 } 2905 } 2906 return sal_False; 2907 } 2908 2909 2910 // static 2911 void SvNumberformat::ImpAppendEraG( String& OutString, 2912 const CalendarWrapper& rCal, sal_Int16 nNatNum ) 2913 { 2914 using namespace ::com::sun::star::i18n; 2915 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) ) 2916 { 2917 sal_Unicode cEra; 2918 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2919 switch ( nVal ) 2920 { 2921 case 1 : cEra = 'M'; break; 2922 case 2 : cEra = 'T'; break; 2923 case 3 : cEra = 'S'; break; 2924 case 4 : cEra = 'H'; break; 2925 default: 2926 cEra = '?'; 2927 } 2928 OutString += cEra; 2929 } 2930 else 2931 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ); 2932 } 2933 2934 2935 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber, 2936 sal_uInt16 nIx, 2937 String& OutString) 2938 { 2939 using namespace ::com::sun::star::i18n; 2940 sal_Bool bRes = sal_False; 2941 CalendarWrapper& rCal = GetCal(); 2942 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 2943 fNumber += fDiff; 2944 rCal.setLocalDateTime( fNumber ); 2945 String aOrgCalendar; // empty => not changed yet 2946 double fOrgDateTime; 2947 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 2948 if ( bOtherCalendar ) 2949 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 2950 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 2951 bOtherCalendar = sal_False; 2952 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2953 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2954 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 2955 for (sal_uInt16 i = 0; i < nAnz; i++) 2956 { 2957 switch (rInfo.nTypeArray[i]) 2958 { 2959 case NF_SYMBOLTYPE_CALENDAR : 2960 if ( !aOrgCalendar.Len() ) 2961 { 2962 aOrgCalendar = rCal.getUniqueID(); 2963 fOrgDateTime = rCal.getDateTime(); 2964 } 2965 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2966 rCal.setDateTime( fOrgDateTime ); 2967 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 2968 break; 2969 case NF_SYMBOLTYPE_STAR: 2970 if( bStarFlag ) 2971 { 2972 OutString += (sal_Unicode) 0x1B; 2973 OutString += rInfo.sStrArray[i].GetChar(1); 2974 bRes = sal_True; 2975 } 2976 break; 2977 case NF_SYMBOLTYPE_BLANK: 2978 InsertBlanks( OutString, OutString.Len(), 2979 rInfo.sStrArray[i].GetChar(1) ); 2980 break; 2981 case NF_SYMBOLTYPE_STRING: 2982 case NF_SYMBOLTYPE_CURRENCY: 2983 case NF_SYMBOLTYPE_DATESEP: 2984 case NF_SYMBOLTYPE_TIMESEP: 2985 case NF_SYMBOLTYPE_TIME100SECSEP: 2986 OutString += rInfo.sStrArray[i]; 2987 break; 2988 case NF_KEY_M: // M 2989 OutString += rCal.getDisplayString( 2990 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 2991 break; 2992 case NF_KEY_MM: // MM 2993 OutString += rCal.getDisplayString( 2994 CalendarDisplayCode::LONG_MONTH, nNatNum ); 2995 break; 2996 case NF_KEY_MMM: // MMM 2997 OutString += rCal.getDisplayString( 2998 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 2999 break; 3000 case NF_KEY_MMMM: // MMMM 3001 OutString += rCal.getDisplayString( 3002 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 3003 break; 3004 case NF_KEY_MMMMM: // MMMMM 3005 OutString += rCal.getDisplayString( 3006 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 3007 break; 3008 case NF_KEY_Q: // Q 3009 OutString += rCal.getDisplayString( 3010 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 3011 break; 3012 case NF_KEY_QQ: // QQ 3013 OutString += rCal.getDisplayString( 3014 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3015 break; 3016 case NF_KEY_D: // D 3017 OutString += rCal.getDisplayString( 3018 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3019 break; 3020 case NF_KEY_DD: // DD 3021 OutString += rCal.getDisplayString( 3022 CalendarDisplayCode::LONG_DAY, nNatNum ); 3023 break; 3024 case NF_KEY_DDD: // DDD 3025 { 3026 if ( bOtherCalendar ) 3027 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3028 OutString += rCal.getDisplayString( 3029 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3030 if ( bOtherCalendar ) 3031 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3032 } 3033 break; 3034 case NF_KEY_DDDD: // DDDD 3035 { 3036 if ( bOtherCalendar ) 3037 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3038 OutString += rCal.getDisplayString( 3039 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3040 if ( bOtherCalendar ) 3041 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3042 } 3043 break; 3044 case NF_KEY_YY: // YY 3045 { 3046 if ( bOtherCalendar ) 3047 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3048 OutString += rCal.getDisplayString( 3049 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3050 if ( bOtherCalendar ) 3051 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3052 } 3053 break; 3054 case NF_KEY_YYYY: // YYYY 3055 { 3056 if ( bOtherCalendar ) 3057 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3058 OutString += rCal.getDisplayString( 3059 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3060 if ( bOtherCalendar ) 3061 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3062 } 3063 break; 3064 case NF_KEY_EC: // E 3065 OutString += rCal.getDisplayString( 3066 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3067 break; 3068 case NF_KEY_EEC: // EE 3069 case NF_KEY_R: // R 3070 OutString += rCal.getDisplayString( 3071 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3072 break; 3073 case NF_KEY_NN: // NN 3074 case NF_KEY_AAA: // AAA 3075 OutString += rCal.getDisplayString( 3076 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3077 break; 3078 case NF_KEY_NNN: // NNN 3079 case NF_KEY_AAAA: // AAAA 3080 OutString += rCal.getDisplayString( 3081 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3082 break; 3083 case NF_KEY_NNNN: // NNNN 3084 { 3085 OutString += rCal.getDisplayString( 3086 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3087 OutString += rLoc().getLongDateDayOfWeekSep(); 3088 } 3089 break; 3090 case NF_KEY_WW : // WW 3091 { 3092 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3093 OutString += ImpIntToString( nIx, nVal ); 3094 } 3095 break; 3096 case NF_KEY_G: // G 3097 ImpAppendEraG( OutString, rCal, nNatNum ); 3098 break; 3099 case NF_KEY_GG: // GG 3100 OutString += rCal.getDisplayString( 3101 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3102 break; 3103 case NF_KEY_GGG: // GGG 3104 OutString += rCal.getDisplayString( 3105 CalendarDisplayCode::LONG_ERA, nNatNum ); 3106 break; 3107 case NF_KEY_RR: // RR => GGGEE 3108 OutString += rCal.getDisplayString( 3109 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3110 break; 3111 } 3112 } 3113 if ( aOrgCalendar.Len() ) 3114 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3115 return bRes; 3116 } 3117 3118 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, 3119 sal_uInt16 nIx, 3120 String& OutString) 3121 { 3122 using namespace ::com::sun::star::i18n; 3123 sal_Bool bRes = sal_False; 3124 3125 CalendarWrapper& rCal = GetCal(); 3126 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 3127 fNumber += fDiff; 3128 3129 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3130 sal_Bool bInputLine; 3131 xub_StrLen nCntPost; 3132 if ( rScan.GetStandardPrec() == 300 && 3133 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 3134 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 3135 bInputLine = sal_True; 3136 nCntPost = 7; 3137 } 3138 else 3139 { 3140 bInputLine = sal_False; 3141 nCntPost = xub_StrLen(rInfo.nCntPost); 3142 } 3143 double fTime = (fNumber - floor( fNumber )) * 86400.0; 3144 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 3145 if (fTime >= 86400.0) 3146 { 3147 // result of fNumber==x.999999999... rounded up, use correct date/time 3148 fTime -= 86400.0; 3149 fNumber = floor( fNumber + 0.5) + fTime; 3150 } 3151 rCal.setLocalDateTime( fNumber ); 3152 3153 String aOrgCalendar; // empty => not changed yet 3154 double fOrgDateTime; 3155 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 3156 if ( bOtherCalendar ) 3157 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3158 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 3159 bOtherCalendar = sal_False; 3160 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 3161 3162 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 3163 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 3164 rtl_math_StringFormat_F, int(nCntPost), '.')); 3165 sSecStr.EraseLeadingChars('0'); 3166 sSecStr.EraseLeadingChars('.'); 3167 if ( bInputLine ) 3168 { 3169 sSecStr.EraseTrailingChars('0'); 3170 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 3171 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 3172 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3173 nCntPost = sSecStr.Len(); 3174 } 3175 else 3176 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3177 3178 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 3179 // abarbeiten 3180 sal_uLong nHour, nMin, nSec; 3181 if (!rInfo.bThousand) // [] Format 3182 { 3183 nHour = (nSeconds/3600) % 24; 3184 nMin = (nSeconds%3600) / 60; 3185 nSec = nSeconds%60; 3186 } 3187 else if (rInfo.nThousand == 3) // [ss] 3188 { 3189 nHour = 0; 3190 nMin = 0; 3191 nSec = nSeconds; 3192 } 3193 else if (rInfo.nThousand == 2) // [mm]:ss 3194 { 3195 nHour = 0; 3196 nMin = nSeconds / 60; 3197 nSec = nSeconds % 60; 3198 } 3199 else if (rInfo.nThousand == 1) // [hh]:mm:ss 3200 { 3201 nHour = nSeconds / 3600; 3202 nMin = (nSeconds%3600) / 60; 3203 nSec = nSeconds%60; 3204 } 3205 else { 3206 nHour = 0; // TODO What should these values be? 3207 nMin = 0; 3208 nSec = 0; 3209 } 3210 sal_Unicode cAmPm = ' '; // a oder p 3211 if (rInfo.nCntExp) // AM/PM 3212 { 3213 if (nHour == 0) 3214 { 3215 nHour = 12; 3216 cAmPm = 'a'; 3217 } 3218 else if (nHour < 12) 3219 cAmPm = 'a'; 3220 else 3221 { 3222 cAmPm = 'p'; 3223 if (nHour > 12) 3224 nHour -= 12; 3225 } 3226 } 3227 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 3228 for (sal_uInt16 i = 0; i < nAnz; i++) 3229 { 3230 switch (rInfo.nTypeArray[i]) 3231 { 3232 case NF_SYMBOLTYPE_CALENDAR : 3233 if ( !aOrgCalendar.Len() ) 3234 { 3235 aOrgCalendar = rCal.getUniqueID(); 3236 fOrgDateTime = rCal.getDateTime(); 3237 } 3238 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 3239 rCal.setDateTime( fOrgDateTime ); 3240 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3241 break; 3242 case NF_SYMBOLTYPE_STAR: 3243 if( bStarFlag ) 3244 { 3245 OutString += (sal_Unicode) 0x1B; 3246 OutString += rInfo.sStrArray[i].GetChar(1); 3247 bRes = sal_True; 3248 } 3249 break; 3250 case NF_SYMBOLTYPE_BLANK: 3251 InsertBlanks( OutString, OutString.Len(), 3252 rInfo.sStrArray[i].GetChar(1) ); 3253 break; 3254 case NF_SYMBOLTYPE_STRING: 3255 case NF_SYMBOLTYPE_CURRENCY: 3256 case NF_SYMBOLTYPE_DATESEP: 3257 case NF_SYMBOLTYPE_TIMESEP: 3258 case NF_SYMBOLTYPE_TIME100SECSEP: 3259 OutString += rInfo.sStrArray[i]; 3260 break; 3261 case NF_SYMBOLTYPE_DIGIT: 3262 { 3263 xub_StrLen nLen = ( bInputLine && i > 0 && 3264 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 3265 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 3266 nCntPost : rInfo.sStrArray[i].Len() ); 3267 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 3268 { 3269 OutString += sSecStr.GetChar(nSecPos); 3270 nSecPos++; 3271 } 3272 } 3273 break; 3274 case NF_KEY_AMPM: // AM/PM 3275 { 3276 if (cAmPm == 'a') 3277 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3278 AmPmValue::AM, 0 ); 3279 else 3280 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3281 AmPmValue::PM, 0 ); 3282 } 3283 break; 3284 case NF_KEY_AP: // A/P 3285 { 3286 if (cAmPm == 'a') 3287 OutString += 'a'; 3288 else 3289 OutString += 'p'; 3290 } 3291 break; 3292 case NF_KEY_MI: // M 3293 OutString += ImpIntToString( nIx, nMin ); 3294 break; 3295 case NF_KEY_MMI: // MM 3296 OutString += ImpIntToString( nIx, nMin, 2 ); 3297 break; 3298 case NF_KEY_H: // H 3299 OutString += ImpIntToString( nIx, nHour ); 3300 break; 3301 case NF_KEY_HH: // HH 3302 OutString += ImpIntToString( nIx, nHour, 2 ); 3303 break; 3304 case NF_KEY_S: // S 3305 OutString += ImpIntToString( nIx, nSec ); 3306 break; 3307 case NF_KEY_SS: // SS 3308 OutString += ImpIntToString( nIx, nSec, 2 ); 3309 break; 3310 case NF_KEY_M: // M 3311 OutString += rCal.getDisplayString( 3312 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 3313 break; 3314 case NF_KEY_MM: // MM 3315 OutString += rCal.getDisplayString( 3316 CalendarDisplayCode::LONG_MONTH, nNatNum ); 3317 break; 3318 case NF_KEY_MMM: // MMM 3319 OutString += rCal.getDisplayString( 3320 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 3321 break; 3322 case NF_KEY_MMMM: // MMMM 3323 OutString += rCal.getDisplayString( 3324 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 3325 break; 3326 case NF_KEY_MMMMM: // MMMMM 3327 OutString += rCal.getDisplayString( 3328 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 3329 break; 3330 case NF_KEY_Q: // Q 3331 OutString += rCal.getDisplayString( 3332 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 3333 break; 3334 case NF_KEY_QQ: // QQ 3335 OutString += rCal.getDisplayString( 3336 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3337 break; 3338 case NF_KEY_D: // D 3339 OutString += rCal.getDisplayString( 3340 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3341 break; 3342 case NF_KEY_DD: // DD 3343 OutString += rCal.getDisplayString( 3344 CalendarDisplayCode::LONG_DAY, nNatNum ); 3345 break; 3346 case NF_KEY_DDD: // DDD 3347 { 3348 if ( bOtherCalendar ) 3349 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3350 OutString += rCal.getDisplayString( 3351 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3352 if ( bOtherCalendar ) 3353 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3354 } 3355 break; 3356 case NF_KEY_DDDD: // DDDD 3357 { 3358 if ( bOtherCalendar ) 3359 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3360 OutString += rCal.getDisplayString( 3361 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3362 if ( bOtherCalendar ) 3363 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3364 } 3365 break; 3366 case NF_KEY_YY: // YY 3367 { 3368 if ( bOtherCalendar ) 3369 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3370 OutString += rCal.getDisplayString( 3371 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3372 if ( bOtherCalendar ) 3373 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3374 } 3375 break; 3376 case NF_KEY_YYYY: // YYYY 3377 { 3378 if ( bOtherCalendar ) 3379 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3380 OutString += rCal.getDisplayString( 3381 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3382 if ( bOtherCalendar ) 3383 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3384 } 3385 break; 3386 case NF_KEY_EC: // E 3387 OutString += rCal.getDisplayString( 3388 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3389 break; 3390 case NF_KEY_EEC: // EE 3391 case NF_KEY_R: // R 3392 OutString += rCal.getDisplayString( 3393 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3394 break; 3395 case NF_KEY_NN: // NN 3396 case NF_KEY_AAA: // AAA 3397 OutString += rCal.getDisplayString( 3398 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3399 break; 3400 case NF_KEY_NNN: // NNN 3401 case NF_KEY_AAAA: // AAAA 3402 OutString += rCal.getDisplayString( 3403 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3404 break; 3405 case NF_KEY_NNNN: // NNNN 3406 { 3407 OutString += rCal.getDisplayString( 3408 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3409 OutString += rLoc().getLongDateDayOfWeekSep(); 3410 } 3411 break; 3412 case NF_KEY_WW : // WW 3413 { 3414 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3415 OutString += ImpIntToString( nIx, nVal ); 3416 } 3417 break; 3418 case NF_KEY_G: // G 3419 ImpAppendEraG( OutString, rCal, nNatNum ); 3420 break; 3421 case NF_KEY_GG: // GG 3422 OutString += rCal.getDisplayString( 3423 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3424 break; 3425 case NF_KEY_GGG: // GGG 3426 OutString += rCal.getDisplayString( 3427 CalendarDisplayCode::LONG_ERA, nNatNum ); 3428 break; 3429 case NF_KEY_RR: // RR => GGGEE 3430 OutString += rCal.getDisplayString( 3431 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3432 break; 3433 } 3434 } 3435 if ( aOrgCalendar.Len() ) 3436 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3437 return bRes; 3438 } 3439 3440 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber, 3441 sal_uInt16 nIx, 3442 String& OutString) 3443 { 3444 sal_Bool bRes = sal_False; 3445 sal_Bool bSign; 3446 if (fNumber < 0.0) 3447 { 3448 if (nIx == 0) // nicht in hinteren 3449 bSign = sal_True; // Formaten 3450 else 3451 bSign = sal_False; 3452 fNumber = -fNumber; 3453 } 3454 else 3455 { 3456 bSign = sal_False; 3457 if ( ::rtl::math::isSignBitSet( fNumber ) ) 3458 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-' 3459 } 3460 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3461 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT) 3462 { 3463 if (fNumber < _D_MAX_D_BY_100) 3464 fNumber *= 100.0; 3465 else 3466 { 3467 OutString = rScan.GetErrorString(); 3468 return sal_False; 3469 } 3470 } 3471 sal_uInt16 i, j; 3472 xub_StrLen k; 3473 String sStr; 3474 long nPrecExp; 3475 sal_Bool bInteger = sal_False; 3476 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) 3477 { // special formatting only if no GENERAL keyword in format code 3478 const sal_uInt16 nThousand = rInfo.nThousand; 3479 for (i = 0; i < nThousand; i++) 3480 { 3481 if (fNumber > _D_MIN_M_BY_1000) 3482 fNumber /= 1000.0; 3483 else 3484 fNumber = 0.0; 3485 } 3486 if (fNumber > 0.0) 3487 nPrecExp = GetPrecExp( fNumber ); 3488 else 3489 nPrecExp = 0; 3490 if (rInfo.nCntPost) // NachkommaStellen 3491 { 3492 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15) 3493 { 3494 sStr = ::rtl::math::doubleToUString( fNumber, 3495 rtl_math_StringFormat_F, 15-nPrecExp, '.'); 3496 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++) 3497 sStr += '0'; 3498 } 3499 else 3500 sStr = ::rtl::math::doubleToUString( fNumber, 3501 rtl_math_StringFormat_F, rInfo.nCntPost, '.' ); 3502 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3503 } 3504 else if (fNumber == 0.0) // Null 3505 { 3506 // nothing to be done here, keep empty string sStr, 3507 // ImpNumberFillWithThousands does the rest 3508 } 3509 else // Integer 3510 { 3511 sStr = ::rtl::math::doubleToUString( fNumber, 3512 rtl_math_StringFormat_F, 0, '.'); 3513 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3514 } 3515 xub_StrLen nPoint = sStr.Search( '.' ); 3516 if ( nPoint != STRING_NOTFOUND ) 3517 { 3518 register const sal_Unicode* p = sStr.GetBuffer() + nPoint; 3519 while ( *++p == '0' ) 3520 ; 3521 if ( !*p ) 3522 bInteger = sal_True; 3523 sStr.Erase( nPoint, 1 ); // . herausnehmen 3524 } 3525 if (bSign && 3526 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000 3527 bSign = sal_False; // nicht -0.00 3528 } // End of != FLAG_STANDARD_IN_FORMAT 3529 3530 // von hinten nach vorn 3531 // editieren: 3532 k = sStr.Len(); // hinter letzter Ziffer 3533 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol 3534 // Nachkommastellen: 3535 if (rInfo.nCntPost > 0) 3536 { 3537 sal_Bool bTrailing = sal_True; // ob Endnullen? 3538 sal_Bool bFilled = sal_False; // ob aufgefuellt wurde ? 3539 short nType; 3540 while (j > 0 && // rueckwaerts 3541 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP) 3542 { 3543 switch ( nType ) 3544 { 3545 case NF_SYMBOLTYPE_STAR: 3546 if( bStarFlag ) 3547 { 3548 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ ); 3549 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3550 bRes = sal_True; 3551 } 3552 break; 3553 case NF_SYMBOLTYPE_BLANK: 3554 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3555 break; 3556 case NF_SYMBOLTYPE_STRING: 3557 case NF_SYMBOLTYPE_CURRENCY: 3558 case NF_SYMBOLTYPE_PERCENT: 3559 sStr.Insert(rInfo.sStrArray[j],k); 3560 break; 3561 case NF_SYMBOLTYPE_THSEP: 3562 if (rInfo.nThousand == 0) 3563 sStr.Insert(rInfo.sStrArray[j],k); 3564 break; 3565 case NF_SYMBOLTYPE_DIGIT: 3566 { 3567 const String& rStr = rInfo.sStrArray[j]; 3568 const sal_Unicode* p1 = rStr.GetBuffer(); 3569 register const sal_Unicode* p = p1 + rStr.Len(); 3570 while ( p1 < p-- ) 3571 { 3572 const sal_Unicode c = *p; 3573 k--; 3574 if ( sStr.GetChar(k) != '0' ) 3575 bTrailing = sal_False; 3576 if (bTrailing) 3577 { 3578 if ( c == '0' ) 3579 bFilled = sal_True; 3580 else if ( c == '-' ) 3581 { 3582 if ( bInteger ) 3583 sStr.SetChar( k, '-' ); 3584 bFilled = sal_True; 3585 } 3586 else if ( c == '?' ) 3587 { 3588 sStr.SetChar( k, ' ' ); 3589 bFilled = sal_True; 3590 } 3591 else if ( !bFilled ) // # 3592 sStr.Erase(k,1); 3593 } 3594 } // of for 3595 } // of case digi 3596 break; 3597 case NF_KEY_CCC: // CCC-Waehrung 3598 sStr.Insert(rScan.GetCurAbbrev(), k); 3599 break; 3600 case NF_KEY_GENERAL: // Standard im String 3601 { 3602 String sNum; 3603 ImpGetOutputStandard(fNumber, sNum); 3604 sNum.EraseLeadingChars('-'); 3605 sStr.Insert(sNum, k); 3606 } 3607 break; 3608 default: 3609 break; 3610 } // of switch 3611 j--; 3612 } // of while 3613 } // of Nachkomma 3614 3615 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit . 3616 rInfo.nCntPre); 3617 if ( rInfo.nCntPost > 0 ) 3618 { 3619 const String& rDecSep = GetFormatter().GetNumDecimalSep(); 3620 xub_StrLen nLen = rDecSep.Len(); 3621 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) ) 3622 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep 3623 } 3624 if (bSign) 3625 sStr.Insert('-',0); 3626 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 3627 OutString = sStr; 3628 return bRes; 3629 } 3630 3631 sal_Bool SvNumberformat::ImpNumberFillWithThousands( 3632 String& sStr, // number string 3633 double& rNumber, // number 3634 xub_StrLen k, // position within string 3635 sal_uInt16 j, // symbol index within format code 3636 sal_uInt16 nIx, // subformat index 3637 sal_uInt16 nDigCnt) // count of integer digits in format 3638 { 3639 sal_Bool bRes = sal_False; 3640 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number 3641 xub_StrLen nDigitCount = 0; // count of integer digits from the right 3642 sal_Bool bStop = sal_False; 3643 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3644 // no normal thousands separators if number divided by thousands 3645 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3646 utl::DigitGroupingIterator aGrouping( 3647 GetFormatter().GetLocaleData()->getDigitGrouping()); 3648 while (!bStop) // backwards 3649 { 3650 if (j == 0) 3651 bStop = sal_True; 3652 switch (rInfo.nTypeArray[j]) 3653 { 3654 case NF_SYMBOLTYPE_DECSEP: 3655 aGrouping.reset(); 3656 // fall thru 3657 case NF_SYMBOLTYPE_STRING: 3658 case NF_SYMBOLTYPE_CURRENCY: 3659 case NF_SYMBOLTYPE_PERCENT: 3660 sStr.Insert(rInfo.sStrArray[j],k); 3661 if ( k == 0 ) 3662 nLeadingStringChars = 3663 nLeadingStringChars + rInfo.sStrArray[j].Len(); 3664 break; 3665 case NF_SYMBOLTYPE_STAR: 3666 if( bStarFlag ) 3667 { 3668 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ ); 3669 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3670 bRes = sal_True; 3671 } 3672 break; 3673 case NF_SYMBOLTYPE_BLANK: 3674 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3675 break; 3676 case NF_SYMBOLTYPE_THSEP: 3677 { 3678 // #i7284# #102685# Insert separator also if number is divided 3679 // by thousands and the separator is specified somewhere in 3680 // between and not only at the end. 3681 // #i12596# But do not insert if it's a parenthesized negative 3682 // format like (#,) 3683 // In fact, do not insert if divided and regex [0#,],[^0#] and 3684 // no other digit symbol follows (which was already detected 3685 // during scan of format code, otherwise there would be no 3686 // division), else do insert. Same in ImpNumberFill() below. 3687 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3688 bDoThousands = ((j == 0) || 3689 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3690 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3691 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3692 if ( bDoThousands ) 3693 { 3694 if (k > 0) 3695 sStr.Insert(rInfo.sStrArray[j],k); 3696 else if (nDigitCount < nDigCnt) 3697 { 3698 // Leading '#' displays nothing (e.g. no leading 3699 // separator for numbers <1000 with #,##0 format). 3700 // Leading '?' displays blank. 3701 // Everything else, including nothing, displays the 3702 // separator. 3703 sal_Unicode cLeader = 0; 3704 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT) 3705 { 3706 const String& rStr = rInfo.sStrArray[j-1]; 3707 xub_StrLen nLen = rStr.Len(); 3708 if (nLen) 3709 cLeader = rStr.GetChar(nLen-1); 3710 } 3711 switch (cLeader) 3712 { 3713 case '#': 3714 ; // nothing 3715 break; 3716 case '?': 3717 // erAck: 2008-04-03T16:24+0200 3718 // Actually this currently isn't executed 3719 // because the format scanner in the context of 3720 // "?," doesn't generate a group separator but 3721 // a literal ',' character instead that is 3722 // inserted unconditionally. Should be changed 3723 // on some occasion. 3724 sStr.Insert(' ',k); 3725 break; 3726 default: 3727 sStr.Insert(rInfo.sStrArray[j],k); 3728 } 3729 } 3730 aGrouping.advance(); 3731 } 3732 } 3733 break; 3734 case NF_SYMBOLTYPE_DIGIT: 3735 { 3736 const String& rStr = rInfo.sStrArray[j]; 3737 const sal_Unicode* p1 = rStr.GetBuffer(); 3738 register const sal_Unicode* p = p1 + rStr.Len(); 3739 while ( p1 < p-- ) 3740 { 3741 nDigitCount++; 3742 if (k > 0) 3743 k--; 3744 else 3745 { 3746 switch (*p) 3747 { 3748 case '0': 3749 sStr.Insert('0',0); 3750 break; 3751 case '?': 3752 sStr.Insert(' ',0); 3753 break; 3754 } 3755 } 3756 if (nDigitCount == nDigCnt && k > 0) 3757 { // more digits than specified 3758 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping); 3759 } 3760 } 3761 } 3762 break; 3763 case NF_KEY_CCC: // CCC currency 3764 sStr.Insert(rScan.GetCurAbbrev(), k); 3765 break; 3766 case NF_KEY_GENERAL: // "General" in string 3767 { 3768 String sNum; 3769 ImpGetOutputStandard(rNumber, sNum); 3770 sNum.EraseLeadingChars('-'); 3771 sStr.Insert(sNum, k); 3772 } 3773 break; 3774 3775 default: 3776 break; 3777 } // switch 3778 j--; // next format code string 3779 } // while 3780 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ... 3781 if (k > nLeadingStringChars) 3782 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping); 3783 return bRes; 3784 } 3785 3786 void SvNumberformat::ImpDigitFill( 3787 String& sStr, // number string 3788 xub_StrLen nStart, // start of digits 3789 xub_StrLen& k, // position within string 3790 sal_uInt16 nIx, // subformat index 3791 xub_StrLen & nDigitCount, // count of integer digits from the right so far 3792 utl::DigitGroupingIterator & rGrouping ) // current grouping 3793 { 3794 if (NumFor[nIx].Info().bThousand) // only if grouping 3795 { // fill in separators 3796 const String& rThousandSep = GetFormatter().GetNumThousandSep(); 3797 while (k > nStart) 3798 { 3799 if (nDigitCount == rGrouping.getPos()) 3800 { 3801 sStr.Insert( rThousandSep, k ); 3802 rGrouping.advance(); 3803 } 3804 nDigitCount++; 3805 k--; 3806 } 3807 } 3808 else // simply skip 3809 k = nStart; 3810 } 3811 3812 sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string 3813 double& rNumber, // number for "General" format 3814 xub_StrLen& k, // position within string 3815 sal_uInt16& j, // symbol index within format code 3816 sal_uInt16 nIx, // subformat index 3817 short eSymbolType ) // type of stop condition 3818 { 3819 sal_Bool bRes = sal_False; 3820 k = sStr.Len(); // behind last digit 3821 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3822 // no normal thousands separators if number divided by thousands 3823 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3824 short nType; 3825 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) 3826 { // rueckwaerts: 3827 switch ( nType ) 3828 { 3829 case NF_SYMBOLTYPE_STAR: 3830 if( bStarFlag ) 3831 { 3832 sStr.Insert( sal_Unicode(0x1B), k++ ); 3833 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3834 bRes = sal_True; 3835 } 3836 break; 3837 case NF_SYMBOLTYPE_BLANK: 3838 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3839 break; 3840 case NF_SYMBOLTYPE_THSEP: 3841 { 3842 // Same as in ImpNumberFillWithThousands() above, do not insert 3843 // if divided and regex [0#,],[^0#] and no other digit symbol 3844 // follows (which was already detected during scan of format 3845 // code, otherwise there would be no division), else do insert. 3846 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3847 bDoThousands = ((j == 0) || 3848 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3849 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3850 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3851 if ( bDoThousands && k > 0 ) 3852 { 3853 sStr.Insert(rInfo.sStrArray[j],k); 3854 } 3855 } 3856 break; 3857 case NF_SYMBOLTYPE_DIGIT: 3858 { 3859 const String& rStr = rInfo.sStrArray[j]; 3860 const sal_Unicode* p1 = rStr.GetBuffer(); 3861 register const sal_Unicode* p = p1 + rStr.Len(); 3862 while ( p1 < p-- ) 3863 { 3864 if (k > 0) 3865 k--; 3866 else 3867 { 3868 switch (*p) 3869 { 3870 case '0': 3871 sStr.Insert('0',0); 3872 break; 3873 case '?': 3874 sStr.Insert(' ',0); 3875 break; 3876 } 3877 } 3878 } 3879 } 3880 break; 3881 case NF_KEY_CCC: // CCC-Waehrung 3882 sStr.Insert(rScan.GetCurAbbrev(), k); 3883 break; 3884 case NF_KEY_GENERAL: // Standard im String 3885 { 3886 String sNum; 3887 ImpGetOutputStandard(rNumber, sNum); 3888 sNum.EraseLeadingChars('-'); // Vorzeichen weg!! 3889 sStr.Insert(sNum, k); 3890 } 3891 break; 3892 3893 default: 3894 sStr.Insert(rInfo.sStrArray[j],k); 3895 break; 3896 } // of switch 3897 j--; // naechster String 3898 } // of while 3899 return bRes; 3900 } 3901 3902 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand, 3903 sal_Bool& IsRed, 3904 sal_uInt16& nPrecision, 3905 sal_uInt16& nAnzLeading) const 3906 { 3907 // as before: take info from nNumFor=0 for whole format (for dialog etc.) 3908 3909 short nDummyType; 3910 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading ); 3911 3912 // "negative in red" is only useful for the whole format 3913 3914 const Color* pColor = NumFor[1].GetColor(); 3915 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor 3916 && (*pColor == rScan.GetRedColor())) 3917 IsRed = sal_True; 3918 else 3919 IsRed = sal_False; 3920 } 3921 3922 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType, 3923 sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const 3924 { 3925 // take info from a specified sub-format (for XML export) 3926 3927 if ( nNumFor > 3 ) 3928 return; // invalid 3929 3930 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); 3931 rScannedType = rInfo.eScannedType; 3932 bThousand = rInfo.bThousand; 3933 nPrecision = rInfo.nCntPost; 3934 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER) 3935 // StandardFormat 3936 nAnzLeading = 1; 3937 else 3938 { 3939 nAnzLeading = 0; 3940 sal_Bool bStop = sal_False; 3941 sal_uInt16 i = 0; 3942 const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3943 while (!bStop && i < nAnz) 3944 { 3945 short nType = rInfo.nTypeArray[i]; 3946 if ( nType == NF_SYMBOLTYPE_DIGIT) 3947 { 3948 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer(); 3949 while ( *p == '#' ) 3950 p++; 3951 while ( *p++ == '0' ) 3952 nAnzLeading++; 3953 } 3954 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP) 3955 bStop = sal_True; 3956 i++; 3957 } 3958 } 3959 } 3960 3961 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, 3962 sal_Bool bString /* = sal_False */ ) const 3963 { 3964 if ( nNumFor > 3 ) 3965 return NULL; 3966 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3967 if ( !nAnz ) 3968 return NULL; 3969 if ( nPos == 0xFFFF ) 3970 { 3971 nPos = nAnz - 1; 3972 if ( bString ) 3973 { // rueckwaerts 3974 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3975 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3976 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3977 { 3978 pType--; 3979 nPos--; 3980 } 3981 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3982 return NULL; 3983 } 3984 } 3985 else if ( nPos > nAnz - 1 ) 3986 return NULL; 3987 else if ( bString ) 3988 { // vorwaerts 3989 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3990 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 3991 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3992 { 3993 pType++; 3994 nPos++; 3995 } 3996 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) && 3997 (*pType != NF_SYMBOLTYPE_CURRENCY)) ) 3998 return NULL; 3999 } 4000 return &NumFor[nNumFor].Info().sStrArray[nPos]; 4001 } 4002 4003 4004 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos, 4005 sal_Bool bString /* = sal_False */ ) const 4006 { 4007 if ( nNumFor > 3 ) 4008 return 0; 4009 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 4010 if ( !nAnz ) 4011 return 0; 4012 if ( nPos == 0xFFFF ) 4013 { 4014 nPos = nAnz - 1; 4015 if ( bString ) 4016 { // rueckwaerts 4017 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4018 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 4019 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4020 { 4021 pType--; 4022 nPos--; 4023 } 4024 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4025 return 0; 4026 } 4027 } 4028 else if ( nPos > nAnz - 1 ) 4029 return 0; 4030 else if ( bString ) 4031 { // vorwaerts 4032 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4033 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 4034 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4035 { 4036 pType++; 4037 nPos++; 4038 } 4039 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4040 return 0; 4041 } 4042 return NumFor[nNumFor].Info().nTypeArray[nPos]; 4043 } 4044 4045 4046 sal_Bool SvNumberformat::IsNegativeWithoutSign() const 4047 { 4048 if ( IsNegativeRealNegative() ) 4049 { 4050 const String* pStr = GetNumForString( 1, 0, sal_True ); 4051 if ( pStr ) 4052 return !HasStringNegativeSign( *pStr ); 4053 } 4054 return sal_False; 4055 } 4056 4057 4058 DateFormat SvNumberformat::GetDateOrder() const 4059 { 4060 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE ) 4061 { 4062 short const * const pType = NumFor[0].Info().nTypeArray; 4063 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4064 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4065 { 4066 switch ( pType[j] ) 4067 { 4068 case NF_KEY_D : 4069 case NF_KEY_DD : 4070 return DMY; 4071 case NF_KEY_M : 4072 case NF_KEY_MM : 4073 case NF_KEY_MMM : 4074 case NF_KEY_MMMM : 4075 case NF_KEY_MMMMM : 4076 return MDY; 4077 case NF_KEY_YY : 4078 case NF_KEY_YYYY : 4079 case NF_KEY_EC : 4080 case NF_KEY_EEC : 4081 case NF_KEY_R : 4082 case NF_KEY_RR : 4083 return YMD; 4084 } 4085 } 4086 } 4087 else 4088 { 4089 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" ); 4090 } 4091 return rLoc().getDateFormat(); 4092 } 4093 4094 4095 sal_uInt32 SvNumberformat::GetExactDateOrder() const 4096 { 4097 sal_uInt32 nRet = 0; 4098 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE ) 4099 { 4100 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" ); 4101 return nRet; 4102 } 4103 short const * const pType = NumFor[0].Info().nTypeArray; 4104 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4105 int nShift = 0; 4106 for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ ) 4107 { 4108 switch ( pType[j] ) 4109 { 4110 case NF_KEY_D : 4111 case NF_KEY_DD : 4112 nRet = (nRet << 8) | 'D'; 4113 ++nShift; 4114 break; 4115 case NF_KEY_M : 4116 case NF_KEY_MM : 4117 case NF_KEY_MMM : 4118 case NF_KEY_MMMM : 4119 case NF_KEY_MMMMM : 4120 nRet = (nRet << 8) | 'M'; 4121 ++nShift; 4122 break; 4123 case NF_KEY_YY : 4124 case NF_KEY_YYYY : 4125 case NF_KEY_EC : 4126 case NF_KEY_EEC : 4127 case NF_KEY_R : 4128 case NF_KEY_RR : 4129 nRet = (nRet << 8) | 'Y'; 4130 ++nShift; 4131 break; 4132 } 4133 } 4134 return nRet; 4135 } 4136 4137 4138 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, 4139 SvNumberformatLimitOps& rOper2, double& rVal2 ) const 4140 { 4141 rOper1 = eOp1; 4142 rOper2 = eOp2; 4143 rVal1 = fLimit1; 4144 rVal2 = fLimit2; 4145 } 4146 4147 4148 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const 4149 { 4150 if ( nNumFor > 3 ) 4151 return NULL; 4152 4153 return NumFor[nNumFor].GetColor(); 4154 } 4155 4156 4157 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr, 4158 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep ) 4159 { 4160 if ( eOp != NUMBERFORMAT_OP_NO ) 4161 { 4162 switch ( eOp ) 4163 { 4164 case NUMBERFORMAT_OP_EQ : 4165 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) ); 4166 break; 4167 case NUMBERFORMAT_OP_NE : 4168 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) ); 4169 break; 4170 case NUMBERFORMAT_OP_LT : 4171 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) ); 4172 break; 4173 case NUMBERFORMAT_OP_LE : 4174 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) ); 4175 break; 4176 case NUMBERFORMAT_OP_GT : 4177 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) ); 4178 break; 4179 case NUMBERFORMAT_OP_GE : 4180 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) ); 4181 break; 4182 default: 4183 OSL_ASSERT( "unsupported number format" ); 4184 break; 4185 } 4186 rStr += String( ::rtl::math::doubleToUString( fLimit, 4187 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 4188 rDecSep.GetChar(0), sal_True)); 4189 rStr += ']'; 4190 } 4191 } 4192 4193 4194 String SvNumberformat::GetMappedFormatstring( 4195 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp, 4196 sal_Bool bDontQuote ) const 4197 { 4198 String aStr; 4199 sal_Bool bDefault[4]; 4200 // 1 subformat matches all if no condition specified, 4201 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); 4202 // with 2 subformats [>=0];[<0] is implied if no condition specified 4203 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 && 4204 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 && 4205 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 ); 4206 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified, 4207 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked. 4208 bDefault[2] = ( !bDefault[0] && !bDefault[1] && 4209 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 && 4210 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 ); 4211 sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; 4212 // from now on bDefault[] values are used to append empty subformats at the end 4213 bDefault[3] = sal_False; 4214 if ( !bDefaults ) 4215 { // conditions specified 4216 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) 4217 bDefault[0] = bDefault[1] = sal_True; // [];x 4218 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && 4219 NumFor[2].GetnAnz() == 0 ) 4220 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];; 4221 // nothing to do if conditions specified for every subformat 4222 } 4223 else if ( bDefault[0] ) 4224 bDefault[0] = sal_False; // a single unconditional subformat is never delimited 4225 else 4226 { 4227 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 ) 4228 bDefault[3] = sal_True; // special cases x;x;; and ;x;; 4229 for ( int i=0; i<3 && !bDefault[i]; ++i ) 4230 bDefault[i] = sal_True; 4231 } 4232 int nSem = 0; // needed ';' delimiters 4233 int nSub = 0; // subformats delimited so far 4234 for ( int n=0; n<4; n++ ) 4235 { 4236 if ( n > 0 ) 4237 nSem++; 4238 4239 String aPrefix; 4240 4241 if ( !bDefaults ) 4242 { 4243 switch ( n ) 4244 { 4245 case 0 : 4246 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1, 4247 fLimit1, rLocWrp.getNumDecimalSep() ); 4248 break; 4249 case 1 : 4250 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2, 4251 fLimit2, rLocWrp.getNumDecimalSep() ); 4252 break; 4253 } 4254 } 4255 4256 const String& rColorName = NumFor[n].GetColorName(); 4257 if ( rColorName.Len() ) 4258 { 4259 const NfKeywordTable & rKey = rScan.GetKeywords(); 4260 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ ) 4261 { 4262 if ( rKey[j] == rColorName ) 4263 { 4264 aPrefix += '['; 4265 aPrefix += rKeywords[j]; 4266 aPrefix += ']'; 4267 break; // for 4268 } 4269 } 4270 } 4271 4272 const SvNumberNatNum& rNum = NumFor[n].GetNatNum(); 4273 // The Thai T NatNum modifier during Xcl export. 4274 if (rNum.IsSet() && rNum.GetNatNum() == 1 && 4275 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") && 4276 MsLangId::getRealLanguage( rNum.GetLang()) == 4277 LANGUAGE_THAI) 4278 { 4279 aPrefix += 't'; // must be lowercase, otherwise taken as literal 4280 } 4281 4282 sal_uInt16 nAnz = NumFor[n].GetnAnz(); 4283 if ( nSem && (nAnz || aPrefix.Len()) ) 4284 { 4285 for ( ; nSem; --nSem ) 4286 aStr += ';'; 4287 for ( ; nSub <= n; ++nSub ) 4288 bDefault[nSub] = sal_False; 4289 } 4290 4291 if ( aPrefix.Len() ) 4292 aStr += aPrefix; 4293 4294 if ( nAnz ) 4295 { 4296 const short* pType = NumFor[n].Info().nTypeArray; 4297 const String* pStr = NumFor[n].Info().sStrArray; 4298 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4299 { 4300 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT ) 4301 { 4302 aStr += rKeywords[pType[j]]; 4303 if( NF_KEY_NNNN == pType[j] ) 4304 aStr += rLocWrp.getLongDateDayOfWeekSep(); 4305 } 4306 else 4307 { 4308 switch ( pType[j] ) 4309 { 4310 case NF_SYMBOLTYPE_DECSEP : 4311 aStr += rLocWrp.getNumDecimalSep(); 4312 break; 4313 case NF_SYMBOLTYPE_THSEP : 4314 aStr += rLocWrp.getNumThousandSep(); 4315 break; 4316 case NF_SYMBOLTYPE_DATESEP : 4317 aStr += rLocWrp.getDateSep(); 4318 break; 4319 case NF_SYMBOLTYPE_TIMESEP : 4320 aStr += rLocWrp.getTimeSep(); 4321 break; 4322 case NF_SYMBOLTYPE_TIME100SECSEP : 4323 aStr += rLocWrp.getTime100SecSep(); 4324 break; 4325 case NF_SYMBOLTYPE_STRING : 4326 if( bDontQuote ) 4327 aStr += pStr[j]; 4328 else if ( pStr[j].Len() == 1 ) 4329 { 4330 aStr += '\\'; 4331 aStr += pStr[j]; 4332 } 4333 else 4334 { 4335 aStr += '"'; 4336 aStr += pStr[j]; 4337 aStr += '"'; 4338 } 4339 break; 4340 default: 4341 aStr += pStr[j]; 4342 } 4343 4344 } 4345 } 4346 } 4347 } 4348 for ( ; nSub<4 && bDefault[nSub]; ++nSub ) 4349 { // append empty subformats 4350 aStr += ';'; 4351 } 4352 return aStr; 4353 } 4354 4355 4356 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum, 4357 sal_Int32 nVal, sal_uInt16 nMinDigits ) const 4358 { 4359 String aStr; 4360 if ( nMinDigits ) 4361 { 4362 if ( nMinDigits == 2 ) 4363 { // speed up the most common case 4364 if ( 0 <= nVal && nVal < 10 ) 4365 { 4366 sal_Unicode* p = aStr.AllocBuffer( 2 ); 4367 *p++ = '0'; 4368 *p = sal_Unicode( '0' + nVal ); 4369 } 4370 else 4371 aStr = String::CreateFromInt32( nVal ); 4372 } 4373 else 4374 { 4375 String aValStr( String::CreateFromInt32( nVal ) ); 4376 if ( aValStr.Len() >= nMinDigits ) 4377 aStr = aValStr; 4378 else 4379 { 4380 aStr.Fill( nMinDigits - aValStr.Len(), '0' ); 4381 aStr += aValStr; 4382 } 4383 } 4384 } 4385 else 4386 aStr = String::CreateFromInt32( nVal ); 4387 ImpTransliterate( aStr, rNum ); 4388 return aStr; 4389 } 4390 4391 4392 void SvNumberformat::ImpTransliterateImpl( String& rStr, 4393 const SvNumberNatNum& rNum ) const 4394 { 4395 com::sun::star::lang::Locale aLocale( 4396 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4397 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr, 4398 aLocale, rNum.GetNatNum() ); 4399 } 4400 4401 4402 void SvNumberformat::GetNatNumXml( 4403 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr, 4404 sal_uInt16 nNumFor ) const 4405 { 4406 if ( nNumFor <= 3 ) 4407 { 4408 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); 4409 if ( rNum.IsSet() ) 4410 { 4411 com::sun::star::lang::Locale aLocale( 4412 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4413 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes( 4414 aLocale, rNum.GetNatNum() ); 4415 } 4416 else 4417 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4418 } 4419 else 4420 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4421 } 4422 4423 // static 4424 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr ) 4425 { 4426 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored) 4427 xub_StrLen nLen = rStr.Len(); 4428 if ( !nLen ) 4429 return sal_False; 4430 const sal_Unicode* const pBeg = rStr.GetBuffer(); 4431 const sal_Unicode* const pEnd = pBeg + nLen; 4432 register const sal_Unicode* p = pBeg; 4433 do 4434 { // Anfang 4435 if ( *p == '-' ) 4436 return sal_True; 4437 } while ( *p == ' ' && ++p < pEnd ); 4438 p = pEnd - 1; 4439 do 4440 { // Ende 4441 if ( *p == '-' ) 4442 return sal_True; 4443 } while ( *p == ' ' && pBeg < --p ); 4444 return sal_False; 4445 } 4446 4447 4448 // static 4449 void SvNumberformat::SetComment( const String& rStr, String& rFormat, 4450 String& rComment ) 4451 { 4452 if ( rComment.Len() ) 4453 { // alten Kommentar aus Formatstring loeschen 4454 //! nicht per EraseComment, der Kommentar muss matchen 4455 String aTmp( '{' ); 4456 aTmp += ' '; 4457 aTmp += rComment; 4458 aTmp += ' '; 4459 aTmp += '}'; 4460 xub_StrLen nCom = 0; 4461 do 4462 { 4463 nCom = rFormat.Search( aTmp, nCom ); 4464 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) ); 4465 if ( nCom != STRING_NOTFOUND ) 4466 rFormat.Erase( nCom ); 4467 } 4468 if ( rStr.Len() ) 4469 { // neuen Kommentar setzen 4470 rFormat += '{'; 4471 rFormat += ' '; 4472 rFormat += rStr; 4473 rFormat += ' '; 4474 rFormat += '}'; 4475 rComment = rStr; 4476 } 4477 } 4478 4479 4480 // static 4481 void SvNumberformat::EraseCommentBraces( String& rStr ) 4482 { 4483 xub_StrLen nLen = rStr.Len(); 4484 if ( nLen && rStr.GetChar(0) == '{' ) 4485 { 4486 rStr.Erase( 0, 1 ); 4487 --nLen; 4488 } 4489 if ( nLen && rStr.GetChar(0) == ' ' ) 4490 { 4491 rStr.Erase( 0, 1 ); 4492 --nLen; 4493 } 4494 if ( nLen && rStr.GetChar( nLen-1 ) == '}' ) 4495 rStr.Erase( --nLen, 1 ); 4496 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' ) 4497 rStr.Erase( --nLen, 1 ); 4498 } 4499 4500 4501 // static 4502 void SvNumberformat::EraseComment( String& rStr ) 4503 { 4504 register const sal_Unicode* p = rStr.GetBuffer(); 4505 sal_Bool bInString = sal_False; 4506 sal_Bool bEscaped = sal_False; 4507 sal_Bool bFound = sal_False; 4508 xub_StrLen nPos = 0; 4509 while ( !bFound && *p ) 4510 { 4511 switch ( *p ) 4512 { 4513 case '\\' : 4514 bEscaped = !bEscaped; 4515 break; 4516 case '\"' : 4517 if ( !bEscaped ) 4518 bInString = !bInString; 4519 break; 4520 case '{' : 4521 if ( !bEscaped && !bInString ) 4522 { 4523 bFound = sal_True; 4524 nPos = sal::static_int_cast< xub_StrLen >( 4525 p - rStr.GetBuffer()); 4526 } 4527 break; 4528 } 4529 if ( bEscaped && *p != '\\' ) 4530 bEscaped = sal_False; 4531 ++p; 4532 } 4533 if ( bFound ) 4534 rStr.Erase( nPos ); 4535 } 4536 4537 4538 // static 4539 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos, 4540 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4541 { 4542 xub_StrLen nLen = rStr.Len(); 4543 if ( nPos >= nLen ) 4544 return sal_False; 4545 register const sal_Unicode* p0 = rStr.GetBuffer(); 4546 register const sal_Unicode* p = p0; 4547 register const sal_Unicode* p1 = p0 + nPos; 4548 sal_Bool bQuoted = sal_False; 4549 while ( p <= p1 ) 4550 { 4551 if ( *p == cQuote ) 4552 { 4553 if ( p == p0 ) 4554 bQuoted = sal_True; 4555 else if ( bQuoted ) 4556 { 4557 if ( *(p-1) != cEscIn ) 4558 bQuoted = sal_False; 4559 } 4560 else 4561 { 4562 if ( *(p-1) != cEscOut ) 4563 bQuoted = sal_True; 4564 } 4565 } 4566 p++; 4567 } 4568 return bQuoted; 4569 } 4570 4571 4572 // static 4573 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos, 4574 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4575 { 4576 xub_StrLen nLen = rStr.Len(); 4577 if ( nPos >= nLen ) 4578 return STRING_NOTFOUND; 4579 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) ) 4580 { 4581 if ( rStr.GetChar( nPos ) == cQuote ) 4582 return nPos; // schliessendes cQuote 4583 return STRING_NOTFOUND; 4584 } 4585 register const sal_Unicode* p0 = rStr.GetBuffer(); 4586 register const sal_Unicode* p = p0 + nPos; 4587 register const sal_Unicode* p1 = p0 + nLen; 4588 while ( p < p1 ) 4589 { 4590 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn ) 4591 return sal::static_int_cast< xub_StrLen >(p - p0); 4592 p++; 4593 } 4594 return nLen; // String Ende 4595 } 4596 4597 4598 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const 4599 { 4600 sal_uInt16 nCnt = 0; 4601 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 4602 short const * const pType = NumFor[nNumFor].Info().nTypeArray; 4603 for ( sal_uInt16 j=0; j<nAnz; ++j ) 4604 { 4605 switch ( pType[j] ) 4606 { 4607 case NF_SYMBOLTYPE_STRING: 4608 case NF_SYMBOLTYPE_CURRENCY: 4609 case NF_SYMBOLTYPE_DATESEP: 4610 case NF_SYMBOLTYPE_TIMESEP: 4611 case NF_SYMBOLTYPE_TIME100SECSEP: 4612 case NF_SYMBOLTYPE_PERCENT: 4613 ++nCnt; 4614 break; 4615 } 4616 } 4617 return nCnt; 4618 } 4619 4620