1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <comphelper/string.hxx>
21 #include <svl/zforlist.hxx>
22 #include <svl/zformat.hxx>
23 #include <svl/numuno.hxx>
24 #include <i18nlangtag/mslangid.hxx>
25 #include <i18nlangtag/languagetag.hxx>
26 #include <tools/debug.hxx>
27 #include <rtl/math.hxx>
28 #include <unotools/calendarwrapper.hxx>
29 #include <unotools/charclass.hxx>
30 #include <com/sun/star/lang/Locale.hpp>
31 #include <rtl/ustrbuf.hxx>
32 #include <tools/color.hxx>
33 #include <sax/tools/converter.hxx>
35 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
37 #include <xmloff/xmlnumfe.hxx>
38 #include "xmloff/xmlnmspe.hxx"
39 #include <xmloff/attrlist.hxx>
40 #include <xmloff/nmspmap.hxx>
41 #include <xmloff/families.hxx>
42 #include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults
44 #include <svl/nfsymbol.hxx>
45 #include <xmloff/xmltoken.hxx>
46 #include <xmloff/xmlexp.hxx>
49 #include <boost/ptr_container/ptr_vector.hpp>
52 using namespace ::com::sun::star
;
53 using namespace ::xmloff::token
;
54 using namespace ::svt
;
56 //-------------------------------------------------------------------------
58 #define XMLNUM_MAX_PARTS 3
60 //-------------------------------------------------------------------------
64 sal_Bool
operator() (const sal_uInt32 rValue1
, const sal_uInt32 rValue2
) const
66 return rValue1
< rValue2
;
70 typedef std::set
< sal_uInt32
, LessuInt32
> SvXMLuInt32Set
;
72 class SvXMLNumUsedList_Impl
75 SvXMLuInt32Set aWasUsed
;
76 SvXMLuInt32Set::iterator aCurrentUsedPos
;
77 sal_uInt32 nUsedCount
;
78 sal_uInt32 nWasUsedCount
;
81 SvXMLNumUsedList_Impl();
82 ~SvXMLNumUsedList_Impl();
84 void SetUsed( sal_uInt32 nKey
);
85 sal_Bool
IsUsed( sal_uInt32 nKey
) const;
86 sal_Bool
IsWasUsed( sal_uInt32 nKey
) const;
89 sal_Bool
GetFirstUsed(sal_uInt32
& nKey
);
90 sal_Bool
GetNextUsed(sal_uInt32
& nKey
);
92 void GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
);
93 void SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
);
96 //-------------------------------------------------------------------------
98 struct SvXMLEmbeddedTextEntry
100 sal_uInt16 nSourcePos
; // position in NumberFormat (to skip later)
101 sal_Int32 nFormatPos
; // resulting position in embedded-text element
104 SvXMLEmbeddedTextEntry( sal_uInt16 nSP
, sal_Int32 nFP
, const OUString
& rT
) :
105 nSourcePos(nSP
), nFormatPos(nFP
), aText(rT
) {}
108 class SvXMLEmbeddedTextEntryArr
: public boost::ptr_vector
<SvXMLEmbeddedTextEntry
> {};
110 //-------------------------------------------------------------------------
113 //! SvXMLNumUsedList_Impl should be optimized!
116 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
122 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
126 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey
)
128 if ( !IsWasUsed(nKey
) )
130 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aUsed
.insert( nKey
);
136 sal_Bool
SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey
) const
138 SvXMLuInt32Set::const_iterator aItr
= aUsed
.find(nKey
);
139 return (aItr
!= aUsed
.end());
142 sal_Bool
SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey
) const
144 SvXMLuInt32Set::const_iterator aItr
= aWasUsed
.find(nKey
);
145 return (aItr
!= aWasUsed
.end());
148 void SvXMLNumUsedList_Impl::Export()
150 SvXMLuInt32Set::const_iterator aItr
= aUsed
.begin();
151 while (aItr
!= aUsed
.end())
153 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( *aItr
);
162 sal_Bool
SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32
& nKey
)
164 sal_Bool
bRet(sal_False
);
165 aCurrentUsedPos
= aUsed
.begin();
168 DBG_ASSERT(aCurrentUsedPos
!= aUsed
.end(), "something went wrong");
169 nKey
= *aCurrentUsedPos
;
175 sal_Bool
SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32
& nKey
)
177 sal_Bool
bRet(sal_False
);
178 if (aCurrentUsedPos
!= aUsed
.end())
181 if (aCurrentUsedPos
!= aUsed
.end())
183 nKey
= *aCurrentUsedPos
;
190 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
192 rWasUsed
.realloc(nWasUsedCount
);
193 sal_Int32
* pWasUsed
= rWasUsed
.getArray();
196 SvXMLuInt32Set::const_iterator aItr
= aWasUsed
.begin();
197 while (aItr
!= aWasUsed
.end())
206 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
208 DBG_ASSERT(nWasUsedCount
== 0, "WasUsed should be empty");
209 sal_Int32
nCount(rWasUsed
.getLength());
210 const sal_Int32
* pWasUsed
= rWasUsed
.getConstArray();
211 for (sal_uInt16 i
= 0; i
< nCount
; i
++, pWasUsed
++)
213 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( *pWasUsed
);
219 //-------------------------------------------------------------------------
221 SvXMLNumFmtExport::SvXMLNumFmtExport(
223 const uno::Reference
< util::XNumberFormatsSupplier
>& rSupp
) :
225 sPrefix( OUString("N") ),
230 // supplier must be SvNumberFormatsSupplierObj
231 SvNumberFormatsSupplierObj
* pObj
=
232 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
234 pFormatter
= pObj
->GetNumberFormatter();
238 pCharClass
= new CharClass( pFormatter
->GetComponentContext(),
239 pFormatter
->GetLanguageTag() );
240 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetComponentContext(),
241 pFormatter
->GetLanguageTag() );
245 LanguageTag
aLanguageTag( MsLangId::getSystemLanguage() );
247 pCharClass
= new CharClass( rExport
.getComponentContext(), aLanguageTag
);
248 pLocaleData
= new LocaleDataWrapper( rExport
.getComponentContext(), aLanguageTag
);
251 pUsedList
= new SvXMLNumUsedList_Impl
;
254 SvXMLNumFmtExport::SvXMLNumFmtExport(
256 const ::com::sun::star::uno::Reference
<
257 ::com::sun::star::util::XNumberFormatsSupplier
>& rSupp
,
258 const OUString
& rPrefix
) :
265 // supplier must be SvNumberFormatsSupplierObj
266 SvNumberFormatsSupplierObj
* pObj
=
267 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
269 pFormatter
= pObj
->GetNumberFormatter();
273 pCharClass
= new CharClass( pFormatter
->GetComponentContext(),
274 pFormatter
->GetLanguageTag() );
275 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetComponentContext(),
276 pFormatter
->GetLanguageTag() );
280 LanguageTag
aLanguageTag( MsLangId::getSystemLanguage() );
282 pCharClass
= new CharClass( rExport
.getComponentContext(), aLanguageTag
);
283 pLocaleData
= new LocaleDataWrapper( rExport
.getComponentContext(), aLanguageTag
);
286 pUsedList
= new SvXMLNumUsedList_Impl
;
289 SvXMLNumFmtExport::~SvXMLNumFmtExport()
296 //-------------------------------------------------------------------------
302 static OUString
lcl_CreateStyleName( sal_Int32 nKey
, sal_Int32 nPart
, sal_Bool bDefPart
, const OUString
& rPrefix
)
304 OUStringBuffer
aFmtName( 10L );
305 aFmtName
.append( rPrefix
);
306 aFmtName
.append( nKey
);
309 aFmtName
.append( (sal_Unicode
)'P' );
310 aFmtName
.append( nPart
);
312 return aFmtName
.makeStringAndClear();
315 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString
& rCalendar
)
317 if ( !rCalendar
.isEmpty() )
319 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_CALENDAR
, rCalendar
);
323 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText
)
325 if ( bText
) // non-textual
327 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TEXTUAL
, XML_TRUE
);
331 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong
)
333 if ( bLong
) // short is default
335 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_STYLE
, XML_LONG
);
339 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang
)
341 if ( nLang
!= LANGUAGE_SYSTEM
)
343 /* FIXME-BCP47: handle language tags!
344 * ODF now provides fo:script, and rfc-language-tag attribute in case a
345 * locale can't be expressed using these three ISO codes.
346 * Of course these need to be read in xmlnumfi.cxx then..
347 * In general all places using XML_LANGUAGE and XML_COUNTRY need to be
348 * adapted once we really support bcp47. */
349 OUString aLangStr
, aCountryStr
;
350 LanguageTag( (LanguageType
)nLang
).getIsoLanguageCountry( aLangStr
, aCountryStr
);
352 if (!aLangStr
.isEmpty())
353 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_LANGUAGE
, aLangStr
);
354 if (!aCountryStr
.isEmpty())
355 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_COUNTRY
, aCountryStr
);
359 //-------------------------------------------------------------------------
362 // methods to write individual elements within a format
365 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString
& rString
)
367 // append to sTextContent, write element in FinishTextElement_Impl
368 // to avoid several text elements following each other
370 sTextContent
.append( rString
);
373 void SvXMLNumFmtExport::FinishTextElement_Impl()
375 if ( sTextContent
.getLength() )
377 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
378 sal_True
, sal_False
);
379 rExport
.Characters( sTextContent
.makeStringAndClear() );
383 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color
& rColor
)
385 FinishTextElement_Impl();
387 OUStringBuffer
aColStr( 7 );
388 ::sax::Converter::convertColor( aColStr
, rColor
.GetColor() );
389 rExport
.AddAttribute( XML_NAMESPACE_FO
, XML_COLOR
,
390 aColStr
.makeStringAndClear() );
392 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_TEXT_PROPERTIES
,
393 sal_True
, sal_False
);
396 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString
& rString
,
397 const OUString
& rExt
)
399 FinishTextElement_Impl();
401 if ( !rExt
.isEmpty() )
403 sal_Int32 nLang
= rExt
.toInt32(16); // hex
404 if ( nLang
< 0 ) // extension string may contain "-" separator
406 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
409 SvXMLElementExport
aElem( rExport
,
410 XML_NAMESPACE_NUMBER
, XML_CURRENCY_SYMBOL
,
411 sal_True
, sal_False
);
412 rExport
.Characters( rString
);
415 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
417 FinishTextElement_Impl();
419 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_BOOLEAN
,
420 sal_True
, sal_False
);
423 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
425 FinishTextElement_Impl();
427 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT_CONTENT
,
428 sal_True
, sal_False
);
433 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
435 FinishTextElement_Impl();
437 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
438 AddStyleAttr_Impl( bLong
); // adds to pAttrList
440 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY
,
441 sal_True
, sal_False
);
444 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
, sal_Bool bText
)
446 FinishTextElement_Impl();
448 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
449 AddStyleAttr_Impl( bLong
); // adds to pAttrList
450 AddTextualAttr_Impl( bText
); // adds to pAttrList
452 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MONTH
,
453 sal_True
, sal_False
);
456 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
458 FinishTextElement_Impl();
460 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
461 AddStyleAttr_Impl( bLong
); // adds to pAttrList
463 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_YEAR
,
464 sal_True
, sal_False
);
467 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
469 FinishTextElement_Impl();
471 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
472 AddStyleAttr_Impl( bLong
); // adds to pAttrList
474 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_ERA
,
475 sal_True
, sal_False
);
478 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
480 FinishTextElement_Impl();
482 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
483 AddStyleAttr_Impl( bLong
); // adds to pAttrList
485 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY_OF_WEEK
,
486 sal_True
, sal_False
);
489 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString
& rCalendar
)
491 FinishTextElement_Impl();
493 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
495 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_WEEK_OF_YEAR
,
496 sal_True
, sal_False
);
499 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
501 FinishTextElement_Impl();
503 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
504 AddStyleAttr_Impl( bLong
); // adds to pAttrList
506 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_QUARTER
,
507 sal_True
, sal_False
);
512 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong
)
514 FinishTextElement_Impl();
516 AddStyleAttr_Impl( bLong
); // adds to pAttrList
518 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_HOURS
,
519 sal_True
, sal_False
);
522 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong
)
524 FinishTextElement_Impl();
526 AddStyleAttr_Impl( bLong
); // adds to pAttrList
528 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MINUTES
,
529 sal_True
, sal_False
);
532 void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar
)
534 FinishTextElement_Impl();
535 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_LO_EXT
, XML_FILL_CHARACTER
,
536 sal_True
, sal_False
);
537 rExport
.Characters( OUString::valueOf( nChar
) );
540 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong
, sal_uInt16 nDecimals
)
542 FinishTextElement_Impl();
544 AddStyleAttr_Impl( bLong
); // adds to pAttrList
547 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
548 OUString::valueOf( (sal_Int32
) nDecimals
) );
551 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_SECONDS
,
552 sal_True
, sal_False
);
555 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
557 FinishTextElement_Impl();
559 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_AM_PM
,
560 sal_True
, sal_False
);
565 void SvXMLNumFmtExport::WriteNumberElement_Impl(
566 sal_Int32 nDecimals
, sal_Int32 nInteger
,
567 const OUString
& rDashStr
, sal_Bool bVarDecimals
,
568 sal_Bool bGrouping
, sal_Int32 nTrailingThousands
,
569 const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
)
571 FinishTextElement_Impl();
574 if ( nDecimals
>= 0 ) // negative = automatic
576 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
577 OUString::valueOf( nDecimals
) );
581 if ( nInteger
>= 0 ) // negative = automatic
583 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
584 OUString::valueOf( nInteger
) );
587 // decimal replacement (dashes) or variable decimals (#)
588 if ( !rDashStr
.isEmpty() || bVarDecimals
)
590 // variable decimals means an empty replacement string
591 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_REPLACEMENT
,
595 // (automatic) grouping separator
598 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
601 // display-factor if there are trailing thousands separators
602 if ( nTrailingThousands
)
604 // each separator character removes three digits
605 double fFactor
= ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands
);
607 OUStringBuffer aFactStr
;
608 ::sax::Converter::convertDouble( aFactStr
, fFactor
);
609 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DISPLAY_FACTOR
, aFactStr
.makeStringAndClear() );
612 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_NUMBER
,
613 sal_True
, sal_True
);
615 // number:embedded-text as child elements
617 sal_uInt16 nEntryCount
= rEmbeddedEntries
.size();
618 for (sal_uInt16 nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
620 const SvXMLEmbeddedTextEntry
* pObj
= &rEmbeddedEntries
[nEntry
];
622 // position attribute
623 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_POSITION
,
624 OUString::valueOf( pObj
->nFormatPos
) );
625 SvXMLElementExport
aChildElem( rExport
, XML_NAMESPACE_NUMBER
, XML_EMBEDDED_TEXT
,
626 sal_True
, sal_False
);
628 // text as element content
629 OUString
aContent( pObj
->aText
);
630 while ( nEntry
+1 < nEntryCount
&& rEmbeddedEntries
[nEntry
+1].nFormatPos
== pObj
->nFormatPos
)
632 // The array can contain several elements for the same position in the number
633 // (for example, literal text and space from underscores). They must be merged
634 // into a single embedded-text element.
635 aContent
+= rEmbeddedEntries
[nEntry
+1].aText
;
638 rExport
.Characters( aContent
);
642 void SvXMLNumFmtExport::WriteScientificElement_Impl(
643 sal_Int32 nDecimals
, sal_Int32 nInteger
,
644 sal_Bool bGrouping
, sal_Int32 nExp
)
646 FinishTextElement_Impl();
649 if ( nDecimals
>= 0 ) // negative = automatic
651 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
652 OUString::valueOf( nDecimals
) );
656 if ( nInteger
>= 0 ) // negative = automatic
658 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
659 OUString::valueOf( nInteger
) );
662 // (automatic) grouping separator
665 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
671 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_EXPONENT_DIGITS
,
672 OUString::valueOf( nExp
) );
675 SvXMLElementExport
aElem( rExport
,
676 XML_NAMESPACE_NUMBER
, XML_SCIENTIFIC_NUMBER
,
677 sal_True
, sal_False
);
680 void SvXMLNumFmtExport::WriteFractionElement_Impl(
681 sal_Int32 nInteger
, sal_Bool bGrouping
,
682 sal_Int32 nNumeratorDigits
, sal_Int32 nDenominatorDigits
, sal_Int32 nDenominator
)
684 FinishTextElement_Impl();
687 if ( nInteger
>= 0 ) // negative = default (no integer part)
689 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
690 OUString::valueOf( nInteger
) );
693 // (automatic) grouping separator
696 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
700 if ( nNumeratorDigits
>= 0 )
702 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_NUMERATOR_DIGITS
,
703 OUString::valueOf( nNumeratorDigits
) );
708 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DENOMINATOR_VALUE
,
709 OUString::valueOf( nDenominator
) );
711 // I guess it's not necessary to export nDenominatorDigits
712 // if we have a forced denominator ( remove ? )
713 if ( nDenominatorDigits
>= 0 )
715 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_DENOMINATOR_DIGITS
,
716 OUString::valueOf( nDenominatorDigits
) );
719 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_FRACTION
,
720 sal_True
, sal_False
);
723 // mapping (condition)
725 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp
, double fLimit
,
726 sal_Int32 nKey
, sal_Int32 nPart
)
728 FinishTextElement_Impl();
730 if ( nOp
!= NUMBERFORMAT_OP_NO
)
734 OUStringBuffer
aCondStr( 20L );
735 aCondStr
.appendAscii( "value()" ); //! define constant
738 case NUMBERFORMAT_OP_EQ
: aCondStr
.append( (sal_Unicode
) '=' ); break;
739 case NUMBERFORMAT_OP_NE
: aCondStr
.appendAscii( "<>" ); break;
740 case NUMBERFORMAT_OP_LT
: aCondStr
.append( (sal_Unicode
) '<' ); break;
741 case NUMBERFORMAT_OP_LE
: aCondStr
.appendAscii( "<=" ); break;
742 case NUMBERFORMAT_OP_GT
: aCondStr
.append( (sal_Unicode
) '>' ); break;
743 case NUMBERFORMAT_OP_GE
: aCondStr
.appendAscii( ">=" ); break;
745 OSL_FAIL("unknown operator");
747 ::rtl::math::doubleToUStringBuffer( aCondStr
, fLimit
,
748 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
751 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_CONDITION
,
752 aCondStr
.makeStringAndClear() );
754 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_APPLY_STYLE_NAME
,
755 rExport
.EncodeStyleName( lcl_CreateStyleName( nKey
, nPart
, sal_False
,
758 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_MAP
,
759 sal_True
, sal_False
);
763 //-------------------------------------------------------------------------
764 // for old (automatic) currency formats: parse currency symbol from text
766 sal_Int32
lcl_FindSymbol( const OUString
& sUpperStr
, const OUString
& sCurString
)
768 // search for currency symbol
769 // Quoting as in ImpSvNumberformatScan::Symbol_Division
774 nCPos
= sUpperStr
.indexOf( sCurString
, nCPos
);
778 sal_Int32 nQ
= SvNumberformat::GetQuoteEnd( sUpperStr
, nCPos
);
781 // dm can be escaped as "dm or \d
784 ((c
= sUpperStr
[nCPos
-1]) != '"'
787 return nCPos
; // found
796 nCPos
= nQ
+ 1; // continue after quote end
803 sal_Bool
SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString
& rString
,
804 const ::com::sun::star::lang::Locale
& rLocale
)
806 // returns sal_True if currency element was written
808 sal_Bool bRet
= sal_False
;
810 LanguageTag
aLanguageTag( rLocale
);
811 pFormatter
->ChangeIntl( aLanguageTag
.getLanguageType( false) );
812 OUString sCurString
, sDummy
;
813 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
815 pCharClass
->setLanguageTag( aLanguageTag
);
816 OUString sUpperStr
= pCharClass
->uppercase(rString
);
817 sal_Int32 nPos
= lcl_FindSymbol( sUpperStr
, sCurString
);
820 sal_Int32 nLength
= rString
.getLength();
821 sal_Int32 nCurLen
= sCurString
.getLength();
822 sal_Int32 nCont
= nPos
+ nCurLen
;
824 // text before currency symbol
827 AddToTextElement_Impl( rString
.copy( 0, nPos
) );
829 // currency symbol (empty string -> default)
831 WriteCurrencyElement_Impl( sEmpty
, sEmpty
);
834 // text after currency symbol
835 if ( nCont
< nLength
)
837 AddToTextElement_Impl( rString
.copy( nCont
, nLength
-nCont
) );
842 AddToTextElement_Impl( rString
); // simple text
845 return bRet
; // sal_True: currency element written
848 //-------------------------------------------------------------------------
850 static OUString
lcl_GetDefaultCalendar( SvNumberFormatter
* pFormatter
, LanguageType nLang
)
852 // get name of first non-gregorian calendar for the language
855 CalendarWrapper
* pCalendar
= pFormatter
->GetCalendar();
858 lang::Locale
aLocale( LanguageTag( nLang
).getLocale() );
860 uno::Sequence
<OUString
> aCals
= pCalendar
->getAllCalendars( aLocale
);
861 sal_Int32 nCnt
= aCals
.getLength();
862 sal_Bool bFound
= sal_False
;
863 for ( sal_Int32 j
=0; j
< nCnt
&& !bFound
; j
++ )
865 if ( aCals
[j
] != "gregorian" )
867 aCalendar
= aCals
[j
];
875 //-------------------------------------------------------------------------
877 static sal_Bool
lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
, sal_uInt16 nPos
)
879 sal_uInt16 nCount
= rEmbeddedEntries
.size();
880 for (sal_uInt16 i
=0; i
<nCount
; i
++)
881 if ( rEmbeddedEntries
[i
].nSourcePos
== nPos
)
884 return sal_False
; // not found
887 static sal_Bool
lcl_IsDefaultDateFormat( const SvNumberformat
& rFormat
, sal_Bool bSystemDate
, NfIndexTableOffset eBuiltIn
)
889 // make an extra loop to collect date elements, to check if it is a default format
890 // before adding the automatic-order attribute
892 SvXMLDateElementAttributes eDateDOW
= XML_DEA_NONE
;
893 SvXMLDateElementAttributes eDateDay
= XML_DEA_NONE
;
894 SvXMLDateElementAttributes eDateMonth
= XML_DEA_NONE
;
895 SvXMLDateElementAttributes eDateYear
= XML_DEA_NONE
;
896 SvXMLDateElementAttributes eDateHours
= XML_DEA_NONE
;
897 SvXMLDateElementAttributes eDateMins
= XML_DEA_NONE
;
898 SvXMLDateElementAttributes eDateSecs
= XML_DEA_NONE
;
899 sal_Bool bDateNoDefault
= sal_False
;
902 sal_Bool bEnd
= sal_False
;
906 short nElemType
= rFormat
.GetNumForType( 0, nPos
, sal_False
);
910 if ( nLastType
== NF_SYMBOLTYPE_STRING
)
911 bDateNoDefault
= sal_True
; // text at the end -> no default date format
912 bEnd
= sal_True
; // end of format reached
914 case NF_SYMBOLTYPE_STRING
:
915 case NF_SYMBOLTYPE_DATESEP
:
916 case NF_SYMBOLTYPE_TIMESEP
:
917 case NF_SYMBOLTYPE_TIME100SECSEP
:
918 // text is ignored, except at the end
920 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
921 case NF_KEY_NN
: eDateDOW
= XML_DEA_SHORT
; break;
923 case NF_KEY_NNNN
: eDateDOW
= XML_DEA_LONG
; break;
924 case NF_KEY_D
: eDateDay
= XML_DEA_SHORT
; break;
925 case NF_KEY_DD
: eDateDay
= XML_DEA_LONG
; break;
926 case NF_KEY_M
: eDateMonth
= XML_DEA_SHORT
; break;
927 case NF_KEY_MM
: eDateMonth
= XML_DEA_LONG
; break;
928 case NF_KEY_MMM
: eDateMonth
= XML_DEA_TEXTSHORT
; break;
929 case NF_KEY_MMMM
: eDateMonth
= XML_DEA_TEXTLONG
; break;
930 case NF_KEY_YY
: eDateYear
= XML_DEA_SHORT
; break;
931 case NF_KEY_YYYY
: eDateYear
= XML_DEA_LONG
; break;
932 case NF_KEY_H
: eDateHours
= XML_DEA_SHORT
; break;
933 case NF_KEY_HH
: eDateHours
= XML_DEA_LONG
; break;
934 case NF_KEY_MI
: eDateMins
= XML_DEA_SHORT
; break;
935 case NF_KEY_MMI
: eDateMins
= XML_DEA_LONG
; break;
936 case NF_KEY_S
: eDateSecs
= XML_DEA_SHORT
; break;
937 case NF_KEY_SS
: eDateSecs
= XML_DEA_LONG
; break;
939 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
941 bDateNoDefault
= sal_True
; // any other element -> no default format
943 nLastType
= nElemType
;
947 if ( bDateNoDefault
)
948 return sal_False
; // additional elements
951 NfIndexTableOffset eFound
= (NfIndexTableOffset
) SvXMLNumFmtDefaults::GetDefaultDateFormat(
952 eDateDOW
, eDateDay
, eDateMonth
, eDateYear
, eDateHours
, eDateMins
, eDateSecs
, bSystemDate
);
954 return ( eFound
== eBuiltIn
);
959 // export one part (condition)
962 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
,
963 sal_uInt16 nPart
, sal_Bool bDefPart
)
965 //! for the default part, pass the coditions from the other parts!
971 NfIndexTableOffset eBuiltIn
= pFormatter
->GetIndexTableOffset( nKey
);
974 bool bThousand
= false;
975 sal_uInt16 nPrecision
= 0;
976 sal_uInt16 nLeading
= 0;
977 rFormat
.GetNumForInfo( nPart
, nFmtType
, bThousand
, nPrecision
, nLeading
);
978 nFmtType
&= ~NUMBERFORMAT_DEFINED
;
980 // special treatment of builtin formats that aren't detected by normal parsing
981 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
982 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
983 nFmtType
= NUMBERFORMAT_NUMBER
;
984 else if ( eBuiltIn
== NF_BOOLEAN
)
985 nFmtType
= NUMBERFORMAT_LOGICAL
;
986 else if ( eBuiltIn
== NF_TEXT
)
987 nFmtType
= NUMBERFORMAT_TEXT
;
989 // #101606# An empty subformat is a valid number-style resulting in an
990 // empty display string for the condition of the subformat.
991 if ( nFmtType
== NUMBERFORMAT_UNDEFINED
&& rFormat
.GetNumForType( nPart
,
992 0, sal_False
) == 0 )
995 XMLTokenEnum eType
= XML_TOKEN_INVALID
;
998 // type is 0 if a format contains no recognized elements
999 // (like text only) - this is handled as a number-style.
1001 case NUMBERFORMAT_NUMBER
:
1002 case NUMBERFORMAT_SCIENTIFIC
:
1003 case NUMBERFORMAT_FRACTION
:
1004 eType
= XML_NUMBER_STYLE
;
1006 case NUMBERFORMAT_PERCENT
:
1007 eType
= XML_PERCENTAGE_STYLE
;
1009 case NUMBERFORMAT_CURRENCY
:
1010 eType
= XML_CURRENCY_STYLE
;
1012 case NUMBERFORMAT_DATE
:
1013 case NUMBERFORMAT_DATETIME
:
1014 eType
= XML_DATE_STYLE
;
1016 case NUMBERFORMAT_TIME
:
1017 eType
= XML_TIME_STYLE
;
1019 case NUMBERFORMAT_TEXT
:
1020 eType
= XML_TEXT_STYLE
;
1022 case NUMBERFORMAT_LOGICAL
:
1023 eType
= XML_BOOLEAN_STYLE
;
1026 DBG_ASSERT( eType
!= XML_TOKEN_INVALID
, "unknown format type" );
1028 OUString sAttrValue
;
1029 sal_Bool bUserDef
= ( ( rFormat
.GetType() & NUMBERFORMAT_DEFINED
) != 0 );
1032 // common attributes for format
1035 // format name (generated from key) - style namespace
1036 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
1037 lcl_CreateStyleName( nKey
, nPart
, bDefPart
, sPrefix
) );
1039 // "volatile" attribute for styles used only in maps
1041 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_VOLATILE
, XML_TRUE
);
1043 // language / country
1044 LanguageType nLang
= rFormat
.GetLanguage();
1045 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
1048 // titles for builtin formats are not written
1049 sAttrValue
= rFormat
.GetComment();
1050 if ( !sAttrValue
.isEmpty() && bUserDef
&& bDefPart
)
1052 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TITLE
, sAttrValue
);
1055 // automatic ordering for currency and date formats
1056 // only used for some built-in formats
1057 sal_Bool bAutoOrder
= ( eBuiltIn
== NF_CURRENCY_1000INT
|| eBuiltIn
== NF_CURRENCY_1000DEC2
||
1058 eBuiltIn
== NF_CURRENCY_1000INT_RED
|| eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1059 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
||
1060 eBuiltIn
== NF_DATE_SYSTEM_SHORT
|| eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1061 eBuiltIn
== NF_DATE_SYS_MMYY
|| eBuiltIn
== NF_DATE_SYS_DDMMM
||
1062 eBuiltIn
== NF_DATE_SYS_DDMMYYYY
|| eBuiltIn
== NF_DATE_SYS_DDMMYY
||
1063 eBuiltIn
== NF_DATE_SYS_DMMMYY
|| eBuiltIn
== NF_DATE_SYS_DMMMYYYY
||
1064 eBuiltIn
== NF_DATE_SYS_DMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNDMMMYY
||
1065 eBuiltIn
== NF_DATE_SYS_NNDMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNNNDMMMMYYYY
||
1066 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
|| eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
1068 // format source (for date and time formats)
1069 // only used for some built-in formats
1070 sal_Bool bSystemDate
= ( eBuiltIn
== NF_DATE_SYSTEM_SHORT
||
1071 eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1072 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
);
1073 sal_Bool bLongSysDate
= ( eBuiltIn
== NF_DATE_SYSTEM_LONG
);
1075 // check if the format definition matches the key
1076 if ( bAutoOrder
&& ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) &&
1077 !lcl_IsDefaultDateFormat( rFormat
, bSystemDate
, eBuiltIn
) )
1079 bAutoOrder
= bSystemDate
= bLongSysDate
= sal_False
; // don't write automatic-order attribute then
1083 ( nFmtType
== NUMBERFORMAT_CURRENCY
|| nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) )
1085 // #85109# format type must be checked to avoid dtd errors if
1086 // locale data contains other format types at the built-in positions
1088 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_AUTOMATIC_ORDER
,
1092 if ( bSystemDate
&& bAutoOrder
&&
1093 ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) )
1095 // #85109# format type must be checked to avoid dtd errors if
1096 // locale data contains other format types at the built-in positions
1098 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_FORMAT_SOURCE
,
1102 // overflow for time formats as in [hh]:mm
1103 // controlled by bThousand from number format info
1104 // default for truncate-on-overflow is true
1105 if ( nFmtType
== NUMBERFORMAT_TIME
&& bThousand
)
1107 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRUNCATE_ON_OVERFLOW
,
1112 // Native number transliteration
1114 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr
;
1115 rFormat
.GetNatNumXml( aAttr
, nPart
);
1116 if ( !aAttr
.Format
.isEmpty() )
1118 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_FORMAT
,
1120 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1121 aAttr
.Locale
.Language
);
1122 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1123 aAttr
.Locale
.Country
);
1124 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_STYLE
,
1131 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, eType
,
1132 sal_True
, sal_True
);
1135 // color (properties element)
1138 const Color
* pCol
= rFormat
.GetColor( nPart
);
1140 WriteColorElement_Impl(*pCol
);
1143 // detect if there is "real" content, excluding color and maps
1144 //! move to implementation of Write... methods?
1145 sal_Bool bAnyContent
= sal_False
;
1151 SvXMLEmbeddedTextEntryArr aEmbeddedEntries
;
1152 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1154 // default number format contains just one number element
1155 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1156 bAnyContent
= sal_True
;
1158 else if ( eBuiltIn
== NF_BOOLEAN
)
1160 // boolean format contains just one boolean element
1161 WriteBooleanElement_Impl();
1162 bAnyContent
= sal_True
;
1166 // first loop to collect attributes
1168 sal_Bool bDecDashes
= sal_False
;
1169 sal_Bool bVarDecimals
= sal_False
;
1170 sal_Bool bExpFound
= sal_False
;
1171 sal_Bool bCurrFound
= sal_False
;
1172 sal_Bool bInInteger
= sal_True
;
1173 sal_Int32 nExpDigits
= 0;
1174 sal_Int32 nIntegerSymbols
= 0; // for embedded-text, including "#"
1175 sal_Int32 nTrailingThousands
= 0; // thousands-separators after all digits
1178 sal_uInt16 nPos
= 0;
1179 sal_Bool bEnd
= sal_False
;
1182 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1183 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1185 switch ( nElemType
)
1188 bEnd
= sal_True
; // end of format reached
1190 case NF_SYMBOLTYPE_DIGIT
:
1191 if ( bExpFound
&& pElemStr
)
1192 nExpDigits
+= pElemStr
->getLength();
1193 else if ( !bDecDashes
&& pElemStr
&& (*pElemStr
)[0] == '-' )
1194 bDecDashes
= sal_True
;
1195 else if ( !bVarDecimals
&& !bInInteger
&& pElemStr
&& (*pElemStr
)[0] == '#' )
1197 // If the decimal digits string starts with a '#', variable
1198 // decimals is assumed (for 0.###, but not 0.0##).
1199 bVarDecimals
= sal_True
;
1201 if ( bInInteger
&& pElemStr
)
1202 nIntegerSymbols
+= pElemStr
->getLength();
1203 nTrailingThousands
= 0;
1205 case NF_SYMBOLTYPE_DECSEP
:
1206 bInInteger
= sal_False
;
1208 case NF_SYMBOLTYPE_THSEP
:
1210 nTrailingThousands
+= pElemStr
->getLength(); // is reset to 0 if digits follow
1212 case NF_SYMBOLTYPE_EXP
:
1213 bExpFound
= sal_True
; // following digits are exponent digits
1214 bInInteger
= sal_False
;
1216 case NF_SYMBOLTYPE_CURRENCY
:
1217 bCurrFound
= sal_True
;
1219 case NF_SYMBOLTYPE_CURREXT
:
1221 sCurrExt
= *pElemStr
;
1224 // E, EE, R, RR: select non-gregorian calendar
1225 // AAA, AAAA: calendar is switched at the position of the element
1230 if (aCalendar
.isEmpty())
1231 aCalendar
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1237 // collect strings for embedded-text (must be known before number element is written)
1239 sal_Bool bAllowEmbedded
= ( nFmtType
== 0 || nFmtType
== NUMBERFORMAT_NUMBER
||
1240 nFmtType
== NUMBERFORMAT_CURRENCY
||
1241 nFmtType
== NUMBERFORMAT_PERCENT
);
1242 if ( bAllowEmbedded
)
1244 sal_Int32 nDigitsPassed
= 0;
1249 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1250 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1252 switch ( nElemType
)
1255 bEnd
= sal_True
; // end of format reached
1257 case NF_SYMBOLTYPE_DIGIT
:
1259 nDigitsPassed
+= pElemStr
->getLength();
1261 case NF_SYMBOLTYPE_STRING
:
1262 case NF_SYMBOLTYPE_BLANK
:
1263 case NF_SYMBOLTYPE_PERCENT
:
1264 if ( nDigitsPassed
> 0 && nDigitsPassed
< nIntegerSymbols
&& pElemStr
)
1266 // text (literal or underscore) within the integer part of a number:number element
1268 OUString aEmbeddedStr
;
1269 if ( nElemType
== NF_SYMBOLTYPE_STRING
|| nElemType
== NF_SYMBOLTYPE_PERCENT
)
1271 aEmbeddedStr
= *pElemStr
;
1275 SvNumberformat::InsertBlanks( aEmbeddedStr
, 0, (*pElemStr
)[1] );
1277 sal_Int32 nEmbedPos
= nIntegerSymbols
- nDigitsPassed
;
1279 SvXMLEmbeddedTextEntry
* pObj
= new SvXMLEmbeddedTextEntry( nPos
, nEmbedPos
, aEmbeddedStr
);
1280 aEmbeddedEntries
.push_back( pObj
);
1288 // final loop to write elements
1290 sal_Bool bNumWritten
= sal_False
;
1291 sal_Bool bCurrencyWritten
= sal_False
;
1292 short nPrevType
= 0;
1297 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1298 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1300 switch ( nElemType
)
1303 bEnd
= sal_True
; // end of format reached
1305 case NF_SYMBOLTYPE_STRING
:
1306 case NF_SYMBOLTYPE_DATESEP
:
1307 case NF_SYMBOLTYPE_TIMESEP
:
1308 case NF_SYMBOLTYPE_TIME100SECSEP
:
1309 case NF_SYMBOLTYPE_PERCENT
:
1312 if ( ( nPrevType
== NF_KEY_S
|| nPrevType
== NF_KEY_SS
) &&
1313 ( nElemType
== NF_SYMBOLTYPE_TIME100SECSEP
) &&
1316 // decimal separator after seconds is implied by
1317 // "decimal-places" attribute and must not be written
1319 //! difference between '.' and ',' is lost here
1321 else if ( lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1323 // text is written as embedded-text child of the number,
1324 // don't create a text element
1326 else if ( nFmtType
== NUMBERFORMAT_CURRENCY
&& !bCurrFound
&& !bCurrencyWritten
)
1328 // automatic currency symbol is implemented as part of
1329 // normal text -> search for the symbol
1330 bCurrencyWritten
= WriteTextWithCurrency_Impl( *pElemStr
,
1331 LanguageTag( nLang
).getLocale() );
1332 bAnyContent
= sal_True
;
1335 AddToTextElement_Impl( *pElemStr
);
1338 case NF_SYMBOLTYPE_BLANK
:
1339 if ( pElemStr
&& !lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1341 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1342 // (#i20396# the spaces may also be in embedded-text elements)
1345 SvNumberformat::InsertBlanks( aBlanks
, 0, (*pElemStr
)[1] );
1346 AddToTextElement_Impl( aBlanks
);
1349 case NF_KEY_GENERAL
:
1350 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1355 if ( bCurrencyWritten
)
1356 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1359 //! must be different from short automatic format
1360 //! but should still be empty (meaning automatic)
1361 // pElemStr is "CCC"
1363 WriteCurrencyElement_Impl( *pElemStr
, OUString() );
1364 bAnyContent
= sal_True
;
1365 bCurrencyWritten
= sal_True
;
1369 case NF_SYMBOLTYPE_CURRENCY
:
1372 if ( bCurrencyWritten
)
1373 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1376 WriteCurrencyElement_Impl( *pElemStr
, sCurrExt
);
1377 bAnyContent
= sal_True
;
1378 bCurrencyWritten
= sal_True
;
1382 case NF_SYMBOLTYPE_DIGIT
:
1383 if (!bNumWritten
) // write number part
1387 // for type 0 (not recognized as a special type),
1388 // write a "normal" number
1390 case NUMBERFORMAT_NUMBER
:
1391 case NUMBERFORMAT_CURRENCY
:
1392 case NUMBERFORMAT_PERCENT
:
1395 // only some built-in formats have automatic decimals
1396 sal_Int32 nDecimals
= nPrecision
; // from GetFormatSpecialInfo
1397 if ( eBuiltIn
== NF_NUMBER_STANDARD
||
1398 eBuiltIn
== NF_CURRENCY_1000DEC2
||
1399 eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1400 eBuiltIn
== NF_CURRENCY_1000DEC2_CCC
||
1401 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
)
1405 // only one built-in format has automatic integer digits
1406 sal_Int32 nInteger
= nLeading
;
1407 if ( eBuiltIn
== NF_NUMBER_SYSTEM
)
1410 // string for decimal replacement
1411 // has to be taken from nPrecision
1412 // (positive number even for automatic decimals)
1413 OUStringBuffer sDashStr
;
1414 if (bDecDashes
&& nPrecision
> 0)
1415 comphelper::string::padToLength(sDashStr
, nPrecision
, '-');
1417 WriteNumberElement_Impl(nDecimals
, nInteger
, sDashStr
.makeStringAndClear(),
1418 bVarDecimals
, bThousand
, nTrailingThousands
, aEmbeddedEntries
);
1419 bAnyContent
= sal_True
;
1422 case NUMBERFORMAT_SCIENTIFIC
:
1423 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1424 // as integer digits: use nIntegerSymbols instead of nLeading
1425 // (use of '#' to select multiples in exponent might be added later)
1426 WriteScientificElement_Impl( nPrecision
, nIntegerSymbols
, bThousand
, nExpDigits
);
1427 bAnyContent
= sal_True
;
1429 case NUMBERFORMAT_FRACTION
:
1431 sal_Int32 nInteger
= nLeading
;
1432 if ( pElemStr
&& (*pElemStr
)[0] == '?' )
1434 // If the first digit character is a question mark,
1435 // the fraction doesn't have an integer part, and no
1436 // min-integer-digits attribute must be written.
1439 sal_Int32 nDenominator
= rFormat
.GetForcedDenominatorForType( nPart
);
1440 WriteFractionElement_Impl( nInteger
, bThousand
, nPrecision
, nPrecision
, nDenominator
);
1441 bAnyContent
= sal_True
;
1446 bNumWritten
= sal_True
;
1449 case NF_SYMBOLTYPE_DECSEP
:
1450 if ( pElemStr
&& nPrecision
== 0 )
1452 // A decimal separator after the number, without following decimal digits,
1453 // isn't modelled as part of the number element, so it's written as text
1454 // (the distinction between a quoted and non-quoted, locale-dependent
1455 // character is lost here).
1457 AddToTextElement_Impl( *pElemStr
);
1460 case NF_SYMBOLTYPE_DEL
:
1461 if ( pElemStr
&& comphelper::string::equals(*pElemStr
, '@') )
1463 WriteTextContentElement_Impl();
1464 bAnyContent
= sal_True
;
1468 case NF_SYMBOLTYPE_CALENDAR
:
1470 aCalendar
= *pElemStr
;
1478 sal_Bool bLong
= ( nElemType
== NF_KEY_DD
);
1479 WriteDayElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1480 bAnyContent
= sal_True
;
1491 OUString aCalAttr
= aCalendar
;
1492 if ( nElemType
== NF_KEY_AAA
|| nElemType
== NF_KEY_AAAA
)
1494 // calendar attribute for AAA and AAAA is switched only for this element
1495 if (aCalAttr
.isEmpty())
1496 aCalAttr
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1499 sal_Bool bLong
= ( nElemType
== NF_KEY_NNN
|| nElemType
== NF_KEY_NNNN
||
1500 nElemType
== NF_KEY_DDDD
|| nElemType
== NF_KEY_AAAA
);
1501 WriteDayOfWeekElement_Impl( aCalAttr
, ( bSystemDate
? bLongSysDate
: bLong
) );
1502 bAnyContent
= sal_True
;
1503 if ( nElemType
== NF_KEY_NNNN
)
1505 // write additional text element for separator
1506 pLocaleData
->setLanguageTag( LanguageTag( nLang
) );
1507 AddToTextElement_Impl( pLocaleData
->getLongDateDayOfWeekSep() );
1515 case NF_KEY_MMMMM
: //! first letter of month name, no attribute available
1517 sal_Bool bLong
= ( nElemType
== NF_KEY_MM
|| nElemType
== NF_KEY_MMMM
);
1518 sal_Bool bText
= ( nElemType
== NF_KEY_MMM
|| nElemType
== NF_KEY_MMMM
||
1519 nElemType
== NF_KEY_MMMMM
);
1520 WriteMonthElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
), bText
);
1521 bAnyContent
= sal_True
;
1528 case NF_KEY_R
: //! R acts as EE, no attribute available
1530 //! distinguish EE and R
1531 // calendar attribute for E and EE and R is set in first loop
1532 sal_Bool bLong
= ( nElemType
== NF_KEY_YYYY
|| nElemType
== NF_KEY_EEC
||
1533 nElemType
== NF_KEY_R
);
1534 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1535 bAnyContent
= sal_True
;
1541 case NF_KEY_RR
: //! RR acts as GGGEE, no attribute available
1543 //! distinguish GG and GGG and RR
1544 sal_Bool bLong
= ( nElemType
== NF_KEY_GGG
|| nElemType
== NF_KEY_RR
);
1545 WriteEraElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1546 bAnyContent
= sal_True
;
1547 if ( nElemType
== NF_KEY_RR
)
1549 // calendar attribute for RR is set in first loop
1550 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: sal_True
) );
1557 sal_Bool bLong
= ( nElemType
== NF_KEY_QQ
);
1558 WriteQuarterElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1559 bAnyContent
= sal_True
;
1563 WriteWeekElement_Impl( aCalendar
);
1564 bAnyContent
= sal_True
;
1567 // time elements (bSystemDate is not used):
1571 WriteHoursElement_Impl( nElemType
== NF_KEY_HH
);
1572 bAnyContent
= sal_True
;
1576 WriteMinutesElement_Impl( nElemType
== NF_KEY_MMI
);
1577 bAnyContent
= sal_True
;
1581 WriteSecondsElement_Impl( ( nElemType
== NF_KEY_SS
), nPrecision
);
1582 bAnyContent
= sal_True
;
1586 WriteAMPMElement_Impl(); // short/long?
1587 bAnyContent
= sal_True
;
1589 case NF_SYMBOLTYPE_STAR
:
1590 // export only if ODF 1.2 extensions are enabled
1591 if( SvtSaveOptions().GetODFDefaultVersion() > SvtSaveOptions::ODFVER_012
)
1593 if ( pElemStr
&& pElemStr
->getLength() > 1 )
1594 WriteRepeatedElement_Impl( (*pElemStr
)[1] );
1598 nPrevType
= nElemType
;
1603 if ( sTextContent
.getLength() )
1604 bAnyContent
= sal_True
; // element written in FinishTextElement_Impl
1606 FinishTextElement_Impl(); // final text element - before maps
1610 // for an empty format, write an empty text element
1611 SvXMLElementExport
aTElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
1612 sal_True
, sal_False
);
1616 // mapping (conditions) must be last elements
1621 SvNumberformatLimitOps eOp1
, eOp2
;
1622 double fLimit1
, fLimit2
;
1623 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1625 WriteMapElement_Impl( eOp1
, fLimit1
, nKey
, 0 );
1626 WriteMapElement_Impl( eOp2
, fLimit2
, nKey
, 1 );
1628 if ( rFormat
.HasTextFormat() )
1630 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1631 // by reversing the 2nd condition
1633 SvNumberformatLimitOps eOp3
= NUMBERFORMAT_OP_NO
;
1634 double fLimit3
= fLimit2
;
1637 case NUMBERFORMAT_OP_EQ
: eOp3
= NUMBERFORMAT_OP_NE
; break;
1638 case NUMBERFORMAT_OP_NE
: eOp3
= NUMBERFORMAT_OP_EQ
; break;
1639 case NUMBERFORMAT_OP_LT
: eOp3
= NUMBERFORMAT_OP_GE
; break;
1640 case NUMBERFORMAT_OP_LE
: eOp3
= NUMBERFORMAT_OP_GT
; break;
1641 case NUMBERFORMAT_OP_GT
: eOp3
= NUMBERFORMAT_OP_LE
; break;
1642 case NUMBERFORMAT_OP_GE
: eOp3
= NUMBERFORMAT_OP_LT
; break;
1647 if ( fLimit1
== fLimit2
&&
1648 ( ( eOp1
== NUMBERFORMAT_OP_LT
&& eOp2
== NUMBERFORMAT_OP_GT
) ||
1649 ( eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_LT
) ) )
1651 // For <x and >x, add =x as last condition
1652 // (just for readability, <=x would be valid, too)
1654 eOp3
= NUMBERFORMAT_OP_EQ
;
1657 WriteMapElement_Impl( eOp3
, fLimit3
, nKey
, 2 );
1662 //-------------------------------------------------------------------------
1665 // export one format
1668 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
)
1670 sal_uInt16 nUsedParts
= 0;
1672 for (nPart
=0; nPart
<XMLNUM_MAX_PARTS
; nPart
++)
1673 if (rFormat
.GetNumForType( nPart
, 0, sal_False
) != 0)
1674 nUsedParts
= nPart
+1;
1676 SvNumberformatLimitOps eOp1
, eOp2
;
1677 double fLimit1
, fLimit2
;
1678 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1680 // if conditions are set, even empty formats must be written
1682 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 2 )
1684 if ( eOp2
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 3 )
1686 if ( rFormat
.HasTextFormat() && nUsedParts
< 4 )
1689 for (nPart
=0; nPart
<nUsedParts
; nPart
++)
1691 sal_Bool bDefault
= ( nPart
+1 == nUsedParts
); // last = default
1692 ExportPart_Impl( rFormat
, nKey
, nPart
, bDefault
);
1696 //-------------------------------------------------------------------------
1699 // export method called by application
1702 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle
)
1705 return; // no formatter -> no entries
1708 const SvNumberformat
* pFormat
= NULL
;
1709 sal_Bool
bNext(pUsedList
->GetFirstUsed(nKey
));
1712 pFormat
= pFormatter
->GetEntry(nKey
);
1714 ExportFormat_Impl( *pFormat
, nKey
);
1715 bNext
= pUsedList
->GetNextUsed(nKey
);
1719 std::vector
<sal_uInt16
> aLanguages
;
1720 pFormatter
->GetUsedLanguages( aLanguages
);
1721 for (std::vector
<sal_uInt16
>::const_iterator
it(aLanguages
.begin()); it
!= aLanguages
.end(); ++it
)
1723 LanguageType nLang
= *it
;
1725 sal_uInt32 nDefaultIndex
= 0;
1726 SvNumberFormatTable
& rTable
= pFormatter
->GetEntryTable(
1727 NUMBERFORMAT_DEFINED
, nDefaultIndex
, nLang
);
1728 SvNumberFormatTable::iterator it2
= rTable
.begin();
1729 while (it2
!= rTable
.end())
1732 pFormat
= it2
->second
;
1733 if (!pUsedList
->IsUsed(nKey
))
1735 DBG_ASSERT((pFormat
->GetType() & NUMBERFORMAT_DEFINED
) != 0, "a not user defined numberformat found");
1736 // user-defined and used formats are exported
1737 ExportFormat_Impl( *pFormat
, nKey
);
1738 // if it is a user-defined Format it will be added else nothing will happen
1739 pUsedList
->SetUsed(nKey
);
1746 pUsedList
->Export();
1749 OUString
SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey
)
1751 if(pUsedList
->IsUsed(nKey
) || pUsedList
->IsWasUsed(nKey
))
1752 return lcl_CreateStyleName( nKey
, 0, sal_True
, sPrefix
);
1755 OSL_FAIL("There is no written Data-Style");
1760 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey
)
1762 DBG_ASSERT( pFormatter
!= NULL
, "missing formatter" );
1766 if (pFormatter
->GetEntry(nKey
))
1767 pUsedList
->SetUsed( nKey
);
1769 OSL_FAIL("no existing Numberformat found with this key");
1773 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
1776 pUsedList
->GetWasUsed(rWasUsed
);
1779 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
1782 pUsedList
->SetWasUsed(rWasUsed
);
1787 static const SvNumberformat
* lcl_GetFormat( SvNumberFormatter
* pFormatter
,
1790 return ( pFormatter
!= NULL
) ? pFormatter
->GetEntry( nKey
) : NULL
;
1793 sal_uInt32
SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey
)
1795 sal_uInt32 nRet
= nKey
;
1797 const SvNumberformat
* pFormat
= lcl_GetFormat( pFormatter
, nKey
);
1798 if( pFormat
!= NULL
)
1800 DBG_ASSERT( pFormatter
!= NULL
, "format without formatter?" );
1802 sal_Int32 nErrorPos
;
1803 short nType
= pFormat
->GetType();
1805 sal_uInt32 nNewKey
= pFormatter
->GetFormatForLanguageIfBuiltIn(
1806 nKey
, LANGUAGE_SYSTEM
);
1808 if( nNewKey
!= nKey
)
1814 OUString
aFormatString( pFormat
->GetFormatstring() );
1815 pFormatter
->PutandConvertEntry(
1817 nErrorPos
, nType
, nNewKey
,
1818 pFormat
->GetLanguage(), LANGUAGE_SYSTEM
);
1820 // success? Then use new key.
1821 if( nErrorPos
== 0 )
1829 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */