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>
44 #include <svl/nfsymbol.hxx>
45 #include <xmloff/xmltoken.hxx>
46 #include <xmloff/xmlexp.hxx>
49 #include <boost/ptr_container/ptr_vector.hpp>
51 using namespace ::com::sun::star
;
52 using namespace ::xmloff::token
;
53 using namespace ::svt
;
55 #define XMLNUM_MAX_PARTS 3
59 bool operator() (const sal_uInt32 rValue1
, const sal_uInt32 rValue2
) const
61 return rValue1
< rValue2
;
65 typedef std::set
< sal_uInt32
, LessuInt32
> SvXMLuInt32Set
;
67 class SvXMLEmbeddedTextEntryArr
69 typedef boost::ptr_vector
<SvXMLEmbeddedTextEntry
> DataType
;
74 void push_back( SvXMLEmbeddedTextEntry
* p
)
79 const SvXMLEmbeddedTextEntry
& operator[] ( size_t i
) const
90 class SvXMLNumUsedList_Impl
93 SvXMLuInt32Set aWasUsed
;
94 SvXMLuInt32Set::iterator aCurrentUsedPos
;
95 sal_uInt32 nUsedCount
;
96 sal_uInt32 nWasUsedCount
;
99 SvXMLNumUsedList_Impl();
100 ~SvXMLNumUsedList_Impl();
102 void SetUsed( sal_uInt32 nKey
);
103 bool IsUsed( sal_uInt32 nKey
) const;
104 bool IsWasUsed( sal_uInt32 nKey
) const;
107 bool GetFirstUsed(sal_uInt32
& nKey
);
108 bool GetNextUsed(sal_uInt32
& nKey
);
110 void GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
);
111 void SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
);
114 struct SvXMLEmbeddedTextEntry
116 sal_uInt16 nSourcePos
; // position in NumberFormat (to skip later)
117 sal_Int32 nFormatPos
; // resulting position in embedded-text element
120 SvXMLEmbeddedTextEntry( sal_uInt16 nSP
, sal_Int32 nFP
, const OUString
& rT
) :
121 nSourcePos(nSP
), nFormatPos(nFP
), aText(rT
) {}
124 //! SvXMLNumUsedList_Impl should be optimized!
126 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
132 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
136 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey
)
138 if ( !IsWasUsed(nKey
) )
140 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aUsed
.insert( nKey
);
146 bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey
) const
148 SvXMLuInt32Set::const_iterator aItr
= aUsed
.find(nKey
);
149 return (aItr
!= aUsed
.end());
152 bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey
) const
154 SvXMLuInt32Set::const_iterator aItr
= aWasUsed
.find(nKey
);
155 return (aItr
!= aWasUsed
.end());
158 void SvXMLNumUsedList_Impl::Export()
160 SvXMLuInt32Set::const_iterator aItr
= aUsed
.begin();
161 while (aItr
!= aUsed
.end())
163 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( *aItr
);
172 bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32
& nKey
)
175 aCurrentUsedPos
= aUsed
.begin();
178 DBG_ASSERT(aCurrentUsedPos
!= aUsed
.end(), "something went wrong");
179 nKey
= *aCurrentUsedPos
;
185 bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32
& nKey
)
188 if (aCurrentUsedPos
!= aUsed
.end())
191 if (aCurrentUsedPos
!= aUsed
.end())
193 nKey
= *aCurrentUsedPos
;
200 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
202 rWasUsed
.realloc(nWasUsedCount
);
203 sal_Int32
* pWasUsed
= rWasUsed
.getArray();
206 SvXMLuInt32Set::const_iterator aItr
= aWasUsed
.begin();
207 while (aItr
!= aWasUsed
.end())
216 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
218 DBG_ASSERT(nWasUsedCount
== 0, "WasUsed should be empty");
219 sal_Int32
nCount(rWasUsed
.getLength());
220 const sal_Int32
* pWasUsed
= rWasUsed
.getConstArray();
221 for (sal_uInt16 i
= 0; i
< nCount
; i
++, pWasUsed
++)
223 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( *pWasUsed
);
229 SvXMLNumFmtExport::SvXMLNumFmtExport(
231 const uno::Reference
< util::XNumberFormatsSupplier
>& rSupp
) :
233 sPrefix( OUString("N") ),
238 // supplier must be SvNumberFormatsSupplierObj
239 SvNumberFormatsSupplierObj
* pObj
=
240 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
242 pFormatter
= pObj
->GetNumberFormatter();
246 pCharClass
= new CharClass( pFormatter
->GetComponentContext(),
247 pFormatter
->GetLanguageTag() );
248 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetComponentContext(),
249 pFormatter
->GetLanguageTag() );
253 LanguageTag
aLanguageTag( MsLangId::getSystemLanguage() );
255 pCharClass
= new CharClass( rExport
.getComponentContext(), aLanguageTag
);
256 pLocaleData
= new LocaleDataWrapper( rExport
.getComponentContext(), aLanguageTag
);
259 pUsedList
= new SvXMLNumUsedList_Impl
;
262 SvXMLNumFmtExport::SvXMLNumFmtExport(
264 const ::com::sun::star::uno::Reference
<
265 ::com::sun::star::util::XNumberFormatsSupplier
>& rSupp
,
266 const OUString
& rPrefix
) :
273 // supplier must be SvNumberFormatsSupplierObj
274 SvNumberFormatsSupplierObj
* pObj
=
275 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
277 pFormatter
= pObj
->GetNumberFormatter();
281 pCharClass
= new CharClass( pFormatter
->GetComponentContext(),
282 pFormatter
->GetLanguageTag() );
283 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetComponentContext(),
284 pFormatter
->GetLanguageTag() );
288 LanguageTag
aLanguageTag( MsLangId::getSystemLanguage() );
290 pCharClass
= new CharClass( rExport
.getComponentContext(), aLanguageTag
);
291 pLocaleData
= new LocaleDataWrapper( rExport
.getComponentContext(), aLanguageTag
);
294 pUsedList
= new SvXMLNumUsedList_Impl
;
297 SvXMLNumFmtExport::~SvXMLNumFmtExport()
306 static OUString
lcl_CreateStyleName( sal_Int32 nKey
, sal_Int32 nPart
, bool bDefPart
, const OUString
& rPrefix
)
308 OUStringBuffer
aFmtName(10);
309 aFmtName
.append( rPrefix
);
310 aFmtName
.append( nKey
);
313 aFmtName
.append( 'P' );
314 aFmtName
.append( nPart
);
316 return aFmtName
.makeStringAndClear();
319 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString
& rCalendar
)
321 if ( !rCalendar
.isEmpty() )
323 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_CALENDAR
, rCalendar
);
327 void SvXMLNumFmtExport::AddTextualAttr_Impl( bool bText
)
329 if ( bText
) // non-textual
331 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TEXTUAL
, XML_TRUE
);
335 void SvXMLNumFmtExport::AddStyleAttr_Impl( bool bLong
)
337 if ( bLong
) // short is default
339 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_STYLE
, XML_LONG
);
343 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang
)
345 if ( nLang
!= LANGUAGE_SYSTEM
)
347 rExport
.AddLanguageTagAttributes( XML_NAMESPACE_NUMBER
, XML_NAMESPACE_NUMBER
,
348 LanguageTag( (LanguageType
)nLang
), false);
352 // methods to write individual elements within a format
354 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString
& rString
)
356 // append to sTextContent, write element in FinishTextElement_Impl
357 // to avoid several text elements following each other
359 sTextContent
.append( rString
);
362 void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS
)
364 if ( !sTextContent
.isEmpty() )
366 sal_uInt16 nNS
= bUseExtensionNS
? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
;
367 SvXMLElementExport
aElem( rExport
, nNS
, XML_TEXT
,
369 rExport
.Characters( sTextContent
.makeStringAndClear() );
373 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color
& rColor
)
375 FinishTextElement_Impl();
377 OUStringBuffer
aColStr( 7 );
378 ::sax::Converter::convertColor( aColStr
, rColor
.GetColor() );
379 rExport
.AddAttribute( XML_NAMESPACE_FO
, XML_COLOR
,
380 aColStr
.makeStringAndClear() );
382 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_TEXT_PROPERTIES
,
386 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString
& rString
,
387 const OUString
& rExt
)
389 FinishTextElement_Impl();
391 if ( !rExt
.isEmpty() )
393 // rExt should be a 16-bit hex value max FFFF which may contain a
394 // leading "-" separator (that is not a minus sign, but toInt32 can be
395 // used to parse it, with post-processing as necessary):
396 sal_Int32 nLang
= rExt
.toInt32(16);
399 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
402 SvXMLElementExport
aElem( rExport
,
403 XML_NAMESPACE_NUMBER
, XML_CURRENCY_SYMBOL
,
405 rExport
.Characters( rString
);
408 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
410 FinishTextElement_Impl();
412 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_BOOLEAN
,
416 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
418 FinishTextElement_Impl();
420 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT_CONTENT
,
426 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString
& rCalendar
, bool bLong
)
428 FinishTextElement_Impl();
430 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
431 AddStyleAttr_Impl( bLong
); // adds to pAttrList
433 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY
,
437 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString
& rCalendar
, bool bLong
, bool bText
)
439 FinishTextElement_Impl();
441 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
442 AddStyleAttr_Impl( bLong
); // adds to pAttrList
443 AddTextualAttr_Impl( bText
); // adds to pAttrList
445 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MONTH
,
449 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString
& rCalendar
, bool bLong
)
451 FinishTextElement_Impl();
453 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
454 AddStyleAttr_Impl( bLong
); // adds to pAttrList
456 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_YEAR
,
460 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString
& rCalendar
, bool bLong
)
462 FinishTextElement_Impl();
464 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
465 AddStyleAttr_Impl( bLong
); // adds to pAttrList
467 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_ERA
,
471 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString
& rCalendar
, bool bLong
)
473 FinishTextElement_Impl();
475 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
476 AddStyleAttr_Impl( bLong
); // adds to pAttrList
478 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY_OF_WEEK
,
482 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString
& rCalendar
)
484 FinishTextElement_Impl();
486 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
488 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_WEEK_OF_YEAR
,
492 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString
& rCalendar
, bool bLong
)
494 FinishTextElement_Impl();
496 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
497 AddStyleAttr_Impl( bLong
); // adds to pAttrList
499 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_QUARTER
,
505 void SvXMLNumFmtExport::WriteHoursElement_Impl( bool bLong
)
507 FinishTextElement_Impl();
509 AddStyleAttr_Impl( bLong
); // adds to pAttrList
511 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_HOURS
,
515 void SvXMLNumFmtExport::WriteMinutesElement_Impl( bool bLong
)
517 FinishTextElement_Impl();
519 AddStyleAttr_Impl( bLong
); // adds to pAttrList
521 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MINUTES
,
525 void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar
)
527 FinishTextElement_Impl(true);
528 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_LO_EXT
, XML_FILL_CHARACTER
,
530 rExport
.Characters( OUString( nChar
) );
533 void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong
, sal_uInt16 nDecimals
)
535 FinishTextElement_Impl();
537 AddStyleAttr_Impl( bLong
); // adds to pAttrList
540 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
541 OUString::number( nDecimals
) );
544 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_SECONDS
,
548 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
550 FinishTextElement_Impl();
552 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_AM_PM
,
558 void SvXMLNumFmtExport::WriteNumberElement_Impl(
559 sal_Int32 nDecimals
, sal_Int32 nMinDecimals
,
560 sal_Int32 nInteger
, const OUString
& rDashStr
,
561 bool bGrouping
, sal_Int32 nTrailingThousands
,
562 const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
)
564 FinishTextElement_Impl();
567 if ( nDecimals
>= 0 ) // negative = automatic
569 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
570 OUString::number( nDecimals
) );
573 if ( nMinDecimals
>= 0 ) // negative = automatic
575 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_MIN_DECIMAL_PLACES
,
576 OUString::number( nMinDecimals
) );
580 if ( nInteger
>= 0 ) // negative = automatic
582 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
583 OUString::number( nInteger
) );
586 // decimal replacement (dashes) or variable decimals (#)
587 if ( !rDashStr
.isEmpty() || nMinDecimals
< nDecimals
)
589 // full variable decimals means an empty replacement string
590 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_REPLACEMENT
,
594 // (automatic) grouping separator
597 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
600 // display-factor if there are trailing thousands separators
601 if ( nTrailingThousands
)
603 // each separator character removes three digits
604 double fFactor
= ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands
);
606 OUStringBuffer aFactStr
;
607 ::sax::Converter::convertDouble( aFactStr
, fFactor
);
608 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DISPLAY_FACTOR
, aFactStr
.makeStringAndClear() );
611 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_NUMBER
,
614 // number:embedded-text as child elements
616 sal_uInt16 nEntryCount
= rEmbeddedEntries
.size();
617 for (sal_uInt16 nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
619 const SvXMLEmbeddedTextEntry
* pObj
= &rEmbeddedEntries
[nEntry
];
621 // position attribute
622 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_POSITION
,
623 OUString::number( pObj
->nFormatPos
) );
624 SvXMLElementExport
aChildElem( rExport
, XML_NAMESPACE_NUMBER
, XML_EMBEDDED_TEXT
,
627 // text as element content
628 OUString
aContent( pObj
->aText
);
629 while ( nEntry
+1 < nEntryCount
&& rEmbeddedEntries
[nEntry
+1].nFormatPos
== pObj
->nFormatPos
)
631 // The array can contain several elements for the same position in the number
632 // (for example, literal text and space from underscores). They must be merged
633 // into a single embedded-text element.
634 aContent
+= rEmbeddedEntries
[nEntry
+1].aText
;
637 rExport
.Characters( aContent
);
641 void SvXMLNumFmtExport::WriteScientificElement_Impl(
642 sal_Int32 nDecimals
, sal_Int32 nMinDecimals
, sal_Int32 nInteger
,
643 bool bGrouping
, sal_Int32 nExp
, sal_Int32 nExpInterval
, bool bExpSign
)
645 FinishTextElement_Impl();
648 if ( nDecimals
>= 0 ) // negative = automatic
650 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
651 OUString::number( nDecimals
) );
654 if ( nMinDecimals
>= 0 ) // negative = automatic
656 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_MIN_DECIMAL_PLACES
,
657 OUString::number( nMinDecimals
) );
661 if ( nInteger
>= 0 ) // negative = automatic
663 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
664 OUString::number( nInteger
) );
667 // (automatic) grouping separator
670 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
676 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_EXPONENT_DIGITS
,
677 OUString::number( nExp
) );
680 // exponent interval for engineering notation
681 if ( nExpInterval
>= 0 )
683 // Export only for 1.2 with extensions or 1.3 and later.
684 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
685 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
687 // For 1.2+ use loext namespace, for 1.3 use number namespace.
688 rExport
.AddAttribute(
689 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
690 XML_EXPONENT_INTERVAL
, OUString::number( nExpInterval
) );
697 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_FORCED_EXPONENT_SIGN
, XML_TRUE
);
701 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_FORCED_EXPONENT_SIGN
, XML_FALSE
);
704 SvXMLElementExport
aElem( rExport
,
705 XML_NAMESPACE_NUMBER
, XML_SCIENTIFIC_NUMBER
,
709 void SvXMLNumFmtExport::WriteFractionElement_Impl(
710 sal_Int32 nInteger
, bool bGrouping
,
711 sal_Int32 nNumeratorDigits
, sal_Int32 nDenominatorDigits
, sal_Int32 nDenominator
)
713 FinishTextElement_Impl();
716 if ( nInteger
>= 0 ) // negative = default (no integer part)
718 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
719 OUString::number( nInteger
) );
722 // (automatic) grouping separator
725 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
729 if ( nNumeratorDigits
>= 0 )
731 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_NUMERATOR_DIGITS
,
732 OUString::number( nNumeratorDigits
) );
737 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DENOMINATOR_VALUE
,
738 OUString::number( nDenominator
) );
740 // I guess it's not necessary to export nDenominatorDigits
741 // if we have a forced denominator ( remove ? )
742 if ( nDenominatorDigits
>= 0 )
744 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_DENOMINATOR_DIGITS
,
745 OUString::number( nDenominatorDigits
) );
748 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_FRACTION
,
752 // mapping (condition)
754 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp
, double fLimit
,
755 sal_Int32 nKey
, sal_Int32 nPart
)
757 FinishTextElement_Impl();
759 if ( nOp
!= NUMBERFORMAT_OP_NO
)
763 OUStringBuffer
aCondStr(20);
764 aCondStr
.appendAscii( "value()" ); //! define constant
767 case NUMBERFORMAT_OP_EQ
: aCondStr
.append( '=' ); break;
768 case NUMBERFORMAT_OP_NE
: aCondStr
.appendAscii( "!=" ); break;
769 case NUMBERFORMAT_OP_LT
: aCondStr
.append( '<' ); break;
770 case NUMBERFORMAT_OP_LE
: aCondStr
.appendAscii( "<=" ); break;
771 case NUMBERFORMAT_OP_GT
: aCondStr
.append( '>' ); break;
772 case NUMBERFORMAT_OP_GE
: aCondStr
.appendAscii( ">=" ); break;
774 OSL_FAIL("unknown operator");
776 ::rtl::math::doubleToUStringBuffer( aCondStr
, fLimit
,
777 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
780 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_CONDITION
,
781 aCondStr
.makeStringAndClear() );
783 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_APPLY_STYLE_NAME
,
784 rExport
.EncodeStyleName( lcl_CreateStyleName( nKey
, nPart
, false,
787 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_MAP
,
792 // for old (automatic) currency formats: parse currency symbol from text
794 sal_Int32
lcl_FindSymbol( const OUString
& sUpperStr
, const OUString
& sCurString
)
796 // search for currency symbol
797 // Quoting as in ImpSvNumberformatScan::Symbol_Division
802 nCPos
= sUpperStr
.indexOf( sCurString
, nCPos
);
806 sal_Int32 nQ
= SvNumberformat::GetQuoteEnd( sUpperStr
, nCPos
);
809 // dm can be escaped as "dm or \d
812 ((c
= sUpperStr
[nCPos
-1]) != '"'
815 return nCPos
; // found
824 nCPos
= nQ
+ 1; // continue after quote end
831 bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString
& rString
,
832 const ::com::sun::star::lang::Locale
& rLocale
)
834 // returns true if currency element was written
838 LanguageTag
aLanguageTag( rLocale
);
839 pFormatter
->ChangeIntl( aLanguageTag
.getLanguageType( false) );
840 OUString sCurString
, sDummy
;
841 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
843 pCharClass
->setLanguageTag( aLanguageTag
);
844 OUString sUpperStr
= pCharClass
->uppercase(rString
);
845 sal_Int32 nPos
= lcl_FindSymbol( sUpperStr
, sCurString
);
848 sal_Int32 nLength
= rString
.getLength();
849 sal_Int32 nCurLen
= sCurString
.getLength();
850 sal_Int32 nCont
= nPos
+ nCurLen
;
852 // text before currency symbol
855 AddToTextElement_Impl( rString
.copy( 0, nPos
) );
857 // currency symbol (empty string -> default)
859 WriteCurrencyElement_Impl( sEmpty
, sEmpty
);
862 // text after currency symbol
863 if ( nCont
< nLength
)
865 AddToTextElement_Impl( rString
.copy( nCont
, nLength
-nCont
) );
870 AddToTextElement_Impl( rString
); // simple text
873 return bRet
; // true: currency element written
876 static OUString
lcl_GetDefaultCalendar( SvNumberFormatter
* pFormatter
, LanguageType nLang
)
878 // get name of first non-gregorian calendar for the language
881 CalendarWrapper
* pCalendar
= pFormatter
->GetCalendar();
884 lang::Locale
aLocale( LanguageTag::convertToLocale( nLang
) );
886 uno::Sequence
<OUString
> aCals
= pCalendar
->getAllCalendars( aLocale
);
887 sal_Int32 nCnt
= aCals
.getLength();
889 for ( sal_Int32 j
=0; j
< nCnt
&& !bFound
; j
++ )
891 if ( aCals
[j
] != "gregorian" )
893 aCalendar
= aCals
[j
];
901 static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
, sal_uInt16 nPos
)
903 sal_uInt16 nCount
= rEmbeddedEntries
.size();
904 for (sal_uInt16 i
=0; i
<nCount
; i
++)
905 if ( rEmbeddedEntries
[i
].nSourcePos
== nPos
)
908 return false; // not found
911 static bool lcl_IsDefaultDateFormat( const SvNumberformat
& rFormat
, bool bSystemDate
, NfIndexTableOffset eBuiltIn
)
913 // make an extra loop to collect date elements, to check if it is a default format
914 // before adding the automatic-order attribute
916 SvXMLDateElementAttributes eDateDOW
= XML_DEA_NONE
;
917 SvXMLDateElementAttributes eDateDay
= XML_DEA_NONE
;
918 SvXMLDateElementAttributes eDateMonth
= XML_DEA_NONE
;
919 SvXMLDateElementAttributes eDateYear
= XML_DEA_NONE
;
920 SvXMLDateElementAttributes eDateHours
= XML_DEA_NONE
;
921 SvXMLDateElementAttributes eDateMins
= XML_DEA_NONE
;
922 SvXMLDateElementAttributes eDateSecs
= XML_DEA_NONE
;
923 bool bDateNoDefault
= false;
930 short nElemType
= rFormat
.GetNumForType( 0, nPos
, false );
934 if ( nLastType
== NF_SYMBOLTYPE_STRING
)
935 bDateNoDefault
= true; // text at the end -> no default date format
936 bEnd
= true; // end of format reached
938 case NF_SYMBOLTYPE_STRING
:
939 case NF_SYMBOLTYPE_DATESEP
:
940 case NF_SYMBOLTYPE_TIMESEP
:
941 case NF_SYMBOLTYPE_TIME100SECSEP
:
942 // text is ignored, except at the end
944 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
945 case NF_KEY_NN
: eDateDOW
= XML_DEA_SHORT
; break;
947 case NF_KEY_NNNN
: eDateDOW
= XML_DEA_LONG
; break;
948 case NF_KEY_D
: eDateDay
= XML_DEA_SHORT
; break;
949 case NF_KEY_DD
: eDateDay
= XML_DEA_LONG
; break;
950 case NF_KEY_M
: eDateMonth
= XML_DEA_SHORT
; break;
951 case NF_KEY_MM
: eDateMonth
= XML_DEA_LONG
; break;
952 case NF_KEY_MMM
: eDateMonth
= XML_DEA_TEXTSHORT
; break;
953 case NF_KEY_MMMM
: eDateMonth
= XML_DEA_TEXTLONG
; break;
954 case NF_KEY_YY
: eDateYear
= XML_DEA_SHORT
; break;
955 case NF_KEY_YYYY
: eDateYear
= XML_DEA_LONG
; break;
956 case NF_KEY_H
: eDateHours
= XML_DEA_SHORT
; break;
957 case NF_KEY_HH
: eDateHours
= XML_DEA_LONG
; break;
958 case NF_KEY_MI
: eDateMins
= XML_DEA_SHORT
; break;
959 case NF_KEY_MMI
: eDateMins
= XML_DEA_LONG
; break;
960 case NF_KEY_S
: eDateSecs
= XML_DEA_SHORT
; break;
961 case NF_KEY_SS
: eDateSecs
= XML_DEA_LONG
; break;
963 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
965 bDateNoDefault
= true; // any other element -> no default format
967 nLastType
= nElemType
;
971 if ( bDateNoDefault
)
972 return false; // additional elements
975 NfIndexTableOffset eFound
= (NfIndexTableOffset
) SvXMLNumFmtDefaults::GetDefaultDateFormat(
976 eDateDOW
, eDateDay
, eDateMonth
, eDateYear
, eDateHours
, eDateMins
, eDateSecs
, bSystemDate
);
978 return ( eFound
== eBuiltIn
);
982 // export one part (condition)
984 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
,
985 sal_uInt16 nPart
, bool bDefPart
)
987 //! for the default part, pass the coditions from the other parts!
991 NfIndexTableOffset eBuiltIn
= pFormatter
->GetIndexTableOffset( nKey
);
994 bool bThousand
= false;
995 sal_uInt16 nPrecision
= 0;
996 sal_uInt16 nLeading
= 0;
997 rFormat
.GetNumForInfo( nPart
, nFmtType
, bThousand
, nPrecision
, nLeading
);
998 nFmtType
&= ~css::util::NumberFormat::DEFINED
;
1000 // special treatment of builtin formats that aren't detected by normal parsing
1001 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
1002 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1003 nFmtType
= css::util::NumberFormat::NUMBER
;
1004 else if ( eBuiltIn
== NF_BOOLEAN
)
1005 nFmtType
= css::util::NumberFormat::LOGICAL
;
1006 else if ( eBuiltIn
== NF_TEXT
)
1007 nFmtType
= css::util::NumberFormat::TEXT
;
1009 // #101606# An empty subformat is a valid number-style resulting in an
1010 // empty display string for the condition of the subformat.
1011 if ( nFmtType
== css::util::NumberFormat::UNDEFINED
&& rFormat
.GetNumForType( nPart
,
1015 XMLTokenEnum eType
= XML_TOKEN_INVALID
;
1018 // type is 0 if a format contains no recognized elements
1019 // (like text only) - this is handled as a number-style.
1021 case css::util::NumberFormat::NUMBER
:
1022 case css::util::NumberFormat::SCIENTIFIC
:
1023 case css::util::NumberFormat::FRACTION
:
1024 eType
= XML_NUMBER_STYLE
;
1026 case css::util::NumberFormat::PERCENT
:
1027 eType
= XML_PERCENTAGE_STYLE
;
1029 case css::util::NumberFormat::CURRENCY
:
1030 eType
= XML_CURRENCY_STYLE
;
1032 case css::util::NumberFormat::DATE
:
1033 case css::util::NumberFormat::DATETIME
:
1034 eType
= XML_DATE_STYLE
;
1036 case css::util::NumberFormat::TIME
:
1037 eType
= XML_TIME_STYLE
;
1039 case css::util::NumberFormat::TEXT
:
1040 eType
= XML_TEXT_STYLE
;
1042 case css::util::NumberFormat::LOGICAL
:
1043 eType
= XML_BOOLEAN_STYLE
;
1046 DBG_ASSERT( eType
!= XML_TOKEN_INVALID
, "unknown format type" );
1048 OUString sAttrValue
;
1049 bool bUserDef
= ( rFormat
.GetType() & css::util::NumberFormat::DEFINED
);
1051 // common attributes for format
1053 // format name (generated from key) - style namespace
1054 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
1055 lcl_CreateStyleName( nKey
, nPart
, bDefPart
, sPrefix
) );
1057 // "volatile" attribute for styles used only in maps
1059 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_VOLATILE
, XML_TRUE
);
1061 // language / country
1062 LanguageType nLang
= rFormat
.GetLanguage();
1063 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
1066 // titles for builtin formats are not written
1067 sAttrValue
= rFormat
.GetComment();
1068 if ( !sAttrValue
.isEmpty() && bUserDef
&& bDefPart
)
1070 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TITLE
, sAttrValue
);
1073 // automatic ordering for currency and date formats
1074 // only used for some built-in formats
1075 bool bAutoOrder
= ( eBuiltIn
== NF_CURRENCY_1000INT
|| eBuiltIn
== NF_CURRENCY_1000DEC2
||
1076 eBuiltIn
== NF_CURRENCY_1000INT_RED
|| eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1077 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
||
1078 eBuiltIn
== NF_DATE_SYSTEM_SHORT
|| eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1079 eBuiltIn
== NF_DATE_SYS_MMYY
|| eBuiltIn
== NF_DATE_SYS_DDMMM
||
1080 eBuiltIn
== NF_DATE_SYS_DDMMYYYY
|| eBuiltIn
== NF_DATE_SYS_DDMMYY
||
1081 eBuiltIn
== NF_DATE_SYS_DMMMYY
|| eBuiltIn
== NF_DATE_SYS_DMMMYYYY
||
1082 eBuiltIn
== NF_DATE_SYS_DMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNDMMMYY
||
1083 eBuiltIn
== NF_DATE_SYS_NNDMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNNNDMMMMYYYY
||
1084 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
|| eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
1086 // format source (for date and time formats)
1087 // only used for some built-in formats
1088 bool bSystemDate
= ( eBuiltIn
== NF_DATE_SYSTEM_SHORT
||
1089 eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1090 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
);
1091 bool bLongSysDate
= ( eBuiltIn
== NF_DATE_SYSTEM_LONG
);
1093 // check if the format definition matches the key
1094 if ( bAutoOrder
&& ( nFmtType
== css::util::NumberFormat::DATE
|| nFmtType
== css::util::NumberFormat::DATETIME
) &&
1095 !lcl_IsDefaultDateFormat( rFormat
, bSystemDate
, eBuiltIn
) )
1097 bAutoOrder
= bSystemDate
= bLongSysDate
= false; // don't write automatic-order attribute then
1101 ( nFmtType
== css::util::NumberFormat::CURRENCY
|| nFmtType
== css::util::NumberFormat::DATE
|| nFmtType
== css::util::NumberFormat::DATETIME
) )
1103 // #85109# format type must be checked to avoid dtd errors if
1104 // locale data contains other format types at the built-in positions
1106 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_AUTOMATIC_ORDER
,
1110 if ( bSystemDate
&& bAutoOrder
&&
1111 ( nFmtType
== css::util::NumberFormat::DATE
|| nFmtType
== css::util::NumberFormat::DATETIME
) )
1113 // #85109# format type must be checked to avoid dtd errors if
1114 // locale data contains other format types at the built-in positions
1116 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_FORMAT_SOURCE
,
1120 // overflow for time formats as in [hh]:mm
1121 // controlled by bThousand from number format info
1122 // default for truncate-on-overflow is true
1123 if ( nFmtType
== css::util::NumberFormat::TIME
&& bThousand
)
1125 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRUNCATE_ON_OVERFLOW
,
1129 // Native number transliteration
1130 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr
;
1131 rFormat
.GetNatNumXml( aAttr
, nPart
);
1132 if ( !aAttr
.Format
.isEmpty() )
1134 /* FIXME-BCP47: ODF defines no transliteration-script or
1135 * transliteration-rfc-language-tag */
1136 LanguageTag
aLanguageTag( aAttr
.Locale
);
1137 OUString aLanguage
, aScript
, aCountry
;
1138 aLanguageTag
.getIsoLanguageScriptCountry( aLanguage
, aScript
, aCountry
);
1139 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_FORMAT
,
1141 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1143 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1145 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_STYLE
,
1150 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, eType
,
1153 // color (properties element)
1155 const Color
* pCol
= rFormat
.GetColor( nPart
);
1157 WriteColorElement_Impl(*pCol
);
1159 // detect if there is "real" content, excluding color and maps
1160 //! move to implementation of Write... methods?
1161 bool bAnyContent
= false;
1165 SvXMLEmbeddedTextEntryArr aEmbeddedEntries
;
1166 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1168 // default number format contains just one number element
1169 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries
);
1172 else if ( eBuiltIn
== NF_BOOLEAN
)
1174 // boolean format contains just one boolean element
1175 WriteBooleanElement_Impl();
1180 // first loop to collect attributes
1182 bool bDecDashes
= false;
1183 bool bExpFound
= false;
1184 bool bCurrFound
= false;
1185 bool bInInteger
= true;
1186 bool bExpSign
= true;
1187 sal_Int32 nExpDigits
= 0;
1188 sal_Int32 nIntegerSymbols
= 0; // for embedded-text, including "#"
1189 sal_Int32 nTrailingThousands
= 0; // thousands-separators after all digits
1190 sal_Int32 nMinDecimals
= nPrecision
;
1193 sal_uInt16 nPos
= 0;
1197 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, false );
1198 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, false );
1200 switch ( nElemType
)
1203 bEnd
= true; // end of format reached
1205 case NF_SYMBOLTYPE_DIGIT
:
1206 if ( bExpFound
&& pElemStr
)
1207 nExpDigits
+= pElemStr
->getLength();
1208 else if ( !bDecDashes
&& pElemStr
&& (*pElemStr
)[0] == '-' )
1213 else if ( !bInInteger
&& pElemStr
)
1215 for ( sal_Int32 i
= pElemStr
->getLength()-1; i
>= 0 && (*pElemStr
)[i
] == '#'; i
-- )
1220 if ( bInInteger
&& pElemStr
)
1221 nIntegerSymbols
+= pElemStr
->getLength();
1222 nTrailingThousands
= 0;
1224 case NF_SYMBOLTYPE_DECSEP
:
1227 case NF_SYMBOLTYPE_THSEP
:
1229 nTrailingThousands
+= pElemStr
->getLength(); // is reset to 0 if digits follow
1231 case NF_SYMBOLTYPE_EXP
:
1232 bExpFound
= true; // following digits are exponent digits
1234 if ( pElemStr
&& pElemStr
->getLength() == 1 )
1235 bExpSign
= false; // for 0.00E0
1237 case NF_SYMBOLTYPE_CURRENCY
:
1240 case NF_SYMBOLTYPE_CURREXT
:
1242 sCurrExt
= *pElemStr
;
1245 // E, EE, R, RR: select non-gregorian calendar
1246 // AAA, AAAA: calendar is switched at the position of the element
1251 if (aCalendar
.isEmpty())
1252 aCalendar
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1258 // collect strings for embedded-text (must be known before number element is written)
1260 bool bAllowEmbedded
= ( nFmtType
== 0 || nFmtType
== css::util::NumberFormat::NUMBER
||
1261 nFmtType
== css::util::NumberFormat::CURRENCY
||
1262 nFmtType
== css::util::NumberFormat::PERCENT
);
1263 if ( bAllowEmbedded
)
1265 sal_Int32 nDigitsPassed
= 0;
1270 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, false );
1271 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, false );
1273 switch ( nElemType
)
1276 bEnd
= true; // end of format reached
1278 case NF_SYMBOLTYPE_DIGIT
:
1280 nDigitsPassed
+= pElemStr
->getLength();
1282 case NF_SYMBOLTYPE_STRING
:
1283 case NF_SYMBOLTYPE_BLANK
:
1284 case NF_SYMBOLTYPE_PERCENT
:
1285 if ( nDigitsPassed
> 0 && nDigitsPassed
< nIntegerSymbols
&& pElemStr
)
1287 // text (literal or underscore) within the integer part of a number:number element
1289 OUString aEmbeddedStr
;
1290 if ( nElemType
== NF_SYMBOLTYPE_STRING
|| nElemType
== NF_SYMBOLTYPE_PERCENT
)
1292 aEmbeddedStr
= *pElemStr
;
1296 SvNumberformat::InsertBlanks( aEmbeddedStr
, 0, (*pElemStr
)[1] );
1298 sal_Int32 nEmbedPos
= nIntegerSymbols
- nDigitsPassed
;
1300 SvXMLEmbeddedTextEntry
* pObj
= new SvXMLEmbeddedTextEntry( nPos
, nEmbedPos
, aEmbeddedStr
);
1301 aEmbeddedEntries
.push_back( pObj
);
1309 // final loop to write elements
1311 bool bNumWritten
= false;
1312 bool bCurrencyWritten
= false;
1313 short nPrevType
= 0;
1318 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, false );
1319 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, false );
1321 switch ( nElemType
)
1324 bEnd
= true; // end of format reached
1326 case NF_SYMBOLTYPE_STRING
:
1327 case NF_SYMBOLTYPE_DATESEP
:
1328 case NF_SYMBOLTYPE_TIMESEP
:
1329 case NF_SYMBOLTYPE_TIME100SECSEP
:
1330 case NF_SYMBOLTYPE_PERCENT
:
1333 if ( ( nPrevType
== NF_KEY_S
|| nPrevType
== NF_KEY_SS
) &&
1334 ( nElemType
== NF_SYMBOLTYPE_TIME100SECSEP
) &&
1337 // decimal separator after seconds is implied by
1338 // "decimal-places" attribute and must not be written
1340 //! difference between '.' and ',' is lost here
1342 else if ( lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1344 // text is written as embedded-text child of the number,
1345 // don't create a text element
1347 else if ( nFmtType
== css::util::NumberFormat::CURRENCY
&& !bCurrFound
&& !bCurrencyWritten
)
1349 // automatic currency symbol is implemented as part of
1350 // normal text -> search for the symbol
1351 bCurrencyWritten
= WriteTextWithCurrency_Impl( *pElemStr
,
1352 LanguageTag::convertToLocale( nLang
) );
1356 AddToTextElement_Impl( *pElemStr
);
1359 case NF_SYMBOLTYPE_BLANK
:
1360 if ( pElemStr
&& !lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1362 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1363 // (#i20396# the spaces may also be in embedded-text elements)
1366 SvNumberformat::InsertBlanks( aBlanks
, 0, (*pElemStr
)[1] );
1367 AddToTextElement_Impl( aBlanks
);
1370 case NF_KEY_GENERAL
:
1371 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries
);
1376 if ( bCurrencyWritten
)
1377 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1380 //! must be different from short automatic format
1381 //! but should still be empty (meaning automatic)
1382 // pElemStr is "CCC"
1384 WriteCurrencyElement_Impl( *pElemStr
, OUString() );
1386 bCurrencyWritten
= true;
1390 case NF_SYMBOLTYPE_CURRENCY
:
1393 if ( bCurrencyWritten
)
1394 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1397 WriteCurrencyElement_Impl( *pElemStr
, sCurrExt
);
1399 bCurrencyWritten
= true;
1403 case NF_SYMBOLTYPE_DIGIT
:
1404 if (!bNumWritten
) // write number part
1408 // for type 0 (not recognized as a special type),
1409 // write a "normal" number
1411 case css::util::NumberFormat::NUMBER
:
1412 case css::util::NumberFormat::CURRENCY
:
1413 case css::util::NumberFormat::PERCENT
:
1416 // only some built-in formats have automatic decimals
1417 sal_Int32 nDecimals
= nPrecision
; // from GetFormatSpecialInfo
1418 if ( eBuiltIn
== NF_NUMBER_STANDARD
||
1419 eBuiltIn
== NF_CURRENCY_1000DEC2
||
1420 eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1421 eBuiltIn
== NF_CURRENCY_1000DEC2_CCC
||
1422 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
)
1426 // only one built-in format has automatic integer digits
1427 sal_Int32 nInteger
= nLeading
;
1428 if ( eBuiltIn
== NF_NUMBER_SYSTEM
)
1431 // string for decimal replacement
1432 // has to be taken from nPrecision
1433 // (positive number even for automatic decimals)
1434 OUStringBuffer sDashStr
;
1435 if (bDecDashes
&& nPrecision
> 0)
1436 comphelper::string::padToLength(sDashStr
, nPrecision
, '-');
1438 WriteNumberElement_Impl(nDecimals
, nMinDecimals
, nInteger
, sDashStr
.makeStringAndClear(),
1439 bThousand
, nTrailingThousands
, aEmbeddedEntries
);
1443 case css::util::NumberFormat::SCIENTIFIC
:
1444 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1445 // as integer digits: use nIntegerSymbols instead of nLeading
1446 // nIntegerSymbols represents exponent interval (for engineering notation)
1447 WriteScientificElement_Impl( nPrecision
, nMinDecimals
, nLeading
, bThousand
, nExpDigits
, nIntegerSymbols
, bExpSign
);
1450 case css::util::NumberFormat::FRACTION
:
1452 sal_Int32 nInteger
= nLeading
;
1453 if ( pElemStr
&& (*pElemStr
)[0] == '?' )
1455 // If the first digit character is a question mark,
1456 // the fraction doesn't have an integer part, and no
1457 // min-integer-digits attribute must be written.
1460 sal_Int32 nDenominator
= rFormat
.GetForcedDenominatorForType( nPart
);
1461 WriteFractionElement_Impl( nInteger
, bThousand
, nPrecision
, nPrecision
, nDenominator
);
1470 case NF_SYMBOLTYPE_DECSEP
:
1471 if ( pElemStr
&& nPrecision
== 0 )
1473 // A decimal separator after the number, without following decimal digits,
1474 // isn't modelled as part of the number element, so it's written as text
1475 // (the distinction between a quoted and non-quoted, locale-dependent
1476 // character is lost here).
1478 AddToTextElement_Impl( *pElemStr
);
1481 case NF_SYMBOLTYPE_DEL
:
1482 if ( pElemStr
&& comphelper::string::equals(*pElemStr
, '@') )
1484 WriteTextContentElement_Impl();
1489 case NF_SYMBOLTYPE_CALENDAR
:
1491 aCalendar
= *pElemStr
;
1499 bool bLong
= ( nElemType
== NF_KEY_DD
);
1500 WriteDayElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1512 OUString aCalAttr
= aCalendar
;
1513 if ( nElemType
== NF_KEY_AAA
|| nElemType
== NF_KEY_AAAA
)
1515 // calendar attribute for AAA and AAAA is switched only for this element
1516 if (aCalAttr
.isEmpty())
1517 aCalAttr
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1520 bool bLong
= ( nElemType
== NF_KEY_NNN
|| nElemType
== NF_KEY_NNNN
||
1521 nElemType
== NF_KEY_DDDD
|| nElemType
== NF_KEY_AAAA
);
1522 WriteDayOfWeekElement_Impl( aCalAttr
, ( bSystemDate
? bLongSysDate
: bLong
) );
1524 if ( nElemType
== NF_KEY_NNNN
)
1526 // write additional text element for separator
1527 pLocaleData
->setLanguageTag( LanguageTag( nLang
) );
1528 AddToTextElement_Impl( pLocaleData
->getLongDateDayOfWeekSep() );
1536 case NF_KEY_MMMMM
: //! first letter of month name, no attribute available
1538 bool bLong
= ( nElemType
== NF_KEY_MM
|| nElemType
== NF_KEY_MMMM
);
1539 bool bText
= ( nElemType
== NF_KEY_MMM
|| nElemType
== NF_KEY_MMMM
||
1540 nElemType
== NF_KEY_MMMMM
);
1541 WriteMonthElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
), bText
);
1549 case NF_KEY_R
: //! R acts as EE, no attribute available
1551 //! distinguish EE and R
1552 // calendar attribute for E and EE and R is set in first loop
1553 bool bLong
= ( nElemType
== NF_KEY_YYYY
|| nElemType
== NF_KEY_EEC
||
1554 nElemType
== NF_KEY_R
);
1555 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1562 case NF_KEY_RR
: //! RR acts as GGGEE, no attribute available
1564 //! distinguish GG and GGG and RR
1565 bool bLong
= ( nElemType
== NF_KEY_GGG
|| nElemType
== NF_KEY_RR
);
1566 WriteEraElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1568 if ( nElemType
== NF_KEY_RR
)
1570 // calendar attribute for RR is set in first loop
1571 WriteYearElement_Impl( aCalendar
, ( bSystemDate
|| bLongSysDate
) );
1578 bool bLong
= ( nElemType
== NF_KEY_QQ
);
1579 WriteQuarterElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1584 WriteWeekElement_Impl( aCalendar
);
1588 // time elements (bSystemDate is not used):
1592 WriteHoursElement_Impl( nElemType
== NF_KEY_HH
);
1597 WriteMinutesElement_Impl( nElemType
== NF_KEY_MMI
);
1602 WriteSecondsElement_Impl( ( nElemType
== NF_KEY_SS
), nPrecision
);
1607 WriteAMPMElement_Impl(); // short/long?
1610 case NF_SYMBOLTYPE_STAR
:
1611 // export only if ODF 1.2 extensions are enabled
1612 if( rExport
.getDefaultVersion() > SvtSaveOptions::ODFVER_012
)
1614 if ( pElemStr
&& pElemStr
->getLength() > 1 )
1615 WriteRepeatedElement_Impl( (*pElemStr
)[1] );
1619 nPrevType
= nElemType
;
1624 if ( !sTextContent
.isEmpty() )
1625 bAnyContent
= true; // element written in FinishTextElement_Impl
1627 FinishTextElement_Impl(); // final text element - before maps
1631 // for an empty format, write an empty text element
1632 SvXMLElementExport
aTElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
1636 // mapping (conditions) must be last elements
1640 SvNumberformatLimitOps eOp1
, eOp2
;
1641 double fLimit1
, fLimit2
;
1642 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1644 WriteMapElement_Impl( eOp1
, fLimit1
, nKey
, 0 );
1645 WriteMapElement_Impl( eOp2
, fLimit2
, nKey
, 1 );
1647 if ( rFormat
.HasTextFormat() )
1649 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1650 // by reversing the 2nd condition
1652 SvNumberformatLimitOps eOp3
= NUMBERFORMAT_OP_NO
;
1653 double fLimit3
= fLimit2
;
1656 case NUMBERFORMAT_OP_EQ
: eOp3
= NUMBERFORMAT_OP_NE
; break;
1657 case NUMBERFORMAT_OP_NE
: eOp3
= NUMBERFORMAT_OP_EQ
; break;
1658 case NUMBERFORMAT_OP_LT
: eOp3
= NUMBERFORMAT_OP_GE
; break;
1659 case NUMBERFORMAT_OP_LE
: eOp3
= NUMBERFORMAT_OP_GT
; break;
1660 case NUMBERFORMAT_OP_GT
: eOp3
= NUMBERFORMAT_OP_LE
; break;
1661 case NUMBERFORMAT_OP_GE
: eOp3
= NUMBERFORMAT_OP_LT
; break;
1666 if ( fLimit1
== fLimit2
&&
1667 ( ( eOp1
== NUMBERFORMAT_OP_LT
&& eOp2
== NUMBERFORMAT_OP_GT
) ||
1668 ( eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_LT
) ) )
1670 // For <x and >x, add =x as last condition
1671 // (just for readability, <=x would be valid, too)
1673 eOp3
= NUMBERFORMAT_OP_EQ
;
1676 WriteMapElement_Impl( eOp3
, fLimit3
, nKey
, 2 );
1681 // export one format
1683 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
)
1685 sal_uInt16 nUsedParts
= 0;
1687 for (nPart
=0; nPart
<XMLNUM_MAX_PARTS
; nPart
++)
1688 if (rFormat
.GetNumForType( nPart
, 0, false ) != 0)
1689 nUsedParts
= nPart
+1;
1691 SvNumberformatLimitOps eOp1
, eOp2
;
1692 double fLimit1
, fLimit2
;
1693 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1695 // if conditions are set, even empty formats must be written
1697 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 2 )
1699 if ( eOp2
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 3 )
1701 if ( rFormat
.HasTextFormat() && nUsedParts
< 4 )
1704 for (nPart
=0; nPart
<nUsedParts
; nPart
++)
1706 bool bDefault
= ( nPart
+1 == nUsedParts
); // last = default
1707 ExportPart_Impl( rFormat
, nKey
, nPart
, bDefault
);
1711 // export method called by application
1713 void SvXMLNumFmtExport::Export( bool bIsAutoStyle
)
1716 return; // no formatter -> no entries
1719 const SvNumberformat
* pFormat
= NULL
;
1720 bool bNext(pUsedList
->GetFirstUsed(nKey
));
1723 pFormat
= pFormatter
->GetEntry(nKey
);
1725 ExportFormat_Impl( *pFormat
, nKey
);
1726 bNext
= pUsedList
->GetNextUsed(nKey
);
1730 std::vector
<sal_uInt16
> aLanguages
;
1731 pFormatter
->GetUsedLanguages( aLanguages
);
1732 for (std::vector
<sal_uInt16
>::const_iterator
it(aLanguages
.begin()); it
!= aLanguages
.end(); ++it
)
1734 LanguageType nLang
= *it
;
1736 sal_uInt32 nDefaultIndex
= 0;
1737 SvNumberFormatTable
& rTable
= pFormatter
->GetEntryTable(
1738 css::util::NumberFormat::DEFINED
, nDefaultIndex
, nLang
);
1739 SvNumberFormatTable::iterator it2
= rTable
.begin();
1740 while (it2
!= rTable
.end())
1743 pFormat
= it2
->second
;
1744 if (!pUsedList
->IsUsed(nKey
))
1746 DBG_ASSERT((pFormat
->GetType() & css::util::NumberFormat::DEFINED
), "a not user defined numberformat found");
1747 // user-defined and used formats are exported
1748 ExportFormat_Impl( *pFormat
, nKey
);
1749 // if it is a user-defined Format it will be added else nothing will happen
1750 pUsedList
->SetUsed(nKey
);
1757 pUsedList
->Export();
1760 OUString
SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey
)
1762 if(pUsedList
->IsUsed(nKey
) || pUsedList
->IsWasUsed(nKey
))
1763 return lcl_CreateStyleName( nKey
, 0, true, sPrefix
);
1766 OSL_FAIL("There is no written Data-Style");
1771 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey
)
1773 DBG_ASSERT( pFormatter
!= NULL
, "missing formatter" );
1777 if (pFormatter
->GetEntry(nKey
))
1778 pUsedList
->SetUsed( nKey
);
1780 OSL_FAIL("no existing Numberformat found with this key");
1784 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
1787 pUsedList
->GetWasUsed(rWasUsed
);
1790 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
1793 pUsedList
->SetWasUsed(rWasUsed
);
1796 static const SvNumberformat
* lcl_GetFormat( SvNumberFormatter
* pFormatter
,
1799 return ( pFormatter
!= NULL
) ? pFormatter
->GetEntry( nKey
) : NULL
;
1802 sal_uInt32
SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey
)
1804 sal_uInt32 nRet
= nKey
;
1806 const SvNumberformat
* pFormat
= lcl_GetFormat( pFormatter
, nKey
);
1807 if( pFormat
!= NULL
)
1809 DBG_ASSERT( pFormatter
!= NULL
, "format without formatter?" );
1811 sal_Int32 nErrorPos
;
1812 short nType
= pFormat
->GetType();
1814 sal_uInt32 nNewKey
= pFormatter
->GetFormatForLanguageIfBuiltIn(
1815 nKey
, LANGUAGE_SYSTEM
);
1817 if( nNewKey
!= nKey
)
1823 OUString
aFormatString( pFormat
->GetFormatstring() );
1824 pFormatter
->PutandConvertEntry(
1826 nErrorPos
, nType
, nNewKey
,
1827 pFormat
->GetLanguage(), LANGUAGE_SYSTEM
);
1829 // success? Then use new key.
1830 if( nErrorPos
== 0 )
1838 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */