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_xmloff.hxx" 26 27 #define _SVSTDARR_ULONGS 28 #define _ZFORLIST_DECLARE_TABLE 29 30 #include <svl/svstdarr.hxx> 31 #include <svl/zforlist.hxx> 32 #include <svl/zformat.hxx> 33 #include <svl/numuno.hxx> 34 #include <i18npool/mslangid.hxx> 35 #include <tools/debug.hxx> 36 #include <rtl/math.hxx> 37 #include <unotools/calendarwrapper.hxx> 38 #include <unotools/charclass.hxx> 39 #include <com/sun/star/lang/Locale.hpp> 40 #include <rtl/ustrbuf.hxx> 41 42 // #110680# 43 //#include <comphelper/processfactory.hxx> 44 45 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp> 46 47 #include <xmloff/xmlnumfe.hxx> 48 #include "xmloff/xmlnmspe.hxx" 49 #include <xmloff/xmluconv.hxx> 50 #include <xmloff/attrlist.hxx> 51 #include <xmloff/nmspmap.hxx> 52 #include <xmloff/families.hxx> 53 #include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults 54 55 #define _SVSTDARR_USHORTS 56 #include <svl/svstdarr.hxx> 57 #include <svl/nfsymbol.hxx> 58 #include <xmloff/xmltoken.hxx> 59 #include <xmloff/xmlexp.hxx> 60 61 #include <set> 62 63 using ::rtl::OUString; 64 using ::rtl::OUStringBuffer; 65 66 using namespace ::com::sun::star; 67 using namespace ::xmloff::token; 68 using namespace ::svt; 69 70 //------------------------------------------------------------------------- 71 72 // 4th condition for text formats doesn't work 73 //#define XMLNUM_MAX_PARTS 4 74 #define XMLNUM_MAX_PARTS 3 75 76 //------------------------------------------------------------------------- 77 78 struct LessuInt32 79 { 80 sal_Bool operator() (const sal_uInt32 rValue1, const sal_uInt32 rValue2) const 81 { 82 return rValue1 < rValue2; 83 } 84 }; 85 86 typedef std::set< sal_uInt32, LessuInt32 > SvXMLuInt32Set; 87 88 class SvXMLNumUsedList_Impl 89 { 90 SvXMLuInt32Set aUsed; 91 SvXMLuInt32Set aWasUsed; 92 SvXMLuInt32Set::iterator aCurrentUsedPos; 93 sal_uInt32 nUsedCount; 94 sal_uInt32 nWasUsedCount; 95 96 public: 97 SvXMLNumUsedList_Impl(); 98 ~SvXMLNumUsedList_Impl(); 99 100 void SetUsed( sal_uInt32 nKey ); 101 sal_Bool IsUsed( sal_uInt32 nKey ) const; 102 sal_Bool IsWasUsed( sal_uInt32 nKey ) const; 103 void Export(); 104 105 sal_Bool GetFirstUsed(sal_uInt32& nKey); 106 sal_Bool GetNextUsed(sal_uInt32& nKey); 107 108 void GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed); 109 void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed); 110 }; 111 112 //------------------------------------------------------------------------- 113 114 struct SvXMLEmbeddedTextEntry 115 { 116 sal_uInt16 nSourcePos; // position in NumberFormat (to skip later) 117 sal_Int32 nFormatPos; // resulting position in embedded-text element 118 rtl::OUString aText; 119 120 SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const rtl::OUString& rT ) : 121 nSourcePos(nSP), nFormatPos(nFP), aText(rT) {} 122 }; 123 124 typedef SvXMLEmbeddedTextEntry* SvXMLEmbeddedTextEntryPtr; 125 SV_DECL_PTRARR_DEL( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr, 4, 4 ) 126 127 //------------------------------------------------------------------------- 128 129 SV_IMPL_PTRARR( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr ); 130 131 //------------------------------------------------------------------------- 132 133 // 134 //! SvXMLNumUsedList_Impl should be optimized! 135 // 136 137 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() : 138 nUsedCount(0), 139 nWasUsedCount(0) 140 { 141 } 142 143 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl() 144 { 145 } 146 147 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey ) 148 { 149 if ( !IsWasUsed(nKey) ) 150 { 151 std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey ); 152 if (aPair.second) 153 nUsedCount++; 154 } 155 } 156 157 sal_Bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const 158 { 159 SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey); 160 return (aItr != aUsed.end()); 161 } 162 163 sal_Bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const 164 { 165 SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey); 166 return (aItr != aWasUsed.end()); 167 } 168 169 void SvXMLNumUsedList_Impl::Export() 170 { 171 SvXMLuInt32Set::iterator aItr = aUsed.begin(); 172 while (aItr != aUsed.end()) 173 { 174 std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *aItr ); 175 if (aPair.second) 176 nWasUsedCount++; 177 aItr++; 178 } 179 aUsed.clear(); 180 nUsedCount = 0; 181 } 182 183 sal_Bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey) 184 { 185 sal_Bool bRet(sal_False); 186 aCurrentUsedPos = aUsed.begin(); 187 if(nUsedCount) 188 { 189 DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong"); 190 nKey = *aCurrentUsedPos; 191 bRet = sal_True; 192 } 193 return bRet; 194 } 195 196 sal_Bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey) 197 { 198 sal_Bool bRet(sal_False); 199 if (aCurrentUsedPos != aUsed.end()) 200 { 201 aCurrentUsedPos++; 202 if (aCurrentUsedPos != aUsed.end()) 203 { 204 nKey = *aCurrentUsedPos; 205 bRet = sal_True; 206 } 207 } 208 return bRet; 209 } 210 211 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed) 212 { 213 rWasUsed.realloc(nWasUsedCount); 214 sal_Int32* pWasUsed = rWasUsed.getArray(); 215 if (pWasUsed) 216 { 217 SvXMLuInt32Set::iterator aItr = aWasUsed.begin(); 218 while (aItr != aWasUsed.end()) 219 { 220 *pWasUsed = *aItr; 221 aItr++; 222 pWasUsed++; 223 } 224 } 225 } 226 227 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed) 228 { 229 DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty"); 230 sal_Int32 nCount(rWasUsed.getLength()); 231 const sal_Int32* pWasUsed = rWasUsed.getConstArray(); 232 for (sal_uInt16 i = 0; i < nCount; i++, pWasUsed++) 233 { 234 std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *pWasUsed ); 235 if (aPair.second) 236 nWasUsedCount++; 237 } 238 } 239 240 //------------------------------------------------------------------------- 241 242 SvXMLNumFmtExport::SvXMLNumFmtExport( 243 SvXMLExport& rExp, 244 const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) : 245 rExport( rExp ), 246 sPrefix( OUString::createFromAscii( "N" ) ), 247 pFormatter( NULL ), 248 pCharClass( NULL ), 249 pLocaleData( NULL ) 250 { 251 // supplier must be SvNumberFormatsSupplierObj 252 SvNumberFormatsSupplierObj* pObj = 253 SvNumberFormatsSupplierObj::getImplementation( rSupp ); 254 if (pObj) 255 pFormatter = pObj->GetNumberFormatter(); 256 257 if ( pFormatter ) 258 { 259 pCharClass = new CharClass( pFormatter->GetServiceManager(), 260 pFormatter->GetLocale() ); 261 pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(), 262 pFormatter->GetLocale() ); 263 } 264 else 265 { 266 lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) ); 267 268 // #110680# 269 // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale ); 270 // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale ); 271 pCharClass = new CharClass( rExport.getServiceFactory(), aLocale ); 272 pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale ); 273 } 274 275 pUsedList = new SvXMLNumUsedList_Impl; 276 } 277 278 SvXMLNumFmtExport::SvXMLNumFmtExport( 279 SvXMLExport& rExp, 280 const ::com::sun::star::uno::Reference< 281 ::com::sun::star::util::XNumberFormatsSupplier >& rSupp, 282 const rtl::OUString& rPrefix ) : 283 rExport( rExp ), 284 sPrefix( rPrefix ), 285 pFormatter( NULL ), 286 pCharClass( NULL ), 287 pLocaleData( NULL ) 288 { 289 // supplier must be SvNumberFormatsSupplierObj 290 SvNumberFormatsSupplierObj* pObj = 291 SvNumberFormatsSupplierObj::getImplementation( rSupp ); 292 if (pObj) 293 pFormatter = pObj->GetNumberFormatter(); 294 295 if ( pFormatter ) 296 { 297 pCharClass = new CharClass( pFormatter->GetServiceManager(), 298 pFormatter->GetLocale() ); 299 pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(), 300 pFormatter->GetLocale() ); 301 } 302 else 303 { 304 lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) ); 305 306 // #110680# 307 // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale ); 308 // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale ); 309 pCharClass = new CharClass( rExport.getServiceFactory(), aLocale ); 310 pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale ); 311 } 312 313 pUsedList = new SvXMLNumUsedList_Impl; 314 } 315 316 SvXMLNumFmtExport::~SvXMLNumFmtExport() 317 { 318 delete pUsedList; 319 delete pLocaleData; 320 delete pCharClass; 321 } 322 323 //------------------------------------------------------------------------- 324 325 // 326 // helper methods 327 // 328 329 OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, sal_Bool bDefPart, const rtl::OUString& rPrefix ) 330 { 331 OUStringBuffer aFmtName( 10L ); 332 aFmtName.append( rPrefix ); 333 aFmtName.append( nKey ); 334 if (!bDefPart) 335 { 336 aFmtName.append( (sal_Unicode)'P' ); 337 aFmtName.append( nPart ); 338 } 339 return aFmtName.makeStringAndClear(); 340 } 341 342 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar ) 343 { 344 if ( rCalendar.getLength() ) 345 { 346 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar ); 347 } 348 } 349 350 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText ) 351 { 352 if ( bText ) // non-textual 353 { 354 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE ); 355 } 356 } 357 358 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong ) 359 { 360 if ( bLong ) // short is default 361 { 362 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG ); 363 } 364 } 365 366 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang ) 367 { 368 if ( nLang != LANGUAGE_SYSTEM ) 369 { 370 OUString aLangStr, aCountryStr; 371 MsLangId::convertLanguageToIsoNames( (LanguageType)nLang, aLangStr, aCountryStr ); 372 373 if (aLangStr.getLength()) 374 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_LANGUAGE, aLangStr ); 375 if (aCountryStr.getLength()) 376 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_COUNTRY, aCountryStr ); 377 } 378 } 379 380 //------------------------------------------------------------------------- 381 382 // 383 // methods to write individual elements within a format 384 // 385 386 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString ) 387 { 388 // append to sTextContent, write element in FinishTextElement_Impl 389 // to avoid several text elements following each other 390 391 sTextContent.append( rString ); 392 } 393 394 void SvXMLNumFmtExport::FinishTextElement_Impl() 395 { 396 if ( sTextContent.getLength() ) 397 { 398 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT, 399 sal_True, sal_False ); 400 rExport.Characters( sTextContent.makeStringAndClear() ); 401 } 402 } 403 404 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor ) 405 { 406 FinishTextElement_Impl(); 407 408 OUStringBuffer aColStr( 7 ); 409 SvXMLUnitConverter::convertColor( aColStr, rColor ); 410 rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR, 411 aColStr.makeStringAndClear() ); 412 413 SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, 414 sal_True, sal_False ); 415 } 416 417 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString, 418 const OUString& rExt ) 419 { 420 FinishTextElement_Impl(); 421 422 if ( rExt.getLength() ) 423 { 424 sal_Int32 nLang = rExt.toInt32(16); // hex 425 if ( nLang < 0 ) // extension string may contain "-" separator 426 nLang = -nLang; 427 AddLanguageAttr_Impl( nLang ); // adds to pAttrList 428 } 429 430 SvXMLElementExport aElem( rExport, 431 XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, 432 sal_True, sal_False ); 433 rExport.Characters( rString ); 434 } 435 436 void SvXMLNumFmtExport::WriteBooleanElement_Impl() 437 { 438 FinishTextElement_Impl(); 439 440 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN, 441 sal_True, sal_False ); 442 } 443 444 void SvXMLNumFmtExport::WriteTextContentElement_Impl() 445 { 446 FinishTextElement_Impl(); 447 448 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, 449 sal_True, sal_False ); 450 } 451 452 // date elements 453 454 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, sal_Bool bLong ) 455 { 456 FinishTextElement_Impl(); 457 458 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 459 AddStyleAttr_Impl( bLong ); // adds to pAttrList 460 461 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY, 462 sal_True, sal_False ); 463 } 464 465 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, sal_Bool bLong, sal_Bool bText ) 466 { 467 FinishTextElement_Impl(); 468 469 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 470 AddStyleAttr_Impl( bLong ); // adds to pAttrList 471 AddTextualAttr_Impl( bText ); // adds to pAttrList 472 473 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH, 474 sal_True, sal_False ); 475 } 476 477 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, sal_Bool bLong ) 478 { 479 FinishTextElement_Impl(); 480 481 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 482 AddStyleAttr_Impl( bLong ); // adds to pAttrList 483 484 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR, 485 sal_True, sal_False ); 486 } 487 488 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, sal_Bool bLong ) 489 { 490 FinishTextElement_Impl(); 491 492 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 493 AddStyleAttr_Impl( bLong ); // adds to pAttrList 494 495 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA, 496 sal_True, sal_False ); 497 } 498 499 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, sal_Bool bLong ) 500 { 501 FinishTextElement_Impl(); 502 503 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 504 AddStyleAttr_Impl( bLong ); // adds to pAttrList 505 506 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, 507 sal_True, sal_False ); 508 } 509 510 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar ) 511 { 512 FinishTextElement_Impl(); 513 514 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 515 516 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, 517 sal_True, sal_False ); 518 } 519 520 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, sal_Bool bLong ) 521 { 522 FinishTextElement_Impl(); 523 524 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList 525 AddStyleAttr_Impl( bLong ); // adds to pAttrList 526 527 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER, 528 sal_True, sal_False ); 529 } 530 531 // time elements 532 533 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong ) 534 { 535 FinishTextElement_Impl(); 536 537 AddStyleAttr_Impl( bLong ); // adds to pAttrList 538 539 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS, 540 sal_True, sal_False ); 541 } 542 543 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong ) 544 { 545 FinishTextElement_Impl(); 546 547 AddStyleAttr_Impl( bLong ); // adds to pAttrList 548 549 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES, 550 sal_True, sal_False ); 551 } 552 553 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong, sal_uInt16 nDecimals ) 554 { 555 FinishTextElement_Impl(); 556 557 AddStyleAttr_Impl( bLong ); // adds to pAttrList 558 if ( nDecimals > 0 ) 559 { 560 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, 561 OUString::valueOf( (sal_Int32) nDecimals ) ); 562 } 563 564 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS, 565 sal_True, sal_False ); 566 } 567 568 void SvXMLNumFmtExport::WriteAMPMElement_Impl() 569 { 570 FinishTextElement_Impl(); 571 572 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM, 573 sal_True, sal_False ); 574 } 575 576 // numbers 577 578 void SvXMLNumFmtExport::WriteNumberElement_Impl( 579 sal_Int32 nDecimals, sal_Int32 nInteger, 580 const OUString& rDashStr, sal_Bool bVarDecimals, 581 sal_Bool bGrouping, sal_Int32 nTrailingThousands, 582 const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) 583 { 584 FinishTextElement_Impl(); 585 586 // decimals 587 if ( nDecimals >= 0 ) // negative = automatic 588 { 589 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, 590 OUString::valueOf( nDecimals ) ); 591 } 592 593 // integer digits 594 if ( nInteger >= 0 ) // negative = automatic 595 { 596 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, 597 OUString::valueOf( nInteger ) ); 598 } 599 600 // decimal replacement (dashes) or variable decimals (#) 601 if ( rDashStr.getLength() || bVarDecimals ) 602 { 603 // variable decimals means an empty replacement string 604 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, 605 rDashStr ); 606 } 607 608 // (automatic) grouping separator 609 if ( bGrouping ) 610 { 611 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); 612 } 613 614 // display-factor if there are trailing thousands separators 615 if ( nTrailingThousands ) 616 { 617 // each separator character removes three digits 618 double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands ); 619 620 OUStringBuffer aFactStr; 621 SvXMLUnitConverter::convertDouble( aFactStr, fFactor ); 622 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() ); 623 } 624 625 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER, 626 sal_True, sal_True ); 627 628 // number:embedded-text as child elements 629 630 sal_uInt16 nEntryCount = rEmbeddedEntries.Count(); 631 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++) 632 { 633 SvXMLEmbeddedTextEntry* pObj = rEmbeddedEntries[nEntry]; 634 635 // position attribute 636 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION, 637 OUString::valueOf( pObj->nFormatPos ) ); 638 SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, 639 sal_True, sal_False ); 640 641 // text as element content 642 rtl::OUString aContent( pObj->aText ); 643 while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1]->nFormatPos == pObj->nFormatPos ) 644 { 645 // The array can contain several elements for the same position in the number 646 // (for example, literal text and space from underscores). They must be merged 647 // into a single embedded-text element. 648 aContent += rEmbeddedEntries[nEntry+1]->aText; 649 ++nEntry; 650 } 651 rExport.Characters( aContent ); 652 } 653 } 654 655 void SvXMLNumFmtExport::WriteScientificElement_Impl( 656 sal_Int32 nDecimals, sal_Int32 nInteger, 657 sal_Bool bGrouping, sal_Int32 nExp ) 658 { 659 FinishTextElement_Impl(); 660 661 // decimals 662 if ( nDecimals >= 0 ) // negative = automatic 663 { 664 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, 665 OUString::valueOf( nDecimals ) ); 666 } 667 668 // integer digits 669 if ( nInteger >= 0 ) // negative = automatic 670 { 671 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, 672 OUString::valueOf( nInteger ) ); 673 } 674 675 // (automatic) grouping separator 676 if ( bGrouping ) 677 { 678 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); 679 } 680 681 // exponent digits 682 if ( nExp >= 0 ) 683 { 684 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, 685 OUString::valueOf( nExp ) ); 686 } 687 688 SvXMLElementExport aElem( rExport, 689 XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, 690 sal_True, sal_False ); 691 } 692 693 void SvXMLNumFmtExport::WriteFractionElement_Impl( 694 sal_Int32 nInteger, sal_Bool bGrouping, 695 sal_Int32 nNumerator, sal_Int32 nDenominator ) 696 { 697 FinishTextElement_Impl(); 698 699 // integer digits 700 if ( nInteger >= 0 ) // negative = default (no integer part) 701 { 702 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, 703 OUString::valueOf( nInteger ) ); 704 } 705 706 // (automatic) grouping separator 707 if ( bGrouping ) 708 { 709 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); 710 } 711 712 // numerator digits 713 if ( nNumerator >= 0 ) 714 { 715 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, 716 OUString::valueOf( nNumerator ) ); 717 } 718 719 // denominator digits 720 if ( nDenominator >= 0 ) 721 { 722 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, 723 OUString::valueOf( nDenominator ) ); 724 } 725 726 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION, 727 sal_True, sal_False ); 728 } 729 730 // mapping (condition) 731 732 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit, 733 sal_Int32 nKey, sal_Int32 nPart ) 734 { 735 FinishTextElement_Impl(); 736 737 if ( nOp != NUMBERFORMAT_OP_NO ) 738 { 739 // style namespace 740 741 OUStringBuffer aCondStr( 20L ); 742 aCondStr.appendAscii( "value()" ); //! define constant 743 switch ( nOp ) 744 { 745 case NUMBERFORMAT_OP_EQ: aCondStr.append( (sal_Unicode) '=' ); break; 746 case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "<>" ); break; 747 case NUMBERFORMAT_OP_LT: aCondStr.append( (sal_Unicode) '<' ); break; 748 case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" ); break; 749 case NUMBERFORMAT_OP_GT: aCondStr.append( (sal_Unicode) '>' ); break; 750 case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" ); break; 751 default: 752 DBG_ERROR("unknown operator"); 753 } 754 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit, 755 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 756 '.', true ); 757 758 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION, 759 aCondStr.makeStringAndClear() ); 760 761 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME, 762 rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, sal_False, 763 sPrefix ) ) ); 764 765 SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP, 766 sal_True, sal_False ); 767 } 768 } 769 770 //------------------------------------------------------------------------- 771 // for old (automatic) currency formats: parse currency symbol from text 772 773 xub_StrLen lcl_FindSymbol( const String& sUpperStr, const String& sCurString ) 774 { 775 // search for currency symbol 776 // Quoting as in ImpSvNumberformatScan::Symbol_Division 777 778 xub_StrLen nCPos = 0; 779 while (nCPos != STRING_NOTFOUND) 780 { 781 nCPos = sUpperStr.Search( sCurString, nCPos ); 782 if (nCPos != STRING_NOTFOUND) 783 { 784 // in Quotes? 785 xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos ); 786 if ( nQ == STRING_NOTFOUND ) 787 { 788 // dm can be escaped as "dm or \d 789 sal_Unicode c; 790 if ( nCPos == 0 || 791 ((c = sUpperStr.GetChar(xub_StrLen(nCPos-1))) != '"' 792 && c != '\\') ) 793 { 794 return nCPos; // found 795 } 796 else 797 nCPos++; // continue 798 } 799 else 800 nCPos = nQ + 1; // continue after quote end 801 } 802 } 803 return STRING_NOTFOUND; // not found 804 } 805 806 sal_Bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString, 807 const ::com::sun::star::lang::Locale& rLocale ) 808 { 809 // returns sal_True if currency element was written 810 811 sal_Bool bRet = sal_False; 812 813 // pLocaleData->setLocale( rLocale ); 814 // String sCurString = pLocaleData->getCurrSymbol(); 815 816 LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale ); 817 pFormatter->ChangeIntl( nLang ); 818 String sCurString, sDummy; 819 pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); 820 821 pCharClass->setLocale( rLocale ); 822 String sUpperStr = pCharClass->upper(rString); 823 xub_StrLen nPos = lcl_FindSymbol( sUpperStr, sCurString ); 824 if ( nPos != STRING_NOTFOUND ) 825 { 826 sal_Int32 nLength = rString.getLength(); 827 sal_Int32 nCurLen = sCurString.Len(); 828 sal_Int32 nCont = nPos + nCurLen; 829 830 // text before currency symbol 831 if ( nPos > 0 ) 832 AddToTextElement_Impl( rString.copy( 0, nPos ) ); 833 834 // currency symbol (empty string -> default) 835 OUString sEmpty; 836 WriteCurrencyElement_Impl( sEmpty, sEmpty ); 837 bRet = sal_True; 838 839 // text after currency symbol 840 if ( nCont < nLength ) 841 AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) ); 842 } 843 else 844 AddToTextElement_Impl( rString ); // simple text 845 846 return bRet; // sal_True: currency element written 847 } 848 849 //------------------------------------------------------------------------- 850 851 OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang ) 852 { 853 // get name of first non-gregorian calendar for the language 854 855 OUString aCalendar; 856 CalendarWrapper* pCalendar = pFormatter->GetCalendar(); 857 if (pCalendar) 858 { 859 lang::Locale aLocale( MsLangId::convertLanguageToLocale( nLang ) ); 860 861 uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale ); 862 sal_Int32 nCnt = aCals.getLength(); 863 sal_Bool bFound = sal_False; 864 for ( sal_Int32 j=0; j < nCnt && !bFound; j++ ) 865 { 866 if ( !aCals[j].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gregorian") ) ) 867 { 868 aCalendar = aCals[j]; 869 bFound = sal_True; 870 } 871 } 872 } 873 return aCalendar; 874 } 875 876 //------------------------------------------------------------------------- 877 878 sal_Bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos ) 879 { 880 sal_uInt16 nCount = rEmbeddedEntries.Count(); 881 for (sal_uInt16 i=0; i<nCount; i++) 882 if ( rEmbeddedEntries[i]->nSourcePos == nPos ) 883 return sal_True; 884 885 return sal_False; // not found 886 } 887 888 sal_Bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, sal_Bool bSystemDate, NfIndexTableOffset eBuiltIn ) 889 { 890 // make an extra loop to collect date elements, to check if it is a default format 891 // before adding the automatic-order attribute 892 893 SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE; 894 SvXMLDateElementAttributes eDateDay = XML_DEA_NONE; 895 SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE; 896 SvXMLDateElementAttributes eDateYear = XML_DEA_NONE; 897 SvXMLDateElementAttributes eDateHours = XML_DEA_NONE; 898 SvXMLDateElementAttributes eDateMins = XML_DEA_NONE; 899 SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE; 900 sal_Bool bDateNoDefault = sal_False; 901 902 sal_uInt16 nPos = 0; 903 sal_Bool bEnd = sal_False; 904 short nLastType = 0; 905 while (!bEnd) 906 { 907 short nElemType = rFormat.GetNumForType( 0, nPos, sal_False ); 908 switch ( nElemType ) 909 { 910 case 0: 911 if ( nLastType == NF_SYMBOLTYPE_STRING ) 912 bDateNoDefault = sal_True; // text at the end -> no default date format 913 bEnd = sal_True; // end of format reached 914 break; 915 case NF_SYMBOLTYPE_STRING: 916 case NF_SYMBOLTYPE_DATESEP: 917 case NF_SYMBOLTYPE_TIMESEP: 918 case NF_SYMBOLTYPE_TIME100SECSEP: 919 // text is ignored, except at the end 920 break; 921 // same mapping as in SvXMLNumFormatContext::AddNfKeyword: 922 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; 923 case NF_KEY_NNN: 924 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; 925 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; 926 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; 927 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; 928 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; 929 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; 930 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; 931 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; 932 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; 933 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; 934 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; 935 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; 936 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; 937 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; 938 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; 939 case NF_KEY_AP: 940 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself 941 default: 942 bDateNoDefault = sal_True; // any other element -> no default format 943 } 944 nLastType = nElemType; 945 ++nPos; 946 } 947 948 if ( bDateNoDefault ) 949 return sal_False; // additional elements 950 else 951 { 952 NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat( 953 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate ); 954 955 return ( eFound == eBuiltIn ); 956 } 957 } 958 959 // 960 // export one part (condition) 961 // 962 963 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, 964 sal_uInt16 nPart, sal_Bool bDefPart ) 965 { 966 //! for the default part, pass the coditions from the other parts! 967 968 // 969 // element name 970 // 971 972 NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey ); 973 974 short nFmtType = 0; 975 sal_Bool bThousand = sal_False; 976 sal_uInt16 nPrecision = 0; 977 sal_uInt16 nLeading = 0; 978 rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading); 979 nFmtType &= ~NUMBERFORMAT_DEFINED; 980 981 // special treatment of builtin formats that aren't detected by normal parsing 982 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats) 983 if ( eBuiltIn == NF_NUMBER_STANDARD ) 984 nFmtType = NUMBERFORMAT_NUMBER; 985 else if ( eBuiltIn == NF_BOOLEAN ) 986 nFmtType = NUMBERFORMAT_LOGICAL; 987 else if ( eBuiltIn == NF_TEXT ) 988 nFmtType = NUMBERFORMAT_TEXT; 989 990 // #101606# An empty subformat is a valid number-style resulting in an 991 // empty display string for the condition of the subformat. 992 if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart, 993 0, sal_False ) == 0 ) 994 nFmtType = 0; 995 996 XMLTokenEnum eType = XML_TOKEN_INVALID; 997 switch ( nFmtType ) 998 { 999 // type is 0 if a format contains no recognized elements 1000 // (like text only) - this is handled as a number-style. 1001 case 0: 1002 case NUMBERFORMAT_NUMBER: 1003 case NUMBERFORMAT_SCIENTIFIC: 1004 case NUMBERFORMAT_FRACTION: 1005 eType = XML_NUMBER_STYLE; 1006 break; 1007 case NUMBERFORMAT_PERCENT: 1008 eType = XML_PERCENTAGE_STYLE; 1009 break; 1010 case NUMBERFORMAT_CURRENCY: 1011 eType = XML_CURRENCY_STYLE; 1012 break; 1013 case NUMBERFORMAT_DATE: 1014 case NUMBERFORMAT_DATETIME: 1015 eType = XML_DATE_STYLE; 1016 break; 1017 case NUMBERFORMAT_TIME: 1018 eType = XML_TIME_STYLE; 1019 break; 1020 case NUMBERFORMAT_TEXT: 1021 eType = XML_TEXT_STYLE; 1022 break; 1023 case NUMBERFORMAT_LOGICAL: 1024 eType = XML_BOOLEAN_STYLE; 1025 break; 1026 } 1027 DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" ); 1028 1029 OUString sAttrValue; 1030 sal_Bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 ); 1031 1032 // 1033 // common attributes for format 1034 // 1035 1036 // format name (generated from key) - style namespace 1037 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, 1038 lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) ); 1039 1040 // "volatile" attribute for styles used only in maps 1041 if ( !bDefPart ) 1042 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE ); 1043 1044 // language / country 1045 LanguageType nLang = rFormat.GetLanguage(); 1046 AddLanguageAttr_Impl( nLang ); // adds to pAttrList 1047 1048 // title (comment) 1049 // titles for builtin formats are not written 1050 sAttrValue = rFormat.GetComment(); 1051 if ( sAttrValue.getLength() && bUserDef && bDefPart ) 1052 { 1053 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue ); 1054 } 1055 1056 // automatic ordering for currency and date formats 1057 // only used for some built-in formats 1058 sal_Bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 || 1059 eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED || 1060 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED || 1061 eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG || 1062 eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM || 1063 eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY || 1064 eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY || 1065 eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY || 1066 eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY || 1067 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS ); 1068 1069 // format source (for date and time formats) 1070 // only used for some built-in formats 1071 sal_Bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT || 1072 eBuiltIn == NF_DATE_SYSTEM_LONG || 1073 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM ); 1074 sal_Bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG ); 1075 1076 // check if the format definition matches the key 1077 if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) && 1078 !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) ) 1079 { 1080 bAutoOrder = bSystemDate = bLongSysDate = sal_False; // don't write automatic-order attribute then 1081 } 1082 1083 if ( bAutoOrder && 1084 ( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) ) 1085 { 1086 // #85109# format type must be checked to avoid dtd errors if 1087 // locale data contains other format types at the built-in positions 1088 1089 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, 1090 XML_TRUE ); 1091 } 1092 1093 if ( bSystemDate && bAutoOrder && 1094 ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) ) 1095 { 1096 // #85109# format type must be checked to avoid dtd errors if 1097 // locale data contains other format types at the built-in positions 1098 1099 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, 1100 XML_LANGUAGE ); 1101 } 1102 1103 // overflow for time formats as in [hh]:mm 1104 // controlled by bThousand from number format info 1105 // default for truncate-on-overflow is true 1106 if ( nFmtType == NUMBERFORMAT_TIME && bThousand ) 1107 { 1108 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, 1109 XML_FALSE ); 1110 } 1111 1112 // 1113 // Native number transliteration 1114 // 1115 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr; 1116 rFormat.GetNatNumXml( aAttr, nPart ); 1117 if ( aAttr.Format.getLength() ) 1118 { 1119 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, 1120 aAttr.Format ); 1121 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, 1122 aAttr.Locale.Language ); 1123 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, 1124 aAttr.Locale.Country ); 1125 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, 1126 aAttr.Style ); 1127 } 1128 1129 // 1130 // The element 1131 // 1132 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType, 1133 sal_True, sal_True ); 1134 1135 // 1136 // color (properties element) 1137 // 1138 1139 const Color* pCol = rFormat.GetColor( nPart ); 1140 if (pCol) 1141 WriteColorElement_Impl(*pCol); 1142 1143 1144 // detect if there is "real" content, excluding color and maps 1145 //! move to implementation of Write... methods? 1146 sal_Bool bAnyContent = sal_False; 1147 1148 // 1149 // format elements 1150 // 1151 1152 SvXMLEmbeddedTextEntryArr aEmbeddedEntries(0); 1153 if ( eBuiltIn == NF_NUMBER_STANDARD ) 1154 { 1155 // default number format contains just one number element 1156 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries ); 1157 bAnyContent = sal_True; 1158 } 1159 else if ( eBuiltIn == NF_BOOLEAN ) 1160 { 1161 // boolean format contains just one boolean element 1162 WriteBooleanElement_Impl(); 1163 bAnyContent = sal_True; 1164 } 1165 else 1166 { 1167 // first loop to collect attributes 1168 1169 sal_Bool bDecDashes = sal_False; 1170 sal_Bool bVarDecimals = sal_False; 1171 sal_Bool bExpFound = sal_False; 1172 sal_Bool bCurrFound = sal_False; 1173 sal_Bool bInInteger = sal_True; 1174 sal_Int32 nExpDigits = 0; 1175 sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#" 1176 sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits 1177 OUString sCurrExt; 1178 OUString aCalendar; 1179 sal_uInt16 nPos = 0; 1180 sal_Bool bEnd = sal_False; 1181 while (!bEnd) 1182 { 1183 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False ); 1184 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False ); 1185 1186 switch ( nElemType ) 1187 { 1188 case 0: 1189 bEnd = sal_True; // end of format reached 1190 break; 1191 case NF_SYMBOLTYPE_DIGIT: 1192 if ( bExpFound && pElemStr ) 1193 nExpDigits += pElemStr->Len(); 1194 else if ( !bDecDashes && pElemStr && pElemStr->GetChar(0) == '-' ) 1195 bDecDashes = sal_True; 1196 else if ( !bVarDecimals && !bInInteger && pElemStr && pElemStr->GetChar(0) == '#' ) 1197 { 1198 // If the decimal digits string starts with a '#', variable 1199 // decimals is assumed (for 0.###, but not 0.0##). 1200 bVarDecimals = sal_True; 1201 } 1202 if ( bInInteger && pElemStr ) 1203 nIntegerSymbols += pElemStr->Len(); 1204 nTrailingThousands = 0; 1205 break; 1206 case NF_SYMBOLTYPE_DECSEP: 1207 bInInteger = sal_False; 1208 break; 1209 case NF_SYMBOLTYPE_THSEP: 1210 if (pElemStr) 1211 nTrailingThousands += pElemStr->Len(); // is reset to 0 if digits follow 1212 break; 1213 case NF_SYMBOLTYPE_EXP: 1214 bExpFound = sal_True; // following digits are exponent digits 1215 bInInteger = sal_False; 1216 break; 1217 case NF_SYMBOLTYPE_CURRENCY: 1218 bCurrFound = sal_True; 1219 break; 1220 case NF_SYMBOLTYPE_CURREXT: 1221 if (pElemStr) 1222 sCurrExt = *pElemStr; 1223 break; 1224 1225 // E, EE, R, RR: select non-gregorian calendar 1226 // AAA, AAAA: calendar is switched at the position of the element 1227 case NF_KEY_EC: 1228 case NF_KEY_EEC: 1229 case NF_KEY_R: 1230 case NF_KEY_RR: 1231 if (!aCalendar.getLength()) 1232 aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang ); 1233 break; 1234 } 1235 ++nPos; 1236 } 1237 1238 // collect strings for embedded-text (must be known before number element is written) 1239 1240 sal_Bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER || 1241 nFmtType == NUMBERFORMAT_CURRENCY || 1242 nFmtType == NUMBERFORMAT_PERCENT ); 1243 if ( bAllowEmbedded ) 1244 { 1245 sal_Int32 nDigitsPassed = 0; 1246 nPos = 0; 1247 bEnd = sal_False; 1248 while (!bEnd) 1249 { 1250 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False ); 1251 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False ); 1252 1253 switch ( nElemType ) 1254 { 1255 case 0: 1256 bEnd = sal_True; // end of format reached 1257 break; 1258 case NF_SYMBOLTYPE_DIGIT: 1259 if ( pElemStr ) 1260 nDigitsPassed += pElemStr->Len(); 1261 break; 1262 case NF_SYMBOLTYPE_STRING: 1263 case NF_SYMBOLTYPE_BLANK: 1264 case NF_SYMBOLTYPE_PERCENT: 1265 if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr ) 1266 { 1267 // text (literal or underscore) within the integer part of a number:number element 1268 1269 String aEmbeddedStr; 1270 if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT ) 1271 aEmbeddedStr = *pElemStr; 1272 else 1273 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, pElemStr->GetChar(1) ); 1274 1275 sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed; 1276 1277 SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr ); 1278 aEmbeddedEntries.Insert( pObj, aEmbeddedEntries.Count() ); 1279 } 1280 break; 1281 } 1282 ++nPos; 1283 } 1284 } 1285 1286 // final loop to write elements 1287 1288 sal_Bool bNumWritten = sal_False; 1289 sal_Bool bCurrencyWritten = sal_False; 1290 short nPrevType = 0; 1291 nPos = 0; 1292 bEnd = sal_False; 1293 while (!bEnd) 1294 { 1295 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False ); 1296 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False ); 1297 1298 switch ( nElemType ) 1299 { 1300 case 0: 1301 bEnd = sal_True; // end of format reached 1302 break; 1303 case NF_SYMBOLTYPE_STRING: 1304 case NF_SYMBOLTYPE_DATESEP: 1305 case NF_SYMBOLTYPE_TIMESEP: 1306 case NF_SYMBOLTYPE_TIME100SECSEP: 1307 case NF_SYMBOLTYPE_PERCENT: 1308 if (pElemStr) 1309 { 1310 if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) && 1311 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) && 1312 nPrecision > 0 ) 1313 { 1314 // decimal separator after seconds is implied by 1315 // "decimal-places" attribute and must not be written 1316 // as text element 1317 //! difference between '.' and ',' is lost here 1318 } 1319 else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) 1320 { 1321 // text is written as embedded-text child of the number, 1322 // don't create a text element 1323 } 1324 else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten ) 1325 { 1326 // automatic currency symbol is implemented as part of 1327 // normal text -> search for the symbol 1328 bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr, 1329 MsLangId::convertLanguageToLocale( nLang ) ); 1330 bAnyContent = sal_True; 1331 } 1332 else 1333 AddToTextElement_Impl( *pElemStr ); 1334 } 1335 break; 1336 case NF_SYMBOLTYPE_BLANK: 1337 if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) 1338 { 1339 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat 1340 // (#i20396# the spaces may also be in embedded-text elements) 1341 1342 String aBlanks; 1343 SvNumberformat::InsertBlanks( aBlanks, 0, pElemStr->GetChar(1) ); 1344 AddToTextElement_Impl( aBlanks ); 1345 } 1346 break; 1347 case NF_KEY_GENERAL : 1348 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries ); 1349 break; 1350 case NF_KEY_CCC: 1351 if (pElemStr) 1352 { 1353 if ( bCurrencyWritten ) 1354 AddToTextElement_Impl( *pElemStr ); // never more than one currency element 1355 else 1356 { 1357 //! must be different from short automatic format 1358 //! but should still be empty (meaning automatic) 1359 // pElemStr is "CCC" 1360 1361 WriteCurrencyElement_Impl( *pElemStr, OUString() ); 1362 bAnyContent = sal_True; 1363 bCurrencyWritten = sal_True; 1364 } 1365 } 1366 break; 1367 case NF_SYMBOLTYPE_CURRENCY: 1368 if (pElemStr) 1369 { 1370 if ( bCurrencyWritten ) 1371 AddToTextElement_Impl( *pElemStr ); // never more than one currency element 1372 else 1373 { 1374 WriteCurrencyElement_Impl( *pElemStr, sCurrExt ); 1375 bAnyContent = sal_True; 1376 bCurrencyWritten = sal_True; 1377 } 1378 } 1379 break; 1380 case NF_SYMBOLTYPE_DIGIT: 1381 if (!bNumWritten) // write number part 1382 { 1383 switch ( nFmtType ) 1384 { 1385 // for type 0 (not recognized as a special type), 1386 // write a "normal" number 1387 case 0: 1388 case NUMBERFORMAT_NUMBER: 1389 case NUMBERFORMAT_CURRENCY: 1390 case NUMBERFORMAT_PERCENT: 1391 { 1392 // decimals 1393 // only some built-in formats have automatic decimals 1394 sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo 1395 if ( eBuiltIn == NF_NUMBER_STANDARD || 1396 eBuiltIn == NF_CURRENCY_1000DEC2 || 1397 eBuiltIn == NF_CURRENCY_1000DEC2_RED || 1398 eBuiltIn == NF_CURRENCY_1000DEC2_CCC || 1399 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ) 1400 nDecimals = -1; 1401 1402 // integer digits 1403 // only one built-in format has automatic integer digits 1404 sal_Int32 nInteger = nLeading; 1405 if ( eBuiltIn == NF_NUMBER_SYSTEM ) 1406 nInteger = -1; 1407 1408 // string for decimal replacement 1409 // has to be taken from nPrecision 1410 // (positive number even for automatic decimals) 1411 String sDashStr; 1412 if ( bDecDashes && nPrecision > 0 ) 1413 sDashStr.Fill( nPrecision, '-' ); 1414 1415 WriteNumberElement_Impl( nDecimals, nInteger, sDashStr, bVarDecimals, 1416 bThousand, nTrailingThousands, aEmbeddedEntries ); 1417 bAnyContent = sal_True; 1418 } 1419 break; 1420 case NUMBERFORMAT_SCIENTIFIC: 1421 // #i43959# for scientific numbers, count all integer symbols ("0" and "#") 1422 // as integer digits: use nIntegerSymbols instead of nLeading 1423 // (use of '#' to select multiples in exponent might be added later) 1424 WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits ); 1425 bAnyContent = sal_True; 1426 break; 1427 case NUMBERFORMAT_FRACTION: 1428 { 1429 sal_Int32 nInteger = nLeading; 1430 if ( pElemStr && pElemStr->GetChar(0) == '?' ) 1431 { 1432 // If the first digit character is a question mark, 1433 // the fraction doesn't have an integer part, and no 1434 // min-integer-digits attribute must be written. 1435 nInteger = -1; 1436 } 1437 WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision ); 1438 bAnyContent = sal_True; 1439 } 1440 break; 1441 } 1442 1443 bNumWritten = sal_True; 1444 } 1445 break; 1446 case NF_SYMBOLTYPE_DECSEP: 1447 if ( pElemStr && nPrecision == 0 ) 1448 { 1449 // A decimal separator after the number, without following decimal digits, 1450 // isn't modelled as part of the number element, so it's written as text 1451 // (the distinction between a quoted and non-quoted, locale-dependent 1452 // character is lost here). 1453 1454 AddToTextElement_Impl( *pElemStr ); 1455 } 1456 break; 1457 case NF_SYMBOLTYPE_DEL: 1458 if ( pElemStr && *pElemStr == XubString('@') ) 1459 { 1460 WriteTextContentElement_Impl(); 1461 bAnyContent = sal_True; 1462 } 1463 break; 1464 1465 case NF_SYMBOLTYPE_CALENDAR: 1466 if ( pElemStr ) 1467 aCalendar = *pElemStr; 1468 break; 1469 1470 // date elements: 1471 1472 case NF_KEY_D: 1473 case NF_KEY_DD: 1474 { 1475 sal_Bool bLong = ( nElemType == NF_KEY_DD ); 1476 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); 1477 bAnyContent = sal_True; 1478 } 1479 break; 1480 case NF_KEY_DDD: 1481 case NF_KEY_DDDD: 1482 case NF_KEY_NN: 1483 case NF_KEY_NNN: 1484 case NF_KEY_NNNN: 1485 case NF_KEY_AAA: 1486 case NF_KEY_AAAA: 1487 { 1488 OUString aCalAttr = aCalendar; 1489 if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA ) 1490 { 1491 // calendar attribute for AAA and AAAA is switched only for this element 1492 if (!aCalAttr.getLength()) 1493 aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang ); 1494 } 1495 1496 sal_Bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN || 1497 nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA ); 1498 WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) ); 1499 bAnyContent = sal_True; 1500 if ( nElemType == NF_KEY_NNNN ) 1501 { 1502 // write additional text element for separator 1503 pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) ); 1504 AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() ); 1505 } 1506 } 1507 break; 1508 case NF_KEY_M: 1509 case NF_KEY_MM: 1510 case NF_KEY_MMM: 1511 case NF_KEY_MMMM: 1512 case NF_KEY_MMMMM: //! first letter of month name, no attribute available 1513 { 1514 sal_Bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM ); 1515 sal_Bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM || 1516 nElemType == NF_KEY_MMMMM ); 1517 WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText ); 1518 bAnyContent = sal_True; 1519 } 1520 break; 1521 case NF_KEY_YY: 1522 case NF_KEY_YYYY: 1523 case NF_KEY_EC: 1524 case NF_KEY_EEC: 1525 case NF_KEY_R: //! R acts as EE, no attribute available 1526 { 1527 //! distinguish EE and R 1528 // calendar attribute for E and EE and R is set in first loop 1529 sal_Bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC || 1530 nElemType == NF_KEY_R ); 1531 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); 1532 bAnyContent = sal_True; 1533 } 1534 break; 1535 case NF_KEY_G: 1536 case NF_KEY_GG: 1537 case NF_KEY_GGG: 1538 case NF_KEY_RR: //! RR acts as GGGEE, no attribute available 1539 { 1540 //! distinguish GG and GGG and RR 1541 sal_Bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR ); 1542 WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); 1543 bAnyContent = sal_True; 1544 if ( nElemType == NF_KEY_RR ) 1545 { 1546 // calendar attribute for RR is set in first loop 1547 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : sal_True ) ); 1548 } 1549 } 1550 break; 1551 case NF_KEY_Q: 1552 case NF_KEY_QQ: 1553 { 1554 sal_Bool bLong = ( nElemType == NF_KEY_QQ ); 1555 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); 1556 bAnyContent = sal_True; 1557 } 1558 break; 1559 case NF_KEY_WW: 1560 WriteWeekElement_Impl( aCalendar ); 1561 bAnyContent = sal_True; 1562 break; 1563 1564 // time elements (bSystemDate is not used): 1565 1566 case NF_KEY_H: 1567 case NF_KEY_HH: 1568 WriteHoursElement_Impl( nElemType == NF_KEY_HH ); 1569 bAnyContent = sal_True; 1570 break; 1571 case NF_KEY_MI: 1572 case NF_KEY_MMI: 1573 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI ); 1574 bAnyContent = sal_True; 1575 break; 1576 case NF_KEY_S: 1577 case NF_KEY_SS: 1578 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision ); 1579 bAnyContent = sal_True; 1580 break; 1581 case NF_KEY_AMPM: 1582 case NF_KEY_AP: 1583 WriteAMPMElement_Impl(); // short/long? 1584 bAnyContent = sal_True; 1585 break; 1586 } 1587 nPrevType = nElemType; 1588 ++nPos; 1589 } 1590 } 1591 1592 if ( sTextContent.getLength() ) 1593 bAnyContent = sal_True; // element written in FinishTextElement_Impl 1594 1595 FinishTextElement_Impl(); // final text element - before maps 1596 1597 if ( !bAnyContent ) 1598 { 1599 // for an empty format, write an empty text element 1600 SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT, 1601 sal_True, sal_False ); 1602 } 1603 1604 // 1605 // mapping (conditions) must be last elements 1606 // 1607 1608 if (bDefPart) 1609 { 1610 SvNumberformatLimitOps eOp1, eOp2; 1611 double fLimit1, fLimit2; 1612 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 ); 1613 1614 WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 ); 1615 WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 ); 1616 1617 if ( rFormat.HasTextFormat() ) 1618 { 1619 // 4th part is for text -> make an "all other numbers" condition for the 3rd part 1620 // by reversing the 2nd condition 1621 1622 SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO; 1623 double fLimit3 = fLimit2; 1624 switch ( eOp2 ) 1625 { 1626 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break; 1627 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break; 1628 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break; 1629 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break; 1630 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break; 1631 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break; 1632 default: 1633 break; 1634 } 1635 1636 if ( fLimit1 == fLimit2 && 1637 ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) || 1638 ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) ) 1639 { 1640 // For <x and >x, add =x as last condition 1641 // (just for readability, <=x would be valid, too) 1642 1643 eOp3 = NUMBERFORMAT_OP_EQ; 1644 } 1645 1646 WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 ); 1647 } 1648 } 1649 } 1650 1651 //------------------------------------------------------------------------- 1652 1653 // 1654 // export one format 1655 // 1656 1657 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey ) 1658 { 1659 sal_uInt16 nUsedParts = 0; 1660 sal_uInt16 nPart; 1661 for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++) 1662 if (rFormat.GetNumForType( nPart, 0, sal_False ) != 0) 1663 nUsedParts = nPart+1; 1664 1665 SvNumberformatLimitOps eOp1, eOp2; 1666 double fLimit1, fLimit2; 1667 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 ); 1668 1669 // if conditions are set, even empty formats must be written 1670 1671 if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 ) 1672 nUsedParts = 2; 1673 if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 ) 1674 nUsedParts = 3; 1675 if ( rFormat.HasTextFormat() && nUsedParts < 4 ) 1676 nUsedParts = 4; 1677 1678 for (nPart=0; nPart<nUsedParts; nPart++) 1679 { 1680 sal_Bool bDefault = ( nPart+1 == nUsedParts ); // last = default 1681 ExportPart_Impl( rFormat, nKey, nPart, bDefault ); 1682 } 1683 } 1684 1685 //------------------------------------------------------------------------- 1686 1687 // 1688 // export method called by application 1689 // 1690 1691 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle ) 1692 { 1693 if ( !pFormatter ) 1694 return; // no formatter -> no entries 1695 1696 sal_uInt32 nKey; 1697 const SvNumberformat* pFormat = NULL; 1698 sal_Bool bNext(pUsedList->GetFirstUsed(nKey)); 1699 while(bNext) 1700 { 1701 pFormat = pFormatter->GetEntry(nKey); 1702 if(pFormat) 1703 ExportFormat_Impl( *pFormat, nKey ); 1704 bNext = pUsedList->GetNextUsed(nKey); 1705 } 1706 if (!bIsAutoStyle) 1707 { 1708 SvUShorts aLanguages; 1709 pFormatter->GetUsedLanguages( aLanguages ); 1710 sal_uInt16 nLangCount = aLanguages.Count(); 1711 for (sal_uInt16 nLangPos=0; nLangPos<nLangCount; nLangPos++) 1712 { 1713 LanguageType nLang = aLanguages[nLangPos]; 1714 1715 sal_uInt32 nDefaultIndex = 0; 1716 SvNumberFormatTable& rTable = pFormatter->GetEntryTable( 1717 NUMBERFORMAT_DEFINED, nDefaultIndex, nLang ); 1718 pFormat = rTable.First(); 1719 while (pFormat) 1720 { 1721 nKey = rTable.GetCurKey(); 1722 if (!pUsedList->IsUsed(nKey)) 1723 { 1724 DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found"); 1725 // user-defined and used formats are exported 1726 ExportFormat_Impl( *pFormat, nKey ); 1727 // if it is a user-defined Format it will be added else nothing will hapen 1728 pUsedList->SetUsed(nKey); 1729 } 1730 1731 pFormat = rTable.Next(); 1732 } 1733 } 1734 } 1735 pUsedList->Export(); 1736 } 1737 1738 OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey ) 1739 { 1740 if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey)) 1741 return lcl_CreateStyleName( nKey, 0, sal_True, sPrefix ); 1742 else 1743 { 1744 DBG_ERROR("There is no written Data-Style"); 1745 return rtl::OUString(); 1746 } 1747 } 1748 1749 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey ) 1750 { 1751 DBG_ASSERT( pFormatter != NULL, "missing formatter" ); 1752 if( !pFormatter ) 1753 return; 1754 1755 if (pFormatter->GetEntry(nKey)) 1756 pUsedList->SetUsed( nKey ); 1757 else { 1758 DBG_ERROR("no existing Numberformat found with this key"); 1759 } 1760 } 1761 1762 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed) 1763 { 1764 if (pUsedList) 1765 pUsedList->GetWasUsed(rWasUsed); 1766 } 1767 1768 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed) 1769 { 1770 if (pUsedList) 1771 pUsedList->SetWasUsed(rWasUsed); 1772 } 1773 1774 1775 1776 const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter, 1777 sal_uInt32 nKey ) 1778 { 1779 return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL; 1780 } 1781 1782 sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey ) 1783 { 1784 sal_uInt32 nRet = nKey; 1785 1786 const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey ); 1787 if( pFormat != NULL ) 1788 { 1789 DBG_ASSERT( pFormatter != NULL, "format without formatter?" ); 1790 1791 xub_StrLen nErrorPos; 1792 short nType = pFormat->GetType(); 1793 1794 sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn( 1795 nKey, LANGUAGE_SYSTEM ); 1796 1797 if( nNewKey != nKey ) 1798 { 1799 nRet = nNewKey; 1800 } 1801 else 1802 { 1803 String aFormatString( pFormat->GetFormatstring() ); 1804 pFormatter->PutandConvertEntry( 1805 aFormatString, 1806 nErrorPos, nType, nNewKey, 1807 pFormat->GetLanguage(), LANGUAGE_SYSTEM ); 1808 1809 // success? Then use new key. 1810 if( nErrorPos == 0 ) 1811 nRet = nNewKey; 1812 } 1813 } 1814 1815 return nRet; 1816 } 1817