1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <svl/zforlist.hxx> 21 #include <svl/numformat.hxx> 22 #include <svl/zformat.hxx> 23 #include <svl/numuno.hxx> 24 #include <i18nlangtag/languagetag.hxx> 25 #include <tools/color.hxx> 26 #include <osl/diagnose.h> 27 #include <rtl/math.hxx> 28 #include <rtl/ustrbuf.hxx> 29 #include <sal/log.hxx> 30 31 #include <sax/tools/converter.hxx> 32 33 #include <utility> 34 #include <xmloff/xmlement.hxx> 35 #include <xmloff/xmlnumfi.hxx> 36 #include <xmloff/xmltkmap.hxx> 37 #include <xmloff/xmlnamespace.hxx> 38 #include <xmloff/xmlictxt.hxx> 39 #include <xmloff/xmlimp.hxx> 40 #include <xmloff/xmluconv.hxx> 41 #include <xmloff/namespacemap.hxx> 42 #include <xmloff/families.hxx> 43 #include <xmloff/xmltoken.hxx> 44 #include <xmloff/languagetagodf.hxx> 45 46 #include <memory> 47 #include <string_view> 48 #include <vector> 49 50 using namespace ::com::sun::star; 51 using namespace ::xmloff::token; 52 53 namespace { 54 55 struct SvXMLNumFmtEntry 56 { 57 OUString aName; 58 sal_uInt32 nKey; 59 bool bRemoveAfterUse; 60 61 SvXMLNumFmtEntry( OUString aN, sal_uInt32 nK, bool bR ) : 62 aName(std::move(aN)), nKey(nK), bRemoveAfterUse(bR) {} 63 }; 64 65 } 66 67 class SvXMLNumImpData 68 { 69 SvNumberFormatter* pFormatter; 70 std::unique_ptr<LocaleDataWrapper> pLocaleData; 71 std::vector<SvXMLNumFmtEntry> m_NameEntries; 72 73 uno::Reference< uno::XComponentContext > m_xContext; 74 75 public: 76 SvXMLNumImpData( 77 SvNumberFormatter* pFmt, 78 const uno::Reference<uno::XComponentContext>& rxContext ); 79 80 SvNumberFormatter* GetNumberFormatter() const { return pFormatter; } 81 const LocaleDataWrapper& GetLocaleData( LanguageType nLang ); 82 sal_uInt32 GetKeyForName( std::u16string_view rName ); 83 void AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ); 84 void SetUsed( sal_uInt32 nKey ); 85 void RemoveVolatileFormats(); 86 }; 87 88 struct SvXMLNumberInfo 89 { 90 sal_Int32 nDecimals = -1; 91 sal_Int32 nInteger = -1; /// Total min number of digits in integer part ('0' + '?') 92 sal_Int32 nBlankInteger = -1; /// Number of '?' in integer part 93 sal_Int32 nExpDigits = -1; 94 sal_Int32 nExpInterval = -1; 95 sal_Int32 nMinNumerDigits = -1; 96 sal_Int32 nMinDenomDigits = -1; 97 sal_Int32 nMaxNumerDigits = -1; 98 sal_Int32 nMaxDenomDigits = -1; 99 sal_Int32 nFracDenominator = -1; 100 sal_Int32 nMinDecimalDigits = -1; 101 sal_Int32 nZerosNumerDigits = -1; 102 sal_Int32 nZerosDenomDigits = -1; 103 bool bGrouping = false; 104 bool bDecReplace = false; 105 bool bExpSign = true; 106 bool bDecAlign = false; 107 double fDisplayFactor = 1.0; 108 OUString aIntegerFractionDelimiter; 109 std::map<sal_Int32, OUString> m_EmbeddedElements; 110 }; 111 112 namespace { 113 114 enum class SvXMLStyleTokens; 115 116 class SvXMLNumFmtElementContext : public SvXMLImportContext 117 { 118 SvXMLNumFormatContext& rParent; 119 SvXMLStyleTokens nType; 120 OUStringBuffer aContent; 121 SvXMLNumberInfo aNumInfo; 122 LanguageType nElementLang; 123 bool bLong; 124 bool bTextual; 125 OUString sCalendar; 126 127 public: 128 SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement, 129 SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, 130 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); 131 132 virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( 133 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; 134 virtual void SAL_CALL characters( const OUString& rChars ) override; 135 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; 136 137 void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ); 138 }; 139 140 class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext 141 { 142 SvXMLNumFmtElementContext& rParent; 143 OUStringBuffer aContent; 144 sal_Int32 nTextPosition; 145 146 public: 147 SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement, 148 SvXMLNumFmtElementContext& rParentContext, 149 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); 150 151 virtual void SAL_CALL characters( const OUString& rChars ) override; 152 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; 153 }; 154 155 class SvXMLNumFmtMapContext : public SvXMLImportContext 156 { 157 SvXMLNumFormatContext& rParent; 158 OUString sCondition; 159 OUString sName; 160 161 public: 162 SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_Int32 nElement, 163 SvXMLNumFormatContext& rParentContext, 164 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); 165 166 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; 167 }; 168 169 class SvXMLNumFmtPropContext : public SvXMLImportContext 170 { 171 SvXMLNumFormatContext& rParent; 172 Color m_nColor; 173 bool bColSet; 174 175 public: 176 SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_Int32 nElement, 177 SvXMLNumFormatContext& rParentContext, 178 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); 179 180 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; 181 }; 182 183 enum class SvXMLStyleTokens 184 { 185 Text, 186 FillCharacter, 187 Number, 188 ScientificNumber, 189 Fraction, 190 CurrencySymbol, 191 Day, 192 Month, 193 Year, 194 Era, 195 DayOfWeek, 196 WeekOfYear, 197 Quarter, 198 Hours, 199 AmPm, 200 Minutes, 201 Seconds, 202 Boolean, 203 TextContent 204 }; 205 206 } 207 208 // standard colors 209 210 211 #define XML_NUMF_COLORCOUNT 10 212 213 const Color aNumFmtStdColors[XML_NUMF_COLORCOUNT] = 214 { 215 COL_BLACK, 216 COL_LIGHTBLUE, 217 COL_LIGHTGREEN, 218 COL_LIGHTCYAN, 219 COL_LIGHTRED, 220 COL_LIGHTMAGENTA, 221 COL_BROWN, 222 COL_GRAY, 223 COL_YELLOW, 224 COL_WHITE 225 }; 226 227 228 // token maps 229 230 231 // maps for SvXMLUnitConverter::convertEnum 232 233 const SvXMLEnumMapEntry<bool> aStyleValueMap[] = 234 { 235 { XML_SHORT, false }, 236 { XML_LONG, true }, 237 { XML_TOKEN_INVALID, false } 238 }; 239 240 const SvXMLEnumMapEntry<bool> aFormatSourceMap[] = 241 { 242 { XML_FIXED, false }, 243 { XML_LANGUAGE, true }, 244 { XML_TOKEN_INVALID, false } 245 }; 246 247 namespace { 248 249 struct SvXMLDefaultDateFormat 250 { 251 NfIndexTableOffset eFormat; 252 SvXMLDateElementAttributes eDOW; 253 SvXMLDateElementAttributes eDay; 254 SvXMLDateElementAttributes eMonth; 255 SvXMLDateElementAttributes eYear; 256 SvXMLDateElementAttributes eHours; 257 SvXMLDateElementAttributes eMins; 258 SvXMLDateElementAttributes eSecs; 259 bool bSystem; 260 }; 261 262 } 263 264 const SvXMLDefaultDateFormat aDefaultDateFormats[] = 265 { 266 // format day-of-week day month year hours minutes seconds format-source 267 268 { NF_DATE_SYSTEM_SHORT, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, 269 { NF_DATE_SYSTEM_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, 270 { NF_DATE_SYS_MMYY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 271 { NF_DATE_SYS_DDMMM, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_TEXTSHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 272 { NF_DATE_SYS_DDMMYYYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 273 { NF_DATE_SYS_DDMMYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 274 { NF_DATE_SYS_DMMMYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 275 { NF_DATE_SYS_DMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 276 { NF_DATE_SYS_DMMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 277 { NF_DATE_SYS_NNDMMMYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 278 { NF_DATE_SYS_NNDMMMMYYYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 279 { NF_DATE_SYS_NNNNDMMMMYYYY, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, 280 { NF_DATETIME_SYS_DDMMYYYY_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, false }, 281 { NF_DATETIME_SYSTEM_SHORT_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, true }, 282 { NF_DATETIME_SYS_DDMMYYYY_HHMMSS, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, false } 283 }; 284 285 286 // SvXMLNumImpData 287 288 289 SvXMLNumImpData::SvXMLNumImpData( 290 SvNumberFormatter* pFmt, 291 const uno::Reference<uno::XComponentContext>& rxContext ) 292 : pFormatter(pFmt), 293 m_xContext(rxContext) 294 { 295 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); 296 } 297 298 sal_uInt32 SvXMLNumImpData::GetKeyForName( std::u16string_view rName ) 299 { 300 for (const auto& rObj : m_NameEntries) 301 { 302 if (rObj.aName == rName) 303 return rObj.nKey; // found 304 } 305 return NUMBERFORMAT_ENTRY_NOT_FOUND; 306 } 307 308 void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ) 309 { 310 if ( bRemoveAfterUse ) 311 { 312 // if there is already an entry for this key without the bRemoveAfterUse flag, 313 // clear the flag for this entry, too 314 315 for (const auto& rObj : m_NameEntries) 316 { 317 if (rObj.nKey == nKey && !rObj.bRemoveAfterUse) 318 { 319 bRemoveAfterUse = false; // clear flag for new entry 320 break; 321 } 322 } 323 } 324 else 325 { 326 // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key 327 SetUsed( nKey ); 328 } 329 330 m_NameEntries.emplace_back(rName, nKey, bRemoveAfterUse); 331 } 332 333 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey ) 334 { 335 for (auto& rObj : m_NameEntries) 336 { 337 if (rObj.nKey == nKey) 338 { 339 rObj.bRemoveAfterUse = false; // used -> don't remove 340 341 // continue searching - there may be several entries for the same key 342 // (with different names), the format must not be deleted if any one of 343 // them is used 344 } 345 } 346 } 347 348 void SvXMLNumImpData::RemoveVolatileFormats() 349 { 350 // remove temporary (volatile) formats from NumberFormatter 351 // called at the end of each import (styles and content), so volatile formats 352 // from styles can't be used in content 353 354 if ( !pFormatter ) 355 return; 356 357 for (const auto& rObj : m_NameEntries) 358 { 359 if (rObj.bRemoveAfterUse ) 360 { 361 const SvNumberformat* pFormat = pFormatter->GetEntry(rObj.nKey); 362 if (pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED)) 363 pFormatter->DeleteEntry(rObj.nKey); 364 } 365 } 366 } 367 368 const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang ) 369 { 370 if ( !pLocaleData || pLocaleData->getLanguageTag() != LanguageTag(nLang) ) 371 pLocaleData = std::make_unique<LocaleDataWrapper>( 372 pFormatter ? pFormatter->GetComponentContext() : m_xContext, 373 LanguageTag( nLang ) ); 374 return *pLocaleData; 375 } 376 377 378 // SvXMLNumFmtMapContext 379 380 381 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport, 382 sal_Int32 /*nElement*/, 383 SvXMLNumFormatContext& rParentContext, 384 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : 385 SvXMLImportContext( rImport ), 386 rParent( rParentContext ) 387 { 388 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) 389 { 390 OUString sValue = aIter.toString(); 391 switch(aIter.getToken()) 392 { 393 case XML_ELEMENT(STYLE, XML_CONDITION): 394 sCondition = sValue; 395 break; 396 case XML_ELEMENT(STYLE, XML_APPLY_STYLE_NAME): 397 sName = sValue; 398 break; 399 default: 400 XMLOFF_WARN_UNKNOWN("xmloff", aIter); 401 } 402 } 403 } 404 405 void SvXMLNumFmtMapContext::endFastElement(sal_Int32 ) 406 { 407 rParent.AddCondition( sCondition, sName ); 408 } 409 410 411 // SvXMLNumFmtPropContext 412 413 414 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport, 415 sal_Int32 /*nElement*/, 416 SvXMLNumFormatContext& rParentContext, 417 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : 418 SvXMLImportContext( rImport ), 419 rParent( rParentContext ), 420 m_nColor( 0 ), 421 bColSet( false ) 422 { 423 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) 424 { 425 switch ( aIter.getToken()) 426 { 427 case XML_ELEMENT(FO, XML_COLOR): 428 case XML_ELEMENT(FO_COMPAT, XML_COLOR): 429 bColSet = ::sax::Converter::convertColor( m_nColor, aIter.toView() ); 430 break; 431 default: 432 XMLOFF_WARN_UNKNOWN("xmloff", aIter); 433 } 434 } 435 } 436 437 void SvXMLNumFmtPropContext::endFastElement(sal_Int32 ) 438 { 439 if (bColSet) 440 rParent.AddColor( m_nColor ); 441 } 442 443 444 // SvXMLNumFmtEmbeddedTextContext 445 446 447 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, 448 sal_Int32 /*nElement*/, 449 SvXMLNumFmtElementContext& rParentContext, 450 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : 451 SvXMLImportContext( rImport ), 452 rParent( rParentContext ), 453 nTextPosition( 0 ) 454 { 455 sal_Int32 nAttrVal; 456 457 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) 458 { 459 if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) ) 460 { 461 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() )) 462 nTextPosition = nAttrVal; 463 } 464 else 465 XMLOFF_WARN_UNKNOWN("xmloff", aIter); 466 } 467 } 468 469 void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars ) 470 { 471 aContent.append( rChars ); 472 } 473 474 void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 ) 475 { 476 rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() ); 477 } 478 479 static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent ) 480 { 481 SvXMLStylesTokens nFormatType = rParent.GetType(); 482 483 // Treat space equal to non-breaking space separator. 484 const sal_Unicode cNBSP = 0x00A0; 485 sal_Unicode cTS; 486 if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || 487 nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || 488 nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && 489 (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) || 490 (cChar == ' ' && cTS == cNBSP)) ) 491 { 492 // #i22394# Extra occurrences of thousands separator must be quoted, so they 493 // aren't mis-interpreted as display-factor. 494 // This must be limited to the format types that can contain a number element, 495 // because the same character can be a date separator that should not be quoted 496 // in date formats. 497 498 return false; // force quotes 499 } 500 501 // see ImpSvNumberformatScan::Next_Symbol 502 503 // All format types except BOOLEAN may contain minus sign or delimiter. 504 if ( cChar == '-' ) 505 return nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE; 506 507 if ( ( cChar == ' ' || 508 cChar == '/' || 509 cChar == '.' || 510 cChar == ',' || 511 cChar == ':' || 512 cChar == '\'' ) && 513 ( nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || 514 nFormatType == SvXMLStylesTokens::DATE_STYLE || 515 nFormatType == SvXMLStylesTokens::TIME_STYLE ) ) // other formats do not require delimiter tdf#97837 516 return true; 517 518 // percent sign must be used without quotes for percentage styles only 519 if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && cChar == '%' ) 520 return true; 521 522 // don't put quotes around single parentheses (often used for negative numbers) 523 if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || 524 nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || 525 nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && 526 ( cChar == '(' || cChar == ')' ) ) 527 return true; 528 529 return false; 530 } 531 532 static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent ) 533 { 534 bool bQuote = true; 535 sal_Int32 nLength = rContent.getLength(); 536 const SvXMLStylesTokens nFormatType = rParent.GetType(); 537 538 if (nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE && 539 ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) || 540 (nLength == 2 && 541 ((rContent[0] == ' ' && rContent[1] == '-') || 542 (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent)))))) 543 { 544 // Don't quote single separator characters like space or percent, 545 // or separator characters followed by space (used in date formats). 546 // Or space followed by minus (used in currency formats) that would 547 // lead to almost duplicated formats with built-in formats just with 548 // the difference of quotes. 549 bQuote = false; 550 } 551 else if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 ) 552 { 553 // the percent character in percentage styles must be left out of quoting 554 // (one occurrence is enough even if there are several percent characters in the string) 555 556 sal_Int32 nPos = rContent.indexOf( '%' ); 557 if ( nPos >= 0 ) 558 { 559 if ( nPos + 1 < nLength ) 560 { 561 if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) ) 562 { 563 // single character that doesn't need quoting 564 } 565 else 566 { 567 // quote text behind percent character 568 rContent.insert( nPos + 1, '"' ); 569 rContent.append( '"' ); 570 } 571 } 572 if ( nPos > 0 ) 573 { 574 if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) ) 575 { 576 // single character that doesn't need quoting 577 } 578 else 579 { 580 // quote text before percent character 581 rContent.insert( nPos, '"' ); 582 rContent.insert( 0, '"' ); 583 } 584 } 585 bQuote = false; 586 } 587 // else: normal quoting (below) 588 } 589 590 if ( !bQuote ) 591 return; 592 593 // #i55469# quotes in the string itself have to be escaped 594 bool bEscape = ( rContent.indexOf( '"' ) >= 0 ); 595 if ( bEscape ) 596 { 597 // A quote is turned into "\"" - a quote to end quoted text, an escaped quote, 598 // and a quote to resume quoting. 599 OUString aInsert( "\"\\\"" ); 600 601 sal_Int32 nPos = 0; 602 while ( nPos < rContent.getLength() ) 603 { 604 if ( rContent[nPos] == '"' ) 605 { 606 rContent.insert( nPos, aInsert ); 607 nPos += aInsert.getLength(); 608 } 609 ++nPos; 610 } 611 } 612 613 // quote string literals 614 rContent.insert( 0, '"' ); 615 rContent.append( '"' ); 616 617 // remove redundant double quotes at start or end 618 if ( !bEscape ) 619 return; 620 621 if ( rContent.getLength() > 2 && 622 rContent[0] == '"' && 623 rContent[1] == '"' ) 624 { 625 rContent.remove(0, 2); 626 } 627 628 sal_Int32 nLen = rContent.getLength(); 629 if ( nLen > 2 && 630 rContent[nLen - 1] == '"' && 631 rContent[nLen - 2] == '"' ) 632 { 633 rContent.truncate(nLen - 2); 634 } 635 } 636 637 638 // SvXMLNumFmtElementContext 639 640 641 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, 642 sal_Int32 /*nElement*/, 643 SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, 644 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) : 645 SvXMLImportContext( rImport ), 646 rParent( rParentContext ), 647 nType( nNewType ), 648 nElementLang( LANGUAGE_SYSTEM ), 649 bLong( false ), 650 bTextual( false ) 651 { 652 LanguageTagODF aLanguageTagODF; 653 sal_Int32 nAttrVal; 654 bool bAttrBool(false); 655 bool bVarDecimals = false; 656 bool bIsMaxDenominator = false; 657 double fAttrDouble; 658 659 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) 660 { 661 switch (aIter.getToken()) 662 { 663 case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES): 664 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 665 { 666 // fdo#58539 & gnome#627420: limit number of digits during import 667 aNumInfo.nDecimals = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS); 668 } 669 break; 670 case XML_ELEMENT(LO_EXT, XML_MIN_DECIMAL_PLACES): 671 case XML_ELEMENT(NUMBER, XML_MIN_DECIMAL_PLACES): 672 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 673 aNumInfo.nMinDecimalDigits = nAttrVal; 674 break; 675 case XML_ELEMENT(NUMBER, XML_MIN_INTEGER_DIGITS): 676 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 677 aNumInfo.nInteger = nAttrVal; 678 break; 679 case XML_ELEMENT(LO_EXT, XML_MAX_BLANK_INTEGER_DIGITS): 680 case XML_ELEMENT(NUMBER, XML_MAX_BLANK_INTEGER_DIGITS): 681 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 682 aNumInfo.nBlankInteger = nAttrVal; 683 break; 684 case XML_ELEMENT(NUMBER, XML_GROUPING): 685 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 686 aNumInfo.bGrouping = bAttrBool; 687 break; 688 case XML_ELEMENT(NUMBER, XML_DISPLAY_FACTOR): 689 if (::sax::Converter::convertDouble( fAttrDouble, aIter.toView() )) 690 aNumInfo.fDisplayFactor = fAttrDouble; 691 break; 692 case XML_ELEMENT(NUMBER, XML_DECIMAL_REPLACEMENT): 693 if ( aIter.toView() == " " ) 694 { 695 aNumInfo.bDecAlign = true; // space replacement for "?" 696 bVarDecimals = true; 697 } 698 else 699 if ( aIter.isEmpty() ) 700 bVarDecimals = true; // empty replacement string: variable decimals 701 else // all other strings 702 aNumInfo.bDecReplace = true; // decimal replacement with dashes 703 break; 704 case XML_ELEMENT(NUMBER, XML_MIN_EXPONENT_DIGITS): 705 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 706 aNumInfo.nExpDigits = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS); 707 break; 708 case XML_ELEMENT(NUMBER, XML_EXPONENT_INTERVAL): 709 case XML_ELEMENT(LO_EXT, XML_EXPONENT_INTERVAL): 710 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 711 aNumInfo.nExpInterval = nAttrVal; 712 break; 713 case XML_ELEMENT(NUMBER, XML_FORCED_EXPONENT_SIGN): 714 case XML_ELEMENT(LO_EXT, XML_FORCED_EXPONENT_SIGN): 715 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 716 aNumInfo.bExpSign = bAttrBool; 717 break; 718 case XML_ELEMENT(NUMBER, XML_MIN_NUMERATOR_DIGITS): 719 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 720 aNumInfo.nMinNumerDigits = nAttrVal; 721 break; 722 case XML_ELEMENT(NUMBER, XML_MIN_DENOMINATOR_DIGITS): 723 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 724 aNumInfo.nMinDenomDigits = nAttrVal; 725 break; 726 case XML_ELEMENT(LO_EXT, XML_MAX_NUMERATOR_DIGITS): 727 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // at least one '#' 728 aNumInfo.nMaxNumerDigits = nAttrVal; 729 break; 730 case XML_ELEMENT(NUMBER, XML_DENOMINATOR_VALUE): 731 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // 0 is not valid 732 { 733 aNumInfo.nFracDenominator = nAttrVal; 734 bIsMaxDenominator = false; 735 } 736 break; 737 case XML_ELEMENT(NUMBER, XML_MAX_DENOMINATOR_VALUE): // part of ODF 1.3 738 case XML_ELEMENT(LO_EXT, XML_MAX_DENOMINATOR_VALUE): 739 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 ) && aNumInfo.nFracDenominator <= 0) 740 { // if denominator value not yet defined 741 aNumInfo.nFracDenominator = nAttrVal; 742 bIsMaxDenominator = true; 743 } 744 break; 745 case XML_ELEMENT(LO_EXT, XML_ZEROS_NUMERATOR_DIGITS): 746 case XML_ELEMENT(NUMBER, XML_ZEROS_NUMERATOR_DIGITS): 747 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 748 aNumInfo.nZerosNumerDigits = nAttrVal; 749 break; 750 case XML_ELEMENT(NUMBER, XML_ZEROS_DENOMINATOR_DIGITS): 751 case XML_ELEMENT(LO_EXT, XML_ZEROS_DENOMINATOR_DIGITS): 752 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) 753 aNumInfo.nZerosDenomDigits = nAttrVal; 754 break; 755 case XML_ELEMENT(NUMBER, XML_INTEGER_FRACTION_DELIMITER): 756 case XML_ELEMENT(LO_EXT, XML_INTEGER_FRACTION_DELIMITER): 757 aNumInfo.aIntegerFractionDelimiter = aIter.toString(); 758 break; 759 case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): 760 aLanguageTagODF.maRfcLanguageTag = aIter.toString(); 761 break; 762 case XML_ELEMENT(NUMBER, XML_LANGUAGE): 763 aLanguageTagODF.maLanguage = aIter.toString(); 764 break; 765 case XML_ELEMENT(NUMBER, XML_SCRIPT): 766 aLanguageTagODF.maScript = aIter.toString(); 767 break; 768 case XML_ELEMENT(NUMBER, XML_COUNTRY): 769 aLanguageTagODF.maCountry = aIter.toString(); 770 break; 771 case XML_ELEMENT(NUMBER, XML_STYLE): 772 SvXMLUnitConverter::convertEnum( bLong, aIter.toView(), aStyleValueMap ); 773 break; 774 case XML_ELEMENT(NUMBER, XML_TEXTUAL): 775 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 776 bTextual = bAttrBool; 777 break; 778 case XML_ELEMENT(NUMBER, XML_CALENDAR): 779 sCalendar = aIter.toString(); 780 break; 781 default: 782 XMLOFF_WARN_UNKNOWN("xmloff", aIter); 783 } 784 } 785 if ( aNumInfo.nBlankInteger > aNumInfo.nInteger ) 786 aNumInfo.nInteger = aNumInfo.nBlankInteger; 787 if ( aNumInfo.nMinDecimalDigits == -1) 788 { 789 if ( bVarDecimals || aNumInfo.bDecReplace ) 790 aNumInfo.nMinDecimalDigits = 0; 791 else 792 aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals; 793 } 794 if ( aNumInfo.nZerosDenomDigits > 0 ) 795 { // nMin = count of '0' and '?' 796 if ( aNumInfo.nMinDenomDigits < aNumInfo.nZerosDenomDigits ) 797 aNumInfo.nMinDenomDigits = aNumInfo.nZerosDenomDigits; 798 } 799 else 800 aNumInfo.nZerosDenomDigits = 0; 801 if ( aNumInfo.nMinDenomDigits >= 0 ) 802 if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits ) 803 aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 ); 804 if ( aNumInfo.nZerosNumerDigits > 0 ) 805 { 806 if ( aNumInfo.nMinNumerDigits < aNumInfo.nZerosNumerDigits ) 807 aNumInfo.nMinNumerDigits = aNumInfo.nZerosNumerDigits; 808 } 809 else 810 aNumInfo.nZerosNumerDigits = 0; 811 if ( aNumInfo.nMinNumerDigits >= 0 ) 812 if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits ) 813 aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 ); 814 if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 ) 815 { 816 aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1; 817 aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator 818 } 819 if ( aNumInfo.nMaxDenomDigits > 0 ) 820 { 821 if ( aNumInfo.nMinDenomDigits < 0 ) 822 aNumInfo.nMinDenomDigits = 0; 823 else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits ) 824 aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits; 825 } 826 827 if ( !aLanguageTagODF.isEmpty() ) 828 { 829 nElementLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); 830 if ( nElementLang == LANGUAGE_DONTKNOW ) 831 nElementLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? 832 } 833 834 if ( aNumInfo.aIntegerFractionDelimiter.isEmpty() ) 835 aNumInfo.aIntegerFractionDelimiter = " "; 836 } 837 838 css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFmtElementContext::createFastChildContext( 839 sal_Int32 nElement, 840 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) 841 { 842 // only number:number supports number:embedded-text child element 843 844 if ( nType == SvXMLStyleTokens::Number && 845 nElement == XML_ELEMENT(NUMBER, XML_EMBEDDED_TEXT) ) 846 { 847 return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement, *this, xAttrList ); 848 } 849 else 850 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); 851 return nullptr; 852 } 853 854 void SvXMLNumFmtElementContext::characters( const OUString& rChars ) 855 { 856 aContent.append( rChars ); 857 } 858 859 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ) 860 { 861 if (rContent.isEmpty()) 862 return; 863 864 auto iterPair = aNumInfo.m_EmbeddedElements.emplace(nFormatPos, rContent); 865 if (!iterPair.second) 866 // there's already an element at this position - append text to existing element 867 iterPair.first->second += rContent; 868 } 869 870 void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) 871 { 872 bool bEffLong = bLong; 873 switch (nType) 874 { 875 case SvXMLStyleTokens::Text: 876 if ( rParent.HasLongDoW() && 877 std::u16string_view(aContent) == rParent.GetLocaleData().getLongDateDayOfWeekSep() ) 878 { 879 // skip separator constant after long day of week 880 // (NF_KEY_NNNN contains the separator) 881 882 if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) ) 883 { 884 aContent.truncate(); 885 } 886 887 rParent.SetHasLongDoW( false ); // only once 888 } 889 if ( !aContent.isEmpty() ) 890 { 891 lcl_EnquoteIfNecessary( aContent, rParent ); 892 rParent.AddToCode( aContent ); 893 aContent.setLength(0); 894 } 895 else 896 { 897 // Quoted empty text may be significant to separate. 898 aContent.append("\"\""); 899 rParent.AddToCode( aContent ); 900 aContent.setLength(0); 901 rParent.SetHasTrailingEmptyText(true); // *after* AddToCode() 902 } 903 break; 904 905 case SvXMLStyleTokens::Number: 906 rParent.AddNumber( aNumInfo ); 907 break; 908 909 case SvXMLStyleTokens::CurrencySymbol: 910 rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang ); 911 break; 912 913 case SvXMLStyleTokens::TextContent: 914 rParent.AddToCode( '@'); 915 break; 916 case SvXMLStyleTokens::FillCharacter: 917 if ( !aContent.isEmpty() ) 918 { 919 rParent.AddToCode( '*' ); 920 rParent.AddToCode( aContent[0] ); 921 } 922 break; 923 case SvXMLStyleTokens::Boolean: 924 rParent.AddNfKeyword( NF_KEY_BOOLEAN ); 925 break; 926 927 case SvXMLStyleTokens::Day: 928 rParent.UpdateCalendar( sCalendar ); 929 //! I18N doesn't provide SYSTEM or extended date information yet 930 931 rParent.AddNfKeyword( 932 sal::static_int_cast< sal_uInt16 >( 933 bEffLong ? NF_KEY_DD : NF_KEY_D ) ); 934 break; 935 case SvXMLStyleTokens::Month: 936 rParent.UpdateCalendar( sCalendar ); 937 //! I18N doesn't provide SYSTEM or extended date information yet 938 939 rParent.AddNfKeyword( 940 sal::static_int_cast< sal_uInt16 >( 941 bTextual 942 ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM ) 943 : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) ); 944 break; 945 case SvXMLStyleTokens::Year: 946 //! I18N doesn't provide SYSTEM or extended date information yet 947 { 948 // Y after G (era) is replaced by E for a secondary calendar. 949 // Do not replace for default calendar. 950 // Also replace Y by E if we're switching to the secondary 951 // calendar of a locale if it is known to implicitly use E. 952 rParent.UpdateCalendar( sCalendar); 953 const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); 954 if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY 955 || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) 956 { 957 rParent.AddNfKeyword( 958 sal::static_int_cast< sal_uInt16 >( 959 bEffLong ? NF_KEY_EEC : NF_KEY_EC ) ); 960 } 961 else 962 { 963 rParent.AddNfKeyword( 964 sal::static_int_cast< sal_uInt16 >( 965 bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) ); 966 } 967 } 968 break; 969 case SvXMLStyleTokens::Era: 970 rParent.UpdateCalendar( sCalendar ); 971 //! I18N doesn't provide SYSTEM or extended date information yet 972 rParent.AddNfKeyword( 973 sal::static_int_cast< sal_uInt16 >( 974 bEffLong ? NF_KEY_GGG : NF_KEY_G ) ); 975 // HasEra flag is set 976 break; 977 case SvXMLStyleTokens::DayOfWeek: 978 //! I18N doesn't provide SYSTEM or extended date information yet 979 { 980 // Implicit secondary calendar uses A keyword, default and 981 // explicit calendar N keyword. 982 rParent.UpdateCalendar( sCalendar); 983 const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); 984 if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY 985 || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) 986 { 987 rParent.AddNfKeyword( 988 sal::static_int_cast< sal_uInt16 >( 989 bEffLong ? NF_KEY_AAAA : NF_KEY_AAA ) ); 990 } 991 else 992 { 993 rParent.AddNfKeyword( 994 sal::static_int_cast< sal_uInt16 >( 995 bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) ); 996 } 997 } 998 break; 999 case SvXMLStyleTokens::WeekOfYear: 1000 rParent.UpdateCalendar( sCalendar ); 1001 rParent.AddNfKeyword( NF_KEY_WW ); 1002 break; 1003 case SvXMLStyleTokens::Quarter: 1004 rParent.UpdateCalendar( sCalendar ); 1005 rParent.AddNfKeyword( 1006 sal::static_int_cast< sal_uInt16 >( 1007 bEffLong ? NF_KEY_QQ : NF_KEY_Q ) ); 1008 break; 1009 case SvXMLStyleTokens::Hours: 1010 rParent.AddNfKeyword( 1011 sal::static_int_cast< sal_uInt16 >( 1012 bEffLong ? NF_KEY_HH : NF_KEY_H ) ); 1013 break; 1014 case SvXMLStyleTokens::AmPm: 1015 //! short/long? 1016 rParent.AddNfKeyword( NF_KEY_AMPM ); 1017 break; 1018 case SvXMLStyleTokens::Minutes: 1019 rParent.AddNfKeyword( 1020 sal::static_int_cast< sal_uInt16 >( 1021 bEffLong ? NF_KEY_MMI : NF_KEY_MI ) ); 1022 break; 1023 case SvXMLStyleTokens::Seconds: 1024 rParent.AddNfKeyword( 1025 sal::static_int_cast< sal_uInt16 >( 1026 bEffLong ? NF_KEY_SS : NF_KEY_S ) ); 1027 if ( aNumInfo.nDecimals > 0 ) 1028 { 1029 // manually add the decimal places 1030 rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep()); 1031 for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++) 1032 { 1033 rParent.AddToCode( '0'); 1034 } 1035 } 1036 break; 1037 1038 case SvXMLStyleTokens::Fraction: 1039 { 1040 if ( aNumInfo.nInteger >= 0 ) 1041 { 1042 // add integer part only if min-integer-digits attribute is there 1043 aNumInfo.nDecimals = 0; 1044 rParent.AddNumber( aNumInfo ); // number without decimals 1045 OUStringBuffer sIntegerFractionDelimiter(aNumInfo.aIntegerFractionDelimiter); 1046 lcl_EnquoteIfNecessary( sIntegerFractionDelimiter, rParent ); 1047 rParent.AddToCode( sIntegerFractionDelimiter ); // default is ' ' 1048 } 1049 1050 //! build string and add at once 1051 1052 sal_Int32 i; 1053 for (i=aNumInfo.nMaxNumerDigits; i > 0; i--) 1054 { 1055 if ( i > aNumInfo.nMinNumerDigits ) 1056 rParent.AddToCode( '#' ); 1057 else if ( i > aNumInfo.nZerosNumerDigits ) 1058 rParent.AddToCode( '?' ); 1059 else 1060 rParent.AddToCode( '0' ); 1061 } 1062 rParent.AddToCode( '/' ); 1063 if ( aNumInfo.nFracDenominator > 0 ) 1064 { 1065 rParent.AddToCode( OUString::number( aNumInfo.nFracDenominator ) ); 1066 } 1067 else 1068 { 1069 for (i=aNumInfo.nMaxDenomDigits; i > 0 ; i--) 1070 { 1071 if ( i > aNumInfo.nMinDenomDigits ) 1072 rParent.AddToCode( '#' ); 1073 else if ( i > aNumInfo.nZerosDenomDigits ) 1074 rParent.AddToCode( '?' ); 1075 else 1076 rParent.AddToCode( '0' ); 1077 } 1078 } 1079 } 1080 break; 1081 1082 case SvXMLStyleTokens::ScientificNumber: 1083 { 1084 // exponential interval for engineering notation 1085 if( !aNumInfo.bGrouping && aNumInfo.nExpInterval > aNumInfo.nInteger ) 1086 { 1087 for (sal_Int32 i=aNumInfo.nInteger; i<aNumInfo.nExpInterval; i++) 1088 { 1089 rParent.AddToCode( '#' ); 1090 } 1091 } 1092 rParent.AddNumber( aNumInfo ); // simple number 1093 1094 if ( aNumInfo.bExpSign ) 1095 rParent.AddToCode( u"E+" ); 1096 else 1097 rParent.AddToCode( u"E" ); 1098 for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++) 1099 { 1100 rParent.AddToCode( '0' ); 1101 } 1102 } 1103 break; 1104 1105 default: 1106 assert(false && "invalid element ID"); 1107 } 1108 } 1109 1110 sal_uInt16 SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW, 1111 SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, 1112 SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, 1113 SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, 1114 bool bSystem ) 1115 { 1116 for (const auto & rEntry : aDefaultDateFormats) 1117 { 1118 if ( bSystem == rEntry.bSystem && 1119 ( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) && 1120 ( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) && 1121 ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) && 1122 ( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) && 1123 ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) && 1124 ( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) && 1125 ( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) ) 1126 { 1127 return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat); 1128 } 1129 } 1130 1131 return NF_INDEX_TABLE_ENTRIES; // invalid 1132 } 1133 1134 1135 // SvXMLNumFormatContext 1136 1137 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, 1138 sal_Int32 /*nElement*/, 1139 SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType, 1140 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList, 1141 SvXMLStylesContext& rStyles ) : 1142 SvXMLStyleContext( rImport ), 1143 pData( pNewData ), 1144 pStyles( &rStyles ), 1145 nType( nNewType ), 1146 nKey(-1), 1147 eImplicitCalendar(ImplicitCalendar::DEFAULT), 1148 nFormatLang( LANGUAGE_SYSTEM ), 1149 bAutoOrder( false ), 1150 bFromSystem( false ), 1151 bTruncate( true ), 1152 bAutoDec( false ), 1153 bAutoInt( false ), 1154 bHasExtraText( false ), 1155 bHasTrailingEmptyText( false ), 1156 bHasLongDoW( false ), 1157 bHasDateTime( false ), 1158 bRemoveAfterUse( false ), 1159 eDateDOW( XML_DEA_NONE ), 1160 eDateDay( XML_DEA_NONE ), 1161 eDateMonth( XML_DEA_NONE ), 1162 eDateYear( XML_DEA_NONE ), 1163 eDateHours( XML_DEA_NONE ), 1164 eDateMins( XML_DEA_NONE ), 1165 eDateSecs( XML_DEA_NONE ), 1166 bDateNoDefault( false ) 1167 { 1168 LanguageTagODF aLanguageTagODF; 1169 css::i18n::NativeNumberXmlAttributes aNatNumAttr; 1170 OUString aSpellout; 1171 bool bAttrBool(false); 1172 1173 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) 1174 { 1175 switch (aIter.getToken()) 1176 { 1177 // attributes for a style 1178 case XML_ELEMENT(STYLE, XML_NAME): 1179 break; 1180 case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): 1181 aLanguageTagODF.maRfcLanguageTag = aIter.toString(); 1182 break; 1183 case XML_ELEMENT(NUMBER, XML_LANGUAGE): 1184 aLanguageTagODF.maLanguage = aIter.toString(); 1185 break; 1186 case XML_ELEMENT(NUMBER, XML_SCRIPT): 1187 aLanguageTagODF.maScript = aIter.toString(); 1188 break; 1189 case XML_ELEMENT(NUMBER, XML_COUNTRY): 1190 aLanguageTagODF.maCountry = aIter.toString(); 1191 break; 1192 case XML_ELEMENT(NUMBER, XML_TITLE): 1193 sFormatTitle = aIter.toString(); 1194 break; 1195 case XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER): 1196 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 1197 bAutoOrder = bAttrBool; 1198 break; 1199 case XML_ELEMENT(NUMBER, XML_FORMAT_SOURCE): 1200 SvXMLUnitConverter::convertEnum( bFromSystem, aIter.toView(), aFormatSourceMap ); 1201 break; 1202 case XML_ELEMENT(NUMBER, XML_TRUNCATE_ON_OVERFLOW): 1203 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 1204 bTruncate = bAttrBool; 1205 break; 1206 case XML_ELEMENT(STYLE, XML_VOLATILE): 1207 // volatile formats can be removed after importing 1208 // if not used in other styles 1209 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) 1210 bRemoveAfterUse = bAttrBool; 1211 break; 1212 case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_FORMAT): 1213 aNatNumAttr.Format = aIter.toString(); 1214 break; 1215 case XML_ELEMENT(LO_EXT, XML_TRANSLITERATION_SPELLOUT): 1216 case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_SPELLOUT): 1217 aSpellout = aIter.toString(); 1218 break; 1219 case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_LANGUAGE): 1220 aNatNumAttr.Locale.Language = aIter.toString(); 1221 break; 1222 case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_COUNTRY): 1223 aNatNumAttr.Locale.Country = aIter.toString(); 1224 break; 1225 case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_STYLE): 1226 aNatNumAttr.Style = aIter.toString(); 1227 break; 1228 default: 1229 XMLOFF_WARN_UNKNOWN("xmloff", aIter); 1230 } 1231 } 1232 1233 if (!aLanguageTagODF.isEmpty()) 1234 { 1235 nFormatLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); 1236 if ( nFormatLang == LANGUAGE_DONTKNOW ) 1237 nFormatLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? 1238 } 1239 1240 if (aNatNumAttr.Format.isEmpty() && aSpellout.isEmpty()) 1241 return; 1242 1243 LanguageTag aLanguageTag( OUString(), aNatNumAttr.Locale.Language, 1244 std::u16string_view(), aNatNumAttr.Locale.Country); 1245 aNatNumAttr.Locale = aLanguageTag.getLocale( false); 1246 1247 // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.) 1248 if ( !aSpellout.isEmpty() ) 1249 { 1250 aFormatCode.append( "[NatNum12 " ); 1251 aFormatCode.append( aSpellout ); 1252 } else { 1253 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 1254 if ( !pFormatter ) return; 1255 1256 sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr ); 1257 aFormatCode.append( "[NatNum" ); 1258 aFormatCode.append( nNatNum ); 1259 } 1260 1261 LanguageType eLang = aLanguageTag.getLanguageType( false ); 1262 if ( eLang == LANGUAGE_DONTKNOW ) 1263 eLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? 1264 if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM ) 1265 { 1266 aFormatCode.append( "][$-" ); 1267 // language code in upper hex: 1268 aFormatCode.append(OUString::number(static_cast<sal_uInt16>(eLang), 16).toAsciiUpperCase()); 1269 } 1270 aFormatCode.append( ']' ); 1271 } 1272 1273 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, 1274 const OUString& rName, 1275 const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/, 1276 const sal_Int32 nTempKey, LanguageType nLang, 1277 SvXMLStylesContext& rStyles ) : 1278 SvXMLStyleContext( rImport, XmlStyleFamily::DATA_STYLE ), 1279 pData( nullptr ), 1280 pStyles( &rStyles ), 1281 nType( SvXMLStylesTokens::NUMBER_STYLE ), 1282 nKey(nTempKey), 1283 eImplicitCalendar(ImplicitCalendar::DEFAULT), 1284 nFormatLang( nLang ), 1285 bAutoOrder( false ), 1286 bFromSystem( false ), 1287 bTruncate( true ), 1288 bAutoDec( false ), 1289 bAutoInt( false ), 1290 bHasExtraText( false ), 1291 bHasTrailingEmptyText( false ), 1292 bHasLongDoW( false ), 1293 bHasDateTime( false ), 1294 bRemoveAfterUse( false ), 1295 eDateDOW( XML_DEA_NONE ), 1296 eDateDay( XML_DEA_NONE ), 1297 eDateMonth( XML_DEA_NONE ), 1298 eDateYear( XML_DEA_NONE ), 1299 eDateHours( XML_DEA_NONE ), 1300 eDateMins( XML_DEA_NONE ), 1301 eDateSecs( XML_DEA_NONE ), 1302 bDateNoDefault( false ) 1303 { 1304 SetAttribute(XML_ELEMENT(STYLE, XML_NAME), rName); 1305 } 1306 1307 SvXMLNumFormatContext::~SvXMLNumFormatContext() 1308 { 1309 } 1310 1311 css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFormatContext::createFastChildContext( 1312 sal_Int32 nElement, 1313 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) 1314 { 1315 SvXMLImportContext* pContext = nullptr; 1316 1317 switch (nElement) 1318 { 1319 case XML_ELEMENT(LO_EXT, XML_TEXT): 1320 case XML_ELEMENT(NUMBER, XML_TEXT): 1321 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1322 *this, SvXMLStyleTokens::Text, xAttrList ); 1323 break; 1324 case XML_ELEMENT(LO_EXT, XML_FILL_CHARACTER): 1325 case XML_ELEMENT(NUMBER, XML_FILL_CHARACTER): 1326 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1327 *this, SvXMLStyleTokens::FillCharacter, xAttrList ); 1328 break; 1329 case XML_ELEMENT(NUMBER, XML_NUMBER): 1330 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1331 *this, SvXMLStyleTokens::Number, xAttrList ); 1332 break; 1333 case XML_ELEMENT(NUMBER, XML_SCIENTIFIC_NUMBER): 1334 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1335 *this, SvXMLStyleTokens::ScientificNumber, xAttrList ); 1336 break; 1337 case XML_ELEMENT(NUMBER, XML_FRACTION): 1338 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1339 *this, SvXMLStyleTokens::Fraction, xAttrList ); 1340 break; 1341 case XML_ELEMENT(NUMBER, XML_CURRENCY_SYMBOL): 1342 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1343 *this, SvXMLStyleTokens::CurrencySymbol, xAttrList ); 1344 break; 1345 case XML_ELEMENT(NUMBER, XML_DAY): 1346 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1347 *this, SvXMLStyleTokens::Day, xAttrList ); 1348 break; 1349 case XML_ELEMENT(NUMBER, XML_MONTH): 1350 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1351 *this, SvXMLStyleTokens::Month, xAttrList ); 1352 break; 1353 case XML_ELEMENT(NUMBER, XML_YEAR): 1354 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1355 *this, SvXMLStyleTokens::Year, xAttrList ); 1356 break; 1357 case XML_ELEMENT(NUMBER, XML_ERA): 1358 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1359 *this, SvXMLStyleTokens::Era, xAttrList ); 1360 break; 1361 case XML_ELEMENT(NUMBER, XML_DAY_OF_WEEK): 1362 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1363 *this, SvXMLStyleTokens::DayOfWeek, xAttrList ); 1364 break; 1365 case XML_ELEMENT(NUMBER, XML_WEEK_OF_YEAR): 1366 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1367 *this, SvXMLStyleTokens::WeekOfYear, xAttrList ); 1368 break; 1369 case XML_ELEMENT(NUMBER, XML_QUARTER): 1370 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1371 *this, SvXMLStyleTokens::Quarter, xAttrList ); 1372 break; 1373 case XML_ELEMENT(NUMBER, XML_HOURS): 1374 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1375 *this, SvXMLStyleTokens::Hours, xAttrList ); 1376 break; 1377 case XML_ELEMENT(NUMBER, XML_AM_PM): 1378 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1379 *this, SvXMLStyleTokens::AmPm, xAttrList ); 1380 break; 1381 case XML_ELEMENT(NUMBER, XML_MINUTES): 1382 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1383 *this, SvXMLStyleTokens::Minutes, xAttrList ); 1384 break; 1385 case XML_ELEMENT(NUMBER, XML_SECONDS): 1386 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1387 *this, SvXMLStyleTokens::Seconds, xAttrList ); 1388 break; 1389 case XML_ELEMENT(NUMBER, XML_BOOLEAN): 1390 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1391 *this, SvXMLStyleTokens::Boolean, xAttrList ); 1392 break; 1393 case XML_ELEMENT(NUMBER, XML_TEXT_CONTENT): 1394 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, 1395 *this, SvXMLStyleTokens::TextContent, xAttrList ); 1396 break; 1397 1398 case XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES): 1399 pContext = new SvXMLNumFmtPropContext( GetImport(), nElement, 1400 *this, xAttrList ); 1401 break; 1402 case XML_ELEMENT(STYLE, XML_MAP): 1403 { 1404 // SvXMLNumFmtMapContext::EndElement adds to aMyConditions, 1405 // so there's no need for an extra flag 1406 pContext = new SvXMLNumFmtMapContext( GetImport(), nElement, 1407 *this, xAttrList ); 1408 } 1409 break; 1410 } 1411 1412 if( !pContext ) 1413 { 1414 SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); 1415 pContext = new SvXMLImportContext(GetImport()); 1416 } 1417 1418 return pContext; 1419 } 1420 1421 sal_Int32 SvXMLNumFormatContext::GetKey() 1422 { 1423 if (nKey > -1) 1424 { 1425 if (bRemoveAfterUse) 1426 { 1427 // format is used -> don't remove 1428 bRemoveAfterUse = false; 1429 if (pData) 1430 pData->SetUsed(nKey); 1431 1432 // Add to import's list of keys now - CreateAndInsert didn't add 1433 // the style if bRemoveAfterUse was set. 1434 GetImport().AddNumberStyle( nKey, GetName() ); 1435 } 1436 return nKey; 1437 } 1438 else 1439 { 1440 // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set 1441 bRemoveAfterUse = false; 1442 CreateAndInsert(true); 1443 return nKey; 1444 } 1445 } 1446 1447 sal_Int32 SvXMLNumFormatContext::PrivateGetKey() 1448 { 1449 // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag 1450 1451 if (nKey > -1) 1452 return nKey; 1453 else 1454 { 1455 CreateAndInsert(true); 1456 return nKey; 1457 } 1458 } 1459 1460 sal_Int32 SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference< css::util::XNumberFormatsSupplier > const & xFormatsSupplier ) 1461 { 1462 if (nKey <= -1) 1463 { 1464 SvNumberFormatter* pFormatter = nullptr; 1465 SvNumberFormatsSupplierObj* pObj = 1466 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xFormatsSupplier ); 1467 if (pObj) 1468 pFormatter = pObj->GetNumberFormatter(); 1469 1470 if ( pFormatter ) 1471 return CreateAndInsert( pFormatter ); 1472 else 1473 return -1; 1474 } 1475 else 1476 return nKey; 1477 } 1478 1479 void SvXMLNumFormatContext::CreateAndInsert(bool /*bOverwrite*/) 1480 { 1481 if (nKey <= -1) 1482 CreateAndInsert(pData->GetNumberFormatter()); 1483 } 1484 1485 sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) 1486 { 1487 if (!pFormatter) 1488 { 1489 OSL_FAIL("no number formatter"); 1490 return -1; 1491 } 1492 1493 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; 1494 1495 for (size_t i = 0; i < aMyConditions.size(); i++) 1496 { 1497 SvXMLNumFormatContext* pStyle = const_cast<SvXMLNumFormatContext*>( static_cast<const SvXMLNumFormatContext *>(pStyles->FindStyleChildContext( 1498 XmlStyleFamily::DATA_STYLE, aMyConditions[i].sMapName))); 1499 if (this == pStyle) 1500 { 1501 SAL_INFO("xmloff.style", "invalid style:map references containing style"); 1502 pStyle = nullptr; 1503 } 1504 if (pStyle) 1505 { 1506 if (pStyle->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag 1507 AddCondition(i); 1508 } 1509 } 1510 1511 sal_Int32 nBufLen; 1512 if ( aFormatCode.isEmpty() ) 1513 { 1514 // insert empty format as empty string (with quotes) 1515 // #93901# this check has to be done before inserting the conditions 1516 aFormatCode.append("\"\""); // "" 1517 } 1518 else if (bHasTrailingEmptyText && (nBufLen = aFormatCode.getLength()) >= 3) 1519 { 1520 // Remove a trailing empty text. Earlier this may had been written to 1521 // file, like in "General;General" written with elements for 1522 // 'General"";General""' (whyever); when reading, empty text was 1523 // ignored, which it isn't anymore, so get rid of those. 1524 if (aFormatCode[nBufLen-1] == '"' && aFormatCode[nBufLen-2] == '"') 1525 aFormatCode.truncate( nBufLen - 2); 1526 } 1527 1528 aFormatCode.insert( 0, aConditions ); 1529 aConditions.setLength(0); 1530 OUString sFormat = aFormatCode.makeStringAndClear(); 1531 1532 // test special cases 1533 1534 if ( bAutoDec ) // automatic decimal places 1535 { 1536 // #99391# adjust only if the format contains no text elements, no conditions 1537 // and no color definition (detected by the '[' at the start) 1538 1539 if ( nType == SvXMLStylesTokens::NUMBER_STYLE && !bHasExtraText && 1540 aMyConditions.empty() && sFormat.toChar() != '[' ) 1541 nIndex = pFormatter->GetStandardIndex( nFormatLang ); 1542 } 1543 if ( bAutoInt ) // automatic integer digits 1544 { 1545 //! only if two decimal places was set? 1546 1547 if ( nType == SvXMLStylesTokens::NUMBER_STYLE && !bHasExtraText && 1548 aMyConditions.empty() && sFormat.toChar() != '[' ) 1549 nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang ); 1550 } 1551 1552 if ( nType == SvXMLStylesTokens::BOOLEAN_STYLE && !bHasExtraText && 1553 aMyConditions.empty() && sFormat.toChar() != '[' ) 1554 nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang ); 1555 1556 // check for default date formats 1557 if ( nType == SvXMLStylesTokens::DATE_STYLE && bAutoOrder && !bDateNoDefault ) 1558 { 1559 NfIndexTableOffset eFormat = static_cast<NfIndexTableOffset>(SvXMLNumFmtDefaults::GetDefaultDateFormat( 1560 eDateDOW, eDateDay, eDateMonth, eDateYear, 1561 eDateHours, eDateMins, eDateSecs, bFromSystem )); 1562 if ( eFormat < NF_INDEX_TABLE_RESERVED_START ) 1563 { 1564 // #109651# if a date format has the automatic-order attribute and 1565 // contains exactly the elements of one of the default date formats, 1566 // use that default format, with the element order and separators 1567 // from the current locale settings 1568 1569 nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang ); 1570 } 1571 } 1572 1573 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() ) 1574 { 1575 // insert by format string 1576 1577 OUString aFormatStr( sFormat ); 1578 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); 1579 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) 1580 { 1581 sal_Int32 nErrPos = 0; 1582 SvNumFormatType l_nType = SvNumFormatType::ALL; 1583 bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang ); 1584 if ( !bOk && nErrPos == 0 && aFormatStr != sFormat ) 1585 { 1586 // if the string was modified by PutEntry, look for an existing format 1587 // with the modified string 1588 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); 1589 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND ) 1590 bOk = true; 1591 } 1592 if (!bOk) 1593 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; 1594 } 1595 } 1596 1597 //! I18N doesn't provide SYSTEM or extended date information yet 1598 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder ) 1599 { 1600 // use fixed-order formats instead of SYS... if bAutoOrder is false 1601 // (only if the format strings are equal for the locale) 1602 1603 NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex ); 1604 if ( eOffset == NF_DATE_SYS_DMMMYYYY ) 1605 { 1606 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang ); 1607 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); 1608 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); 1609 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) 1610 nIndex = nNewIndex; 1611 } 1612 else if ( eOffset == NF_DATE_SYS_DMMMMYYYY ) 1613 { 1614 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang ); 1615 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); 1616 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); 1617 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) 1618 nIndex = nNewIndex; 1619 } 1620 } 1621 1622 if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty()) 1623 { 1624 SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex )); 1625 if (pFormat) 1626 { 1627 pFormat->SetComment(sFormatTitle); 1628 } 1629 } 1630 1631 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) 1632 { 1633 OSL_FAIL("invalid number format"); 1634 nIndex = pFormatter->GetStandardIndex( nFormatLang ); 1635 } 1636 1637 pData->AddKey( nIndex, GetName(), bRemoveAfterUse ); 1638 nKey = nIndex; 1639 1640 // Add to import's list of keys (shared between styles and content import) 1641 // only if not volatile - formats are removed from NumberFormatter at the 1642 // end of each import (in SvXMLNumFmtHelper dtor). 1643 // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there. 1644 1645 if (!bRemoveAfterUse) 1646 GetImport().AddNumberStyle( nKey, GetName() ); 1647 1648 return nKey; 1649 } 1650 1651 const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const 1652 { 1653 return pData->GetLocaleData( nFormatLang ); 1654 } 1655 1656 void SvXMLNumFormatContext::AddToCode( sal_Unicode c ) 1657 { 1658 aFormatCode.append( c ); 1659 bHasExtraText = true; 1660 } 1661 1662 void SvXMLNumFormatContext::AddToCode( std::u16string_view rString ) 1663 { 1664 aFormatCode.append( rString ); 1665 bHasExtraText = true; 1666 bHasTrailingEmptyText = false; // is set by caller again if so 1667 } 1668 1669 void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) 1670 { 1671 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 1672 if (!pFormatter) 1673 return; 1674 1675 // store special conditions 1676 bAutoDec = ( rInfo.nDecimals < 0 ); 1677 bAutoInt = ( rInfo.nInteger < 0 ); 1678 1679 sal_uInt16 nPrec = 0; 1680 sal_uInt16 nLeading = 0; 1681 if ( rInfo.nDecimals >= 0 ) // < 0 : Default 1682 nPrec = static_cast<sal_uInt16>(rInfo.nDecimals); 1683 if ( rInfo.nInteger >= 0 ) // < 0 : Default 1684 nLeading = static_cast<sal_uInt16>(rInfo.nInteger); 1685 1686 if ( bAutoDec ) 1687 { 1688 if ( nType == SvXMLStylesTokens::CURRENCY_STYLE ) 1689 { 1690 // for currency formats, "automatic decimals" is used for the automatic 1691 // currency format with (fixed) decimals from the locale settings 1692 1693 const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang ); 1694 nPrec = rLoc.getCurrDigits(); 1695 } 1696 else 1697 { 1698 // for other types, "automatic decimals" means dynamic determination of 1699 // decimals, as achieved with the "general" keyword 1700 1701 aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) ); 1702 return; 1703 } 1704 } 1705 if ( bAutoInt ) 1706 { 1707 //!... 1708 } 1709 1710 sal_uInt16 nGenPrec = nPrec; 1711 if ( rInfo.nMinDecimalDigits >= 0 ) 1712 nGenPrec = rInfo.nMinDecimalDigits; 1713 if ( rInfo.bDecReplace ) 1714 nGenPrec = 0; // generate format without decimals... 1715 1716 bool bGrouping = rInfo.bGrouping; 1717 size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size(); 1718 if ( nEmbeddedCount && rInfo.m_EmbeddedElements.rbegin()->first > 0 ) 1719 bGrouping = false; // grouping and embedded characters in integer part can't be used together 1720 1721 sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang ); 1722 OUStringBuffer aNumStr(pFormatter->GenerateFormat( nStdIndex, nFormatLang, 1723 bGrouping, false, nGenPrec, nLeading )); 1724 1725 if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 ) 1726 { 1727 // #i43959# For scientific numbers, "#" in the integer part forces a digit, 1728 // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0"). 1729 1730 aNumStr.stripStart('#'); 1731 } 1732 1733 if ( rInfo.nBlankInteger > 0 ) 1734 { 1735 // Replace nBlankInteger '0' by '?' 1736 sal_Int32 nIndex = 0; 1737 sal_Int32 nBlanks = rInfo.nBlankInteger; 1738 sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); 1739 if ( nIntegerEnd < 0 ) 1740 nIntegerEnd = aNumStr.getLength(); 1741 while ( nIndex < nIntegerEnd && nBlanks > 0 ) 1742 { 1743 if ( aNumStr[nIndex] == '0' ) 1744 { 1745 aNumStr[nIndex] = '?'; 1746 nBlanks--; 1747 } 1748 nIndex++; 1749 } 1750 } 1751 1752 if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger ) 1753 { 1754 sal_Int32 nIndex = 0; 1755 sal_Int32 nDigits = rInfo.nInteger; 1756 sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); 1757 if ( nIntegerEnd < 0 ) 1758 nIntegerEnd = aNumStr.getLength(); 1759 while ( nIndex >= 0 && nIndex < nIntegerEnd ) 1760 { 1761 if ( ( nIndex = aNumStr.indexOf( '#', nIndex ) ) >= 0 ) 1762 { 1763 nDigits ++; 1764 nIndex ++; 1765 } 1766 else 1767 nIndex = -1; 1768 } 1769 while ( rInfo.nExpInterval > nDigits ) 1770 { 1771 nDigits++; 1772 aNumStr.insert( 0, '#' ); 1773 } 1774 } 1775 1776 if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) 1777 { 1778 // add dashes for explicit decimal replacement, # or ? for variable decimals 1779 sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' ); 1780 1781 if ( rInfo.nMinDecimalDigits == 0 ) 1782 aNumStr.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); 1783 for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i<nPrec; i++) 1784 aNumStr.append( cAdd ); 1785 } 1786 1787 if ( nEmbeddedCount ) 1788 { 1789 // insert embedded strings into number string 1790 // support integer (position >=0) and decimal (position <0) part 1791 // nZeroPos is the string position where format position 0 is inserted 1792 1793 sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); 1794 if ( nZeroPos < 0 ) 1795 { 1796 nZeroPos = aNumStr.getLength(); 1797 } 1798 1799 // m_EmbeddedElements is sorted - last entry has the largest position (leftmost) 1800 sal_Int32 const nLastFormatPos = rInfo.m_EmbeddedElements.rbegin()->first; 1801 if ( nLastFormatPos >= nZeroPos ) 1802 { 1803 // add '#' characters so all embedded texts are really embedded in digits 1804 // (there always has to be a digit before the leftmost embedded text) 1805 1806 sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos; 1807 for(sal_Int32 index = 0; index < nAddCount; ++index) 1808 { 1809 aNumStr.insert(0, '#'); 1810 } 1811 nZeroPos = nZeroPos + nAddCount; 1812 } 1813 1814 // m_EmbeddedElements is sorted with ascending positions - loop is from right to left 1815 for (auto const& it : rInfo.m_EmbeddedElements) 1816 { 1817 sal_Int32 const nFormatPos = it.first; 1818 sal_Int32 nInsertPos = nZeroPos - nFormatPos; 1819 if ( nInsertPos >= 0 ) 1820 { 1821 // #107805# always quote embedded strings - even space would otherwise 1822 // be recognized as thousands separator in French. 1823 1824 aNumStr.insert(nInsertPos, '"'); 1825 aNumStr.insert(nInsertPos, it.second); 1826 aNumStr.insert(nInsertPos, '"'); 1827 } 1828 } 1829 } 1830 1831 aFormatCode.append( aNumStr ); 1832 1833 // add extra thousands separators for display factor 1834 1835 if (rInfo.fDisplayFactor == 1.0 || rInfo.fDisplayFactor <= 0.0) 1836 return; 1837 1838 // test for 1.0 is just for optimization - nSepCount would be 0 1839 1840 // one separator for each factor of 1000 1841 sal_Int32 nSepCount = static_cast<sal_Int32>(::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 )); 1842 if ( nSepCount > 0 ) 1843 { 1844 OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep(); 1845 for ( sal_Int32 i=0; i<nSepCount; i++ ) 1846 aFormatCode.append( aSep ); 1847 } 1848 } 1849 1850 void SvXMLNumFormatContext::AddCurrency( const OUString& rContent, LanguageType nLang ) 1851 { 1852 bool bAutomatic = false; 1853 OUString aSymbol = rContent; 1854 if ( aSymbol.isEmpty()) 1855 { 1856 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 1857 if ( pFormatter ) 1858 { 1859 pFormatter->ChangeIntl( nFormatLang ); 1860 OUString sCurString, sDummy; 1861 pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); 1862 aSymbol = sCurString; 1863 1864 bAutomatic = true; 1865 } 1866 } 1867 else if ( nLang == LANGUAGE_SYSTEM && aSymbol == "CCC" ) 1868 { 1869 // "CCC" is used for automatic long symbol 1870 bAutomatic = true; 1871 } 1872 1873 if ( bAutomatic ) 1874 { 1875 // remove unnecessary quotes before automatic symbol (formats like "-(0DM)") 1876 // otherwise the currency symbol isn't recognized (#94048#) 1877 1878 sal_Int32 nLength = aFormatCode.getLength(); 1879 if ( nLength > 1 && aFormatCode[nLength - 1] == '"' ) 1880 { 1881 // find start of quoted string 1882 // When SvXMLNumFmtElementContext::EndElement creates escaped quotes, 1883 // they must be handled here, too. 1884 1885 sal_Int32 nFirst = nLength - 2; 1886 while ( nFirst >= 0 && aFormatCode[nFirst] != '"' ) 1887 --nFirst; 1888 if ( nFirst >= 0 ) 1889 { 1890 // remove both quotes from aFormatCode 1891 OUString aOld = aFormatCode.makeStringAndClear(); 1892 if ( nFirst > 0 ) 1893 aFormatCode.append( aOld.subView( 0, nFirst ) ); 1894 if ( nLength > nFirst + 2 ) 1895 aFormatCode.append( aOld.subView( nFirst + 1, nLength - nFirst - 2 ) ); 1896 } 1897 } 1898 } 1899 1900 if (!bAutomatic) 1901 aFormatCode.append( "[$" ); // intro for "new" currency symbols 1902 1903 aFormatCode.append( aSymbol ); 1904 1905 if (!bAutomatic) 1906 { 1907 if ( nLang != LANGUAGE_SYSTEM ) 1908 { 1909 // '-' sign and language code in hex: 1910 aFormatCode.append("-" + OUString(OUString::number(sal_uInt16(nLang), 16)).toAsciiUpperCase()); 1911 } 1912 1913 aFormatCode.append( ']' ); // end of "new" currency symbol 1914 } 1915 } 1916 1917 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex ) 1918 { 1919 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 1920 if (!pFormatter) 1921 return; 1922 1923 if ( nIndex == NF_KEY_NNNN ) 1924 { 1925 nIndex = NF_KEY_NNN; 1926 bHasLongDoW = true; // to remove string constant with separator 1927 } 1928 1929 OUString sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex ); 1930 1931 if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH || 1932 nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI || 1933 nIndex == NF_KEY_S || nIndex == NF_KEY_SS ) 1934 { 1935 if ( !bTruncate && !bHasDateTime ) 1936 { 1937 // with truncate-on-overflow = false, add "[]" to first time part 1938 aFormatCode.append("[" + sKeyword + "]"); 1939 } 1940 else 1941 { 1942 aFormatCode.append( sKeyword ); 1943 } 1944 bHasDateTime = true; 1945 } 1946 else 1947 { 1948 aFormatCode.append( sKeyword ); 1949 } 1950 // collect the date elements that the format contains, to recognize default date formats 1951 switch ( nIndex ) 1952 { 1953 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; 1954 case NF_KEY_NNN: 1955 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; 1956 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; 1957 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; 1958 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; 1959 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; 1960 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; 1961 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; 1962 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; 1963 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; 1964 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; 1965 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; 1966 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; 1967 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; 1968 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; 1969 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; 1970 case NF_KEY_AP: 1971 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself 1972 default: 1973 bDateNoDefault = true; // any other element -> no default format 1974 } 1975 } 1976 1977 static bool lcl_IsAtEnd( OUStringBuffer& rBuffer, std::u16string_view rToken ) 1978 { 1979 sal_Int32 nBufLen = rBuffer.getLength(); 1980 sal_Int32 nTokLen = rToken.size(); 1981 1982 if ( nTokLen > nBufLen ) 1983 return false; 1984 1985 sal_Int32 nStartPos = nBufLen - nTokLen; 1986 for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ ) 1987 if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] ) 1988 return false; 1989 1990 return true; 1991 } 1992 1993 bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew ) 1994 { 1995 // replaces one keyword with another if it is found at the end of the code 1996 1997 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 1998 if (!pFormatter) 1999 return false; 2000 2001 OUString sOldStr = pFormatter->GetKeyword( nFormatLang, nOld ); 2002 if ( lcl_IsAtEnd( aFormatCode, sOldStr ) ) 2003 { 2004 // remove old keyword 2005 aFormatCode.setLength( aFormatCode.getLength() - sOldStr.getLength() ); 2006 2007 // add new keyword 2008 OUString sNewStr = pFormatter->GetKeyword( nFormatLang, nNew ); 2009 aFormatCode.append( sNewStr ); 2010 2011 return true; // changed 2012 } 2013 return false; // not found 2014 } 2015 2016 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex ) 2017 { 2018 OUString rApplyName = aMyConditions[nIndex].sMapName; 2019 OUString rCondition = aMyConditions[nIndex].sCondition; 2020 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 2021 sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName ); 2022 2023 OUString sRealCond; 2024 if ( !(pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND && 2025 rCondition.startsWith("value()", &sRealCond)) ) 2026 return; 2027 2028 //! test for valid conditions 2029 //! test for default conditions 2030 2031 bool bDefaultCond = false; 2032 2033 //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count 2034 //! allow blanks in conditions 2035 if ( aConditions.isEmpty() && aMyConditions.size() == 1 && sRealCond == ">=0" ) 2036 bDefaultCond = true; 2037 2038 if ( nType == SvXMLStylesTokens::TEXT_STYLE && static_cast<size_t>(nIndex) == aMyConditions.size() - 1 ) 2039 { 2040 // The last condition in a number format with a text part can only 2041 // be "all other numbers", the condition string must be empty. 2042 bDefaultCond = true; 2043 } 2044 2045 if (!bDefaultCond) 2046 { 2047 // Convert != to <> 2048 sal_Int32 nPos = sRealCond.indexOf( "!=" ); 2049 if ( nPos >= 0 ) 2050 { 2051 sRealCond = sRealCond.replaceAt( nPos, 2, u"<>" ); 2052 } 2053 2054 nPos = sRealCond.indexOf( '.' ); 2055 if ( nPos >= 0 ) 2056 { 2057 // #i8026# #103991# localize decimal separator 2058 const OUString& rDecSep = GetLocaleData().getNumDecimalSep(); 2059 if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' ) 2060 { 2061 sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep ); 2062 } 2063 } 2064 aConditions.append("[" + sRealCond + "]"); 2065 } 2066 2067 const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey); 2068 if ( pFormat ) 2069 aConditions.append( pFormat->GetFormatstring() ); 2070 2071 aConditions.append( ';' ); 2072 } 2073 2074 void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName ) 2075 { 2076 MyCondition aCondition; 2077 aCondition.sCondition = rCondition; 2078 aCondition.sMapName = rApplyName; 2079 aMyConditions.push_back(aCondition); 2080 } 2081 2082 void SvXMLNumFormatContext::AddColor( Color const nColor ) 2083 { 2084 SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); 2085 if (!pFormatter) 2086 return; 2087 2088 OUStringBuffer aColName; 2089 for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ ) 2090 if (nColor == aNumFmtStdColors[i]) 2091 { 2092 aColName = pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ); 2093 break; 2094 } 2095 2096 if ( !aColName.isEmpty() ) 2097 { 2098 aColName.insert( 0, '[' ); 2099 aColName.append( ']' ); 2100 aFormatCode.insert( 0, aColName ); 2101 } 2102 } 2103 2104 void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar ) 2105 { 2106 if ( rNewCalendar == sCalendar ) 2107 return; 2108 2109 if (rNewCalendar.isEmpty() || rNewCalendar == aImplicitCalendar[0]) 2110 { 2111 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? 2112 ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); 2113 } 2114 else if (aImplicitCalendar[0].isEmpty() && rNewCalendar == GetLocaleData().getDefaultCalendar()->Name) 2115 { 2116 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? 2117 ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); 2118 aImplicitCalendar[0] = rNewCalendar; 2119 } 2120 else if (rNewCalendar == aImplicitCalendar[1]) 2121 { 2122 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? 2123 ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); 2124 } 2125 else if (aImplicitCalendar[1].isEmpty() && GetLocaleData().doesSecondaryCalendarUseEC( rNewCalendar)) 2126 { 2127 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? 2128 ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); 2129 aImplicitCalendar[1] = rNewCalendar; 2130 } 2131 else 2132 { 2133 eImplicitCalendar = ImplicitCalendar::OTHER; 2134 } 2135 2136 if (eImplicitCalendar != ImplicitCalendar::DEFAULT && eImplicitCalendar != ImplicitCalendar::SECONDARY) 2137 { 2138 // A switch from empty default calendar to named default calendar or 2139 // vice versa is not a switch. 2140 bool bSameDefault = false; 2141 if (sCalendar.isEmpty() || rNewCalendar.isEmpty()) 2142 { 2143 // As both are not equal, only one can be empty here, the other 2144 // can not. 2145 const OUString& rDefaultCalendar = GetLocaleData().getDefaultCalendar()->Name; 2146 // So if one is the named default calendar the other is the 2147 // empty default calendar. 2148 bSameDefault = (rNewCalendar == rDefaultCalendar || sCalendar == rDefaultCalendar); 2149 } 2150 if (!bSameDefault) 2151 { 2152 aFormatCode.append( "[~" ); // intro for calendar code 2153 if (rNewCalendar.isEmpty()) 2154 { 2155 // Empty calendar name here means switching to default calendar 2156 // from a different calendar. Needs to be explicitly stated in 2157 // format code. 2158 aFormatCode.append( GetLocaleData().getDefaultCalendar()->Name ); 2159 } 2160 else 2161 { 2162 aFormatCode.append( rNewCalendar ); 2163 } 2164 aFormatCode.append( ']' ); // end of calendar code 2165 } 2166 } 2167 sCalendar = rNewCalendar; 2168 } 2169 2170 bool SvXMLNumFormatContext::IsSystemLanguage() const 2171 { 2172 return nFormatLang == LANGUAGE_SYSTEM; 2173 } 2174 2175 2176 // SvXMLNumFmtHelper 2177 2178 2179 SvXMLNumFmtHelper::SvXMLNumFmtHelper( 2180 const uno::Reference<util::XNumberFormatsSupplier>& rSupp, 2181 const uno::Reference<uno::XComponentContext>& rxContext ) 2182 { 2183 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); 2184 2185 SvNumberFormatter* pFormatter = nullptr; 2186 SvNumberFormatsSupplierObj* pObj = 2187 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp ); 2188 if (pObj) 2189 pFormatter = pObj->GetNumberFormatter(); 2190 2191 pData = std::make_unique<SvXMLNumImpData>( pFormatter, rxContext ); 2192 } 2193 2194 SvXMLNumFmtHelper::SvXMLNumFmtHelper( 2195 SvNumberFormatter* pNumberFormatter, 2196 const uno::Reference<uno::XComponentContext>& rxContext ) 2197 { 2198 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); 2199 2200 pData = std::make_unique<SvXMLNumImpData>( pNumberFormatter, rxContext ); 2201 } 2202 2203 SvXMLNumFmtHelper::~SvXMLNumFmtHelper() 2204 { 2205 // remove temporary (volatile) formats from NumberFormatter 2206 pData->RemoveVolatileFormats(); 2207 } 2208 2209 2210 SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport, 2211 sal_Int32 nElement, 2212 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, 2213 SvXMLStylesContext& rStyles ) 2214 { 2215 SvXMLStylesTokens nStyleToken; 2216 switch (nElement) 2217 { 2218 case XML_ELEMENT(NUMBER, XML_NUMBER_STYLE): 2219 nStyleToken = SvXMLStylesTokens::NUMBER_STYLE; 2220 break; 2221 case XML_ELEMENT(NUMBER, XML_CURRENCY_STYLE): 2222 nStyleToken = SvXMLStylesTokens::CURRENCY_STYLE; 2223 break; 2224 case XML_ELEMENT(NUMBER, XML_PERCENTAGE_STYLE): 2225 nStyleToken = SvXMLStylesTokens::PERCENTAGE_STYLE; 2226 break; 2227 case XML_ELEMENT(NUMBER, XML_DATE_STYLE): 2228 nStyleToken = SvXMLStylesTokens::DATE_STYLE; 2229 break; 2230 case XML_ELEMENT(NUMBER, XML_TIME_STYLE): 2231 nStyleToken = SvXMLStylesTokens::TIME_STYLE; 2232 break; 2233 case XML_ELEMENT(NUMBER, XML_BOOLEAN_STYLE): 2234 nStyleToken = SvXMLStylesTokens::BOOLEAN_STYLE; 2235 break; 2236 case XML_ELEMENT(NUMBER, XML_TEXT_STYLE): 2237 nStyleToken = SvXMLStylesTokens::TEXT_STYLE; 2238 break; 2239 default: 2240 // return NULL if not a data style, caller must handle other elements 2241 return nullptr; 2242 } 2243 return new SvXMLNumFormatContext( rImport, nElement, 2244 pData.get(), nStyleToken, xAttrList, rStyles ); 2245 } 2246 2247 LanguageType SvXMLNumFmtHelper::GetLanguageForKey(sal_Int32 nKey) const 2248 { 2249 if (pData->GetNumberFormatter()) 2250 { 2251 const SvNumberformat* pEntry = pData->GetNumberFormatter()->GetEntry(nKey); 2252 if (pEntry) 2253 return pEntry->GetLanguage(); 2254 } 2255 2256 return LANGUAGE_SYSTEM; 2257 } 2258 2259 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2260
