1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <svl/svstdarr.hxx>
30 #include <svl/zforlist.hxx>
31 #include <svl/zformat.hxx>
32 #include <svl/numuno.hxx>
33 #include <i18npool/mslangid.hxx>
34 #include <tools/debug.hxx>
35 #include <rtl/math.hxx>
36 #include <unotools/calendarwrapper.hxx>
37 #include <unotools/charclass.hxx>
38 #include <com/sun/star/lang/Locale.hpp>
39 #include <rtl/ustrbuf.hxx>
40 #include <tools/color.hxx>
41 #include <sax/tools/converter.hxx>
43 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
45 #include <xmloff/xmlnumfe.hxx>
46 #include "xmloff/xmlnmspe.hxx"
47 #include <xmloff/attrlist.hxx>
48 #include <xmloff/nmspmap.hxx>
49 #include <xmloff/families.hxx>
50 #include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults
52 #include <svl/nfsymbol.hxx>
53 #include <xmloff/xmltoken.hxx>
54 #include <xmloff/xmlexp.hxx>
57 #include <boost/ptr_container/ptr_vector.hpp>
59 using ::rtl::OUString
;
60 using ::rtl::OUStringBuffer
;
62 using namespace ::com::sun::star
;
63 using namespace ::xmloff::token
;
64 using namespace ::svt
;
66 //-------------------------------------------------------------------------
68 #define XMLNUM_MAX_PARTS 3
70 //-------------------------------------------------------------------------
74 sal_Bool
operator() (const sal_uInt32 rValue1
, const sal_uInt32 rValue2
) const
76 return rValue1
< rValue2
;
80 typedef std::set
< sal_uInt32
, LessuInt32
> SvXMLuInt32Set
;
82 class SvXMLNumUsedList_Impl
85 SvXMLuInt32Set aWasUsed
;
86 SvXMLuInt32Set::iterator aCurrentUsedPos
;
87 sal_uInt32 nUsedCount
;
88 sal_uInt32 nWasUsedCount
;
91 SvXMLNumUsedList_Impl();
92 ~SvXMLNumUsedList_Impl();
94 void SetUsed( sal_uInt32 nKey
);
95 sal_Bool
IsUsed( sal_uInt32 nKey
) const;
96 sal_Bool
IsWasUsed( sal_uInt32 nKey
) const;
99 sal_Bool
GetFirstUsed(sal_uInt32
& nKey
);
100 sal_Bool
GetNextUsed(sal_uInt32
& nKey
);
102 void GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
);
103 void SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
);
106 //-------------------------------------------------------------------------
108 struct SvXMLEmbeddedTextEntry
110 sal_uInt16 nSourcePos
; // position in NumberFormat (to skip later)
111 sal_Int32 nFormatPos
; // resulting position in embedded-text element
114 SvXMLEmbeddedTextEntry( sal_uInt16 nSP
, sal_Int32 nFP
, const rtl::OUString
& rT
) :
115 nSourcePos(nSP
), nFormatPos(nFP
), aText(rT
) {}
118 class SvXMLEmbeddedTextEntryArr
: public boost::ptr_vector
<SvXMLEmbeddedTextEntry
> {};
120 //-------------------------------------------------------------------------
123 //! 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 sal_Bool
SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey
) const
148 SvXMLuInt32Set::const_iterator aItr
= aUsed
.find(nKey
);
149 return (aItr
!= aUsed
.end());
152 sal_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 sal_Bool
SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32
& nKey
)
174 sal_Bool
bRet(sal_False
);
175 aCurrentUsedPos
= aUsed
.begin();
178 DBG_ASSERT(aCurrentUsedPos
!= aUsed
.end(), "something went wrong");
179 nKey
= *aCurrentUsedPos
;
185 sal_Bool
SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32
& nKey
)
187 sal_Bool
bRet(sal_False
);
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 //-------------------------------------------------------------------------
231 SvXMLNumFmtExport::SvXMLNumFmtExport(
233 const uno::Reference
< util::XNumberFormatsSupplier
>& rSupp
) :
235 sPrefix( OUString("N") ),
240 // supplier must be SvNumberFormatsSupplierObj
241 SvNumberFormatsSupplierObj
* pObj
=
242 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
244 pFormatter
= pObj
->GetNumberFormatter();
248 pCharClass
= new CharClass( pFormatter
->GetServiceManager(),
249 pFormatter
->GetLocale() );
250 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetServiceManager(),
251 pFormatter
->GetLocale() );
255 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
257 pCharClass
= new CharClass( rExport
.getServiceFactory(), aLocale
);
258 pLocaleData
= new LocaleDataWrapper( rExport
.getServiceFactory(), aLocale
);
261 pUsedList
= new SvXMLNumUsedList_Impl
;
264 SvXMLNumFmtExport::SvXMLNumFmtExport(
266 const ::com::sun::star::uno::Reference
<
267 ::com::sun::star::util::XNumberFormatsSupplier
>& rSupp
,
268 const rtl::OUString
& rPrefix
) :
275 // supplier must be SvNumberFormatsSupplierObj
276 SvNumberFormatsSupplierObj
* pObj
=
277 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
279 pFormatter
= pObj
->GetNumberFormatter();
283 pCharClass
= new CharClass( pFormatter
->GetServiceManager(),
284 pFormatter
->GetLocale() );
285 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetServiceManager(),
286 pFormatter
->GetLocale() );
290 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
292 pCharClass
= new CharClass( rExport
.getServiceFactory(), aLocale
);
293 pLocaleData
= new LocaleDataWrapper( rExport
.getServiceFactory(), aLocale
);
296 pUsedList
= new SvXMLNumUsedList_Impl
;
299 SvXMLNumFmtExport::~SvXMLNumFmtExport()
306 //-------------------------------------------------------------------------
312 OUString
lcl_CreateStyleName( sal_Int32 nKey
, sal_Int32 nPart
, sal_Bool bDefPart
, const rtl::OUString
& rPrefix
)
314 OUStringBuffer
aFmtName( 10L );
315 aFmtName
.append( rPrefix
);
316 aFmtName
.append( nKey
);
319 aFmtName
.append( (sal_Unicode
)'P' );
320 aFmtName
.append( nPart
);
322 return aFmtName
.makeStringAndClear();
325 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString
& rCalendar
)
327 if ( !rCalendar
.isEmpty() )
329 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_CALENDAR
, rCalendar
);
333 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText
)
335 if ( bText
) // non-textual
337 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TEXTUAL
, XML_TRUE
);
341 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong
)
343 if ( bLong
) // short is default
345 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_STYLE
, XML_LONG
);
349 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang
)
351 if ( nLang
!= LANGUAGE_SYSTEM
)
353 OUString aLangStr
, aCountryStr
;
354 MsLangId::convertLanguageToIsoNames( (LanguageType
)nLang
, aLangStr
, aCountryStr
);
356 if (!aLangStr
.isEmpty())
357 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_LANGUAGE
, aLangStr
);
358 if (!aCountryStr
.isEmpty())
359 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_COUNTRY
, aCountryStr
);
363 //-------------------------------------------------------------------------
366 // methods to write individual elements within a format
369 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString
& rString
)
371 // append to sTextContent, write element in FinishTextElement_Impl
372 // to avoid several text elements following each other
374 sTextContent
.append( rString
);
377 void SvXMLNumFmtExport::FinishTextElement_Impl()
379 if ( sTextContent
.getLength() )
381 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
382 sal_True
, sal_False
);
383 rExport
.Characters( sTextContent
.makeStringAndClear() );
387 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color
& rColor
)
389 FinishTextElement_Impl();
391 OUStringBuffer
aColStr( 7 );
392 ::sax::Converter::convertColor( aColStr
, rColor
.GetColor() );
393 rExport
.AddAttribute( XML_NAMESPACE_FO
, XML_COLOR
,
394 aColStr
.makeStringAndClear() );
396 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_TEXT_PROPERTIES
,
397 sal_True
, sal_False
);
400 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString
& rString
,
401 const OUString
& rExt
)
403 FinishTextElement_Impl();
405 if ( !rExt
.isEmpty() )
407 sal_Int32 nLang
= rExt
.toInt32(16); // hex
408 if ( nLang
< 0 ) // extension string may contain "-" separator
410 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
413 SvXMLElementExport
aElem( rExport
,
414 XML_NAMESPACE_NUMBER
, XML_CURRENCY_SYMBOL
,
415 sal_True
, sal_False
);
416 rExport
.Characters( rString
);
419 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
421 FinishTextElement_Impl();
423 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_BOOLEAN
,
424 sal_True
, sal_False
);
427 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
429 FinishTextElement_Impl();
431 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT_CONTENT
,
432 sal_True
, sal_False
);
437 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
439 FinishTextElement_Impl();
441 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
442 AddStyleAttr_Impl( bLong
); // adds to pAttrList
444 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY
,
445 sal_True
, sal_False
);
448 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
, sal_Bool bText
)
450 FinishTextElement_Impl();
452 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
453 AddStyleAttr_Impl( bLong
); // adds to pAttrList
454 AddTextualAttr_Impl( bText
); // adds to pAttrList
456 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MONTH
,
457 sal_True
, sal_False
);
460 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString
& rCalendar
, sal_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_YEAR
,
468 sal_True
, sal_False
);
471 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString
& rCalendar
, sal_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_ERA
,
479 sal_True
, sal_False
);
482 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
484 FinishTextElement_Impl();
486 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
487 AddStyleAttr_Impl( bLong
); // adds to pAttrList
489 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY_OF_WEEK
,
490 sal_True
, sal_False
);
493 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString
& rCalendar
)
495 FinishTextElement_Impl();
497 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
499 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_WEEK_OF_YEAR
,
500 sal_True
, sal_False
);
503 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
505 FinishTextElement_Impl();
507 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
508 AddStyleAttr_Impl( bLong
); // adds to pAttrList
510 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_QUARTER
,
511 sal_True
, sal_False
);
516 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong
)
518 FinishTextElement_Impl();
520 AddStyleAttr_Impl( bLong
); // adds to pAttrList
522 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_HOURS
,
523 sal_True
, sal_False
);
526 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong
)
528 FinishTextElement_Impl();
530 AddStyleAttr_Impl( bLong
); // adds to pAttrList
532 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MINUTES
,
533 sal_True
, sal_False
);
536 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong
, sal_uInt16 nDecimals
)
538 FinishTextElement_Impl();
540 AddStyleAttr_Impl( bLong
); // adds to pAttrList
543 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
544 OUString::valueOf( (sal_Int32
) nDecimals
) );
547 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_SECONDS
,
548 sal_True
, sal_False
);
551 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
553 FinishTextElement_Impl();
555 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_AM_PM
,
556 sal_True
, sal_False
);
561 void SvXMLNumFmtExport::WriteNumberElement_Impl(
562 sal_Int32 nDecimals
, sal_Int32 nInteger
,
563 const OUString
& rDashStr
, sal_Bool bVarDecimals
,
564 sal_Bool bGrouping
, sal_Int32 nTrailingThousands
,
565 const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
)
567 FinishTextElement_Impl();
570 if ( nDecimals
>= 0 ) // negative = automatic
572 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
573 OUString::valueOf( nDecimals
) );
577 if ( nInteger
>= 0 ) // negative = automatic
579 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
580 OUString::valueOf( nInteger
) );
583 // decimal replacement (dashes) or variable decimals (#)
584 if ( !rDashStr
.isEmpty() || bVarDecimals
)
586 // variable decimals means an empty replacement string
587 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_REPLACEMENT
,
591 // (automatic) grouping separator
594 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
597 // display-factor if there are trailing thousands separators
598 if ( nTrailingThousands
)
600 // each separator character removes three digits
601 double fFactor
= ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands
);
603 OUStringBuffer aFactStr
;
604 ::sax::Converter::convertDouble( aFactStr
, fFactor
);
605 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DISPLAY_FACTOR
, aFactStr
.makeStringAndClear() );
608 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_NUMBER
,
609 sal_True
, sal_True
);
611 // number:embedded-text as child elements
613 sal_uInt16 nEntryCount
= rEmbeddedEntries
.size();
614 for (sal_uInt16 nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
616 const SvXMLEmbeddedTextEntry
* pObj
= &rEmbeddedEntries
[nEntry
];
618 // position attribute
619 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_POSITION
,
620 OUString::valueOf( pObj
->nFormatPos
) );
621 SvXMLElementExport
aChildElem( rExport
, XML_NAMESPACE_NUMBER
, XML_EMBEDDED_TEXT
,
622 sal_True
, sal_False
);
624 // text as element content
625 rtl::OUString
aContent( pObj
->aText
);
626 while ( nEntry
+1 < nEntryCount
&& rEmbeddedEntries
[nEntry
+1].nFormatPos
== pObj
->nFormatPos
)
628 // The array can contain several elements for the same position in the number
629 // (for example, literal text and space from underscores). They must be merged
630 // into a single embedded-text element.
631 aContent
+= rEmbeddedEntries
[nEntry
+1].aText
;
634 rExport
.Characters( aContent
);
638 void SvXMLNumFmtExport::WriteScientificElement_Impl(
639 sal_Int32 nDecimals
, sal_Int32 nInteger
,
640 sal_Bool bGrouping
, sal_Int32 nExp
)
642 FinishTextElement_Impl();
645 if ( nDecimals
>= 0 ) // negative = automatic
647 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
648 OUString::valueOf( nDecimals
) );
652 if ( nInteger
>= 0 ) // negative = automatic
654 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
655 OUString::valueOf( nInteger
) );
658 // (automatic) grouping separator
661 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
667 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_EXPONENT_DIGITS
,
668 OUString::valueOf( nExp
) );
671 SvXMLElementExport
aElem( rExport
,
672 XML_NAMESPACE_NUMBER
, XML_SCIENTIFIC_NUMBER
,
673 sal_True
, sal_False
);
676 void SvXMLNumFmtExport::WriteFractionElement_Impl(
677 sal_Int32 nInteger
, sal_Bool bGrouping
,
678 sal_Int32 nNumeratorDigits
, sal_Int32 nDenominatorDigits
, sal_Int32 nDenominator
)
680 FinishTextElement_Impl();
683 if ( nInteger
>= 0 ) // negative = default (no integer part)
685 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
686 OUString::valueOf( nInteger
) );
689 // (automatic) grouping separator
692 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
696 if ( nNumeratorDigits
>= 0 )
698 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_NUMERATOR_DIGITS
,
699 OUString::valueOf( nNumeratorDigits
) );
704 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DENOMINATOR_VALUE
,
705 OUString::valueOf( nDenominator
) );
707 // I guess it's not necessary to export nDenominatorDigits
708 // if we have a forced denominator ( remove ? )
709 if ( nDenominatorDigits
>= 0 )
711 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_DENOMINATOR_DIGITS
,
712 OUString::valueOf( nDenominatorDigits
) );
715 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_FRACTION
,
716 sal_True
, sal_False
);
719 // mapping (condition)
721 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp
, double fLimit
,
722 sal_Int32 nKey
, sal_Int32 nPart
)
724 FinishTextElement_Impl();
726 if ( nOp
!= NUMBERFORMAT_OP_NO
)
730 OUStringBuffer
aCondStr( 20L );
731 aCondStr
.appendAscii( "value()" ); //! define constant
734 case NUMBERFORMAT_OP_EQ
: aCondStr
.append( (sal_Unicode
) '=' ); break;
735 case NUMBERFORMAT_OP_NE
: aCondStr
.appendAscii( "<>" ); break;
736 case NUMBERFORMAT_OP_LT
: aCondStr
.append( (sal_Unicode
) '<' ); break;
737 case NUMBERFORMAT_OP_LE
: aCondStr
.appendAscii( "<=" ); break;
738 case NUMBERFORMAT_OP_GT
: aCondStr
.append( (sal_Unicode
) '>' ); break;
739 case NUMBERFORMAT_OP_GE
: aCondStr
.appendAscii( ">=" ); break;
741 OSL_FAIL("unknown operator");
743 ::rtl::math::doubleToUStringBuffer( aCondStr
, fLimit
,
744 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
747 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_CONDITION
,
748 aCondStr
.makeStringAndClear() );
750 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_APPLY_STYLE_NAME
,
751 rExport
.EncodeStyleName( lcl_CreateStyleName( nKey
, nPart
, sal_False
,
754 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_MAP
,
755 sal_True
, sal_False
);
759 //-------------------------------------------------------------------------
760 // for old (automatic) currency formats: parse currency symbol from text
762 xub_StrLen
lcl_FindSymbol( const String
& sUpperStr
, const String
& sCurString
)
764 // search for currency symbol
765 // Quoting as in ImpSvNumberformatScan::Symbol_Division
767 xub_StrLen nCPos
= 0;
768 while (nCPos
!= STRING_NOTFOUND
)
770 nCPos
= sUpperStr
.Search( sCurString
, nCPos
);
771 if (nCPos
!= STRING_NOTFOUND
)
774 xub_StrLen nQ
= SvNumberformat::GetQuoteEnd( sUpperStr
, nCPos
);
775 if ( nQ
== STRING_NOTFOUND
)
777 // dm can be escaped as "dm or \d
780 ((c
= sUpperStr
.GetChar(xub_StrLen(nCPos
-1))) != '"'
783 return nCPos
; // found
789 nCPos
= nQ
+ 1; // continue after quote end
792 return STRING_NOTFOUND
; // not found
795 sal_Bool
SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString
& rString
,
796 const ::com::sun::star::lang::Locale
& rLocale
)
798 // returns sal_True if currency element was written
800 sal_Bool bRet
= sal_False
;
802 LanguageType nLang
= MsLangId::convertLocaleToLanguage( rLocale
);
803 pFormatter
->ChangeIntl( nLang
);
804 String sCurString
, sDummy
;
805 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
807 pCharClass
->setLocale( rLocale
);
808 String sUpperStr
= pCharClass
->uppercase(rString
);
809 xub_StrLen nPos
= lcl_FindSymbol( sUpperStr
, sCurString
);
810 if ( nPos
!= STRING_NOTFOUND
)
812 sal_Int32 nLength
= rString
.getLength();
813 sal_Int32 nCurLen
= sCurString
.Len();
814 sal_Int32 nCont
= nPos
+ nCurLen
;
816 // text before currency symbol
818 AddToTextElement_Impl( rString
.copy( 0, nPos
) );
820 // currency symbol (empty string -> default)
822 WriteCurrencyElement_Impl( sEmpty
, sEmpty
);
825 // text after currency symbol
826 if ( nCont
< nLength
)
827 AddToTextElement_Impl( rString
.copy( nCont
, nLength
-nCont
) );
830 AddToTextElement_Impl( rString
); // simple text
832 return bRet
; // sal_True: currency element written
835 //-------------------------------------------------------------------------
837 OUString
lcl_GetDefaultCalendar( SvNumberFormatter
* pFormatter
, LanguageType nLang
)
839 // get name of first non-gregorian calendar for the language
842 CalendarWrapper
* pCalendar
= pFormatter
->GetCalendar();
845 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( nLang
) );
847 uno::Sequence
<OUString
> aCals
= pCalendar
->getAllCalendars( aLocale
);
848 sal_Int32 nCnt
= aCals
.getLength();
849 sal_Bool bFound
= sal_False
;
850 for ( sal_Int32 j
=0; j
< nCnt
&& !bFound
; j
++ )
852 if ( aCals
[j
] != "gregorian" )
854 aCalendar
= aCals
[j
];
862 //-------------------------------------------------------------------------
864 sal_Bool
lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
, sal_uInt16 nPos
)
866 sal_uInt16 nCount
= rEmbeddedEntries
.size();
867 for (sal_uInt16 i
=0; i
<nCount
; i
++)
868 if ( rEmbeddedEntries
[i
].nSourcePos
== nPos
)
871 return sal_False
; // not found
874 sal_Bool
lcl_IsDefaultDateFormat( const SvNumberformat
& rFormat
, sal_Bool bSystemDate
, NfIndexTableOffset eBuiltIn
)
876 // make an extra loop to collect date elements, to check if it is a default format
877 // before adding the automatic-order attribute
879 SvXMLDateElementAttributes eDateDOW
= XML_DEA_NONE
;
880 SvXMLDateElementAttributes eDateDay
= XML_DEA_NONE
;
881 SvXMLDateElementAttributes eDateMonth
= XML_DEA_NONE
;
882 SvXMLDateElementAttributes eDateYear
= XML_DEA_NONE
;
883 SvXMLDateElementAttributes eDateHours
= XML_DEA_NONE
;
884 SvXMLDateElementAttributes eDateMins
= XML_DEA_NONE
;
885 SvXMLDateElementAttributes eDateSecs
= XML_DEA_NONE
;
886 sal_Bool bDateNoDefault
= sal_False
;
889 sal_Bool bEnd
= sal_False
;
893 short nElemType
= rFormat
.GetNumForType( 0, nPos
, sal_False
);
897 if ( nLastType
== NF_SYMBOLTYPE_STRING
)
898 bDateNoDefault
= sal_True
; // text at the end -> no default date format
899 bEnd
= sal_True
; // end of format reached
901 case NF_SYMBOLTYPE_STRING
:
902 case NF_SYMBOLTYPE_DATESEP
:
903 case NF_SYMBOLTYPE_TIMESEP
:
904 case NF_SYMBOLTYPE_TIME100SECSEP
:
905 // text is ignored, except at the end
907 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
908 case NF_KEY_NN
: eDateDOW
= XML_DEA_SHORT
; break;
910 case NF_KEY_NNNN
: eDateDOW
= XML_DEA_LONG
; break;
911 case NF_KEY_D
: eDateDay
= XML_DEA_SHORT
; break;
912 case NF_KEY_DD
: eDateDay
= XML_DEA_LONG
; break;
913 case NF_KEY_M
: eDateMonth
= XML_DEA_SHORT
; break;
914 case NF_KEY_MM
: eDateMonth
= XML_DEA_LONG
; break;
915 case NF_KEY_MMM
: eDateMonth
= XML_DEA_TEXTSHORT
; break;
916 case NF_KEY_MMMM
: eDateMonth
= XML_DEA_TEXTLONG
; break;
917 case NF_KEY_YY
: eDateYear
= XML_DEA_SHORT
; break;
918 case NF_KEY_YYYY
: eDateYear
= XML_DEA_LONG
; break;
919 case NF_KEY_H
: eDateHours
= XML_DEA_SHORT
; break;
920 case NF_KEY_HH
: eDateHours
= XML_DEA_LONG
; break;
921 case NF_KEY_MI
: eDateMins
= XML_DEA_SHORT
; break;
922 case NF_KEY_MMI
: eDateMins
= XML_DEA_LONG
; break;
923 case NF_KEY_S
: eDateSecs
= XML_DEA_SHORT
; break;
924 case NF_KEY_SS
: eDateSecs
= XML_DEA_LONG
; break;
926 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
928 bDateNoDefault
= sal_True
; // any other element -> no default format
930 nLastType
= nElemType
;
934 if ( bDateNoDefault
)
935 return sal_False
; // additional elements
938 NfIndexTableOffset eFound
= (NfIndexTableOffset
) SvXMLNumFmtDefaults::GetDefaultDateFormat(
939 eDateDOW
, eDateDay
, eDateMonth
, eDateYear
, eDateHours
, eDateMins
, eDateSecs
, bSystemDate
);
941 return ( eFound
== eBuiltIn
);
946 // export one part (condition)
949 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
,
950 sal_uInt16 nPart
, sal_Bool bDefPart
)
952 //! for the default part, pass the coditions from the other parts!
958 NfIndexTableOffset eBuiltIn
= pFormatter
->GetIndexTableOffset( nKey
);
961 bool bThousand
= false;
962 sal_uInt16 nPrecision
= 0;
963 sal_uInt16 nLeading
= 0;
964 rFormat
.GetNumForInfo( nPart
, nFmtType
, bThousand
, nPrecision
, nLeading
);
965 nFmtType
&= ~NUMBERFORMAT_DEFINED
;
967 // special treatment of builtin formats that aren't detected by normal parsing
968 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
969 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
970 nFmtType
= NUMBERFORMAT_NUMBER
;
971 else if ( eBuiltIn
== NF_BOOLEAN
)
972 nFmtType
= NUMBERFORMAT_LOGICAL
;
973 else if ( eBuiltIn
== NF_TEXT
)
974 nFmtType
= NUMBERFORMAT_TEXT
;
976 // #101606# An empty subformat is a valid number-style resulting in an
977 // empty display string for the condition of the subformat.
978 if ( nFmtType
== NUMBERFORMAT_UNDEFINED
&& rFormat
.GetNumForType( nPart
,
979 0, sal_False
) == 0 )
982 XMLTokenEnum eType
= XML_TOKEN_INVALID
;
985 // type is 0 if a format contains no recognized elements
986 // (like text only) - this is handled as a number-style.
988 case NUMBERFORMAT_NUMBER
:
989 case NUMBERFORMAT_SCIENTIFIC
:
990 case NUMBERFORMAT_FRACTION
:
991 eType
= XML_NUMBER_STYLE
;
993 case NUMBERFORMAT_PERCENT
:
994 eType
= XML_PERCENTAGE_STYLE
;
996 case NUMBERFORMAT_CURRENCY
:
997 eType
= XML_CURRENCY_STYLE
;
999 case NUMBERFORMAT_DATE
:
1000 case NUMBERFORMAT_DATETIME
:
1001 eType
= XML_DATE_STYLE
;
1003 case NUMBERFORMAT_TIME
:
1004 eType
= XML_TIME_STYLE
;
1006 case NUMBERFORMAT_TEXT
:
1007 eType
= XML_TEXT_STYLE
;
1009 case NUMBERFORMAT_LOGICAL
:
1010 eType
= XML_BOOLEAN_STYLE
;
1013 DBG_ASSERT( eType
!= XML_TOKEN_INVALID
, "unknown format type" );
1015 OUString sAttrValue
;
1016 sal_Bool bUserDef
= ( ( rFormat
.GetType() & NUMBERFORMAT_DEFINED
) != 0 );
1019 // common attributes for format
1022 // format name (generated from key) - style namespace
1023 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
1024 lcl_CreateStyleName( nKey
, nPart
, bDefPart
, sPrefix
) );
1026 // "volatile" attribute for styles used only in maps
1028 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_VOLATILE
, XML_TRUE
);
1030 // language / country
1031 LanguageType nLang
= rFormat
.GetLanguage();
1032 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
1035 // titles for builtin formats are not written
1036 sAttrValue
= rFormat
.GetComment();
1037 if ( !sAttrValue
.isEmpty() && bUserDef
&& bDefPart
)
1039 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TITLE
, sAttrValue
);
1042 // automatic ordering for currency and date formats
1043 // only used for some built-in formats
1044 sal_Bool bAutoOrder
= ( eBuiltIn
== NF_CURRENCY_1000INT
|| eBuiltIn
== NF_CURRENCY_1000DEC2
||
1045 eBuiltIn
== NF_CURRENCY_1000INT_RED
|| eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1046 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
||
1047 eBuiltIn
== NF_DATE_SYSTEM_SHORT
|| eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1048 eBuiltIn
== NF_DATE_SYS_MMYY
|| eBuiltIn
== NF_DATE_SYS_DDMMM
||
1049 eBuiltIn
== NF_DATE_SYS_DDMMYYYY
|| eBuiltIn
== NF_DATE_SYS_DDMMYY
||
1050 eBuiltIn
== NF_DATE_SYS_DMMMYY
|| eBuiltIn
== NF_DATE_SYS_DMMMYYYY
||
1051 eBuiltIn
== NF_DATE_SYS_DMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNDMMMYY
||
1052 eBuiltIn
== NF_DATE_SYS_NNDMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNNNDMMMMYYYY
||
1053 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
|| eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
1055 // format source (for date and time formats)
1056 // only used for some built-in formats
1057 sal_Bool bSystemDate
= ( eBuiltIn
== NF_DATE_SYSTEM_SHORT
||
1058 eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1059 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
);
1060 sal_Bool bLongSysDate
= ( eBuiltIn
== NF_DATE_SYSTEM_LONG
);
1062 // check if the format definition matches the key
1063 if ( bAutoOrder
&& ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) &&
1064 !lcl_IsDefaultDateFormat( rFormat
, bSystemDate
, eBuiltIn
) )
1066 bAutoOrder
= bSystemDate
= bLongSysDate
= sal_False
; // don't write automatic-order attribute then
1070 ( nFmtType
== NUMBERFORMAT_CURRENCY
|| nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) )
1072 // #85109# format type must be checked to avoid dtd errors if
1073 // locale data contains other format types at the built-in positions
1075 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_AUTOMATIC_ORDER
,
1079 if ( bSystemDate
&& bAutoOrder
&&
1080 ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) )
1082 // #85109# format type must be checked to avoid dtd errors if
1083 // locale data contains other format types at the built-in positions
1085 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_FORMAT_SOURCE
,
1089 // overflow for time formats as in [hh]:mm
1090 // controlled by bThousand from number format info
1091 // default for truncate-on-overflow is true
1092 if ( nFmtType
== NUMBERFORMAT_TIME
&& bThousand
)
1094 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRUNCATE_ON_OVERFLOW
,
1099 // Native number transliteration
1101 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr
;
1102 rFormat
.GetNatNumXml( aAttr
, nPart
);
1103 if ( !aAttr
.Format
.isEmpty() )
1105 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_FORMAT
,
1107 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1108 aAttr
.Locale
.Language
);
1109 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1110 aAttr
.Locale
.Country
);
1111 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_STYLE
,
1118 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, eType
,
1119 sal_True
, sal_True
);
1122 // color (properties element)
1125 const Color
* pCol
= rFormat
.GetColor( nPart
);
1127 WriteColorElement_Impl(*pCol
);
1130 // detect if there is "real" content, excluding color and maps
1131 //! move to implementation of Write... methods?
1132 sal_Bool bAnyContent
= sal_False
;
1138 SvXMLEmbeddedTextEntryArr aEmbeddedEntries
;
1139 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1141 // default number format contains just one number element
1142 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1143 bAnyContent
= sal_True
;
1145 else if ( eBuiltIn
== NF_BOOLEAN
)
1147 // boolean format contains just one boolean element
1148 WriteBooleanElement_Impl();
1149 bAnyContent
= sal_True
;
1153 // first loop to collect attributes
1155 sal_Bool bDecDashes
= sal_False
;
1156 sal_Bool bVarDecimals
= sal_False
;
1157 sal_Bool bExpFound
= sal_False
;
1158 sal_Bool bCurrFound
= sal_False
;
1159 sal_Bool bInInteger
= sal_True
;
1160 sal_Int32 nExpDigits
= 0;
1161 sal_Int32 nIntegerSymbols
= 0; // for embedded-text, including "#"
1162 sal_Int32 nTrailingThousands
= 0; // thousands-separators after all digits
1165 sal_uInt16 nPos
= 0;
1166 sal_Bool bEnd
= sal_False
;
1169 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1170 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1172 switch ( nElemType
)
1175 bEnd
= sal_True
; // end of format reached
1177 case NF_SYMBOLTYPE_DIGIT
:
1178 if ( bExpFound
&& pElemStr
)
1179 nExpDigits
+= pElemStr
->Len();
1180 else if ( !bDecDashes
&& pElemStr
&& pElemStr
->GetChar(0) == '-' )
1181 bDecDashes
= sal_True
;
1182 else if ( !bVarDecimals
&& !bInInteger
&& pElemStr
&& pElemStr
->GetChar(0) == '#' )
1184 // If the decimal digits string starts with a '#', variable
1185 // decimals is assumed (for 0.###, but not 0.0##).
1186 bVarDecimals
= sal_True
;
1188 if ( bInInteger
&& pElemStr
)
1189 nIntegerSymbols
+= pElemStr
->Len();
1190 nTrailingThousands
= 0;
1192 case NF_SYMBOLTYPE_DECSEP
:
1193 bInInteger
= sal_False
;
1195 case NF_SYMBOLTYPE_THSEP
:
1197 nTrailingThousands
+= pElemStr
->Len(); // is reset to 0 if digits follow
1199 case NF_SYMBOLTYPE_EXP
:
1200 bExpFound
= sal_True
; // following digits are exponent digits
1201 bInInteger
= sal_False
;
1203 case NF_SYMBOLTYPE_CURRENCY
:
1204 bCurrFound
= sal_True
;
1206 case NF_SYMBOLTYPE_CURREXT
:
1208 sCurrExt
= *pElemStr
;
1211 // E, EE, R, RR: select non-gregorian calendar
1212 // AAA, AAAA: calendar is switched at the position of the element
1217 if (aCalendar
.isEmpty())
1218 aCalendar
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1224 // collect strings for embedded-text (must be known before number element is written)
1226 sal_Bool bAllowEmbedded
= ( nFmtType
== 0 || nFmtType
== NUMBERFORMAT_NUMBER
||
1227 nFmtType
== NUMBERFORMAT_CURRENCY
||
1228 nFmtType
== NUMBERFORMAT_PERCENT
);
1229 if ( bAllowEmbedded
)
1231 sal_Int32 nDigitsPassed
= 0;
1236 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1237 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1239 switch ( nElemType
)
1242 bEnd
= sal_True
; // end of format reached
1244 case NF_SYMBOLTYPE_DIGIT
:
1246 nDigitsPassed
+= pElemStr
->Len();
1248 case NF_SYMBOLTYPE_STRING
:
1249 case NF_SYMBOLTYPE_BLANK
:
1250 case NF_SYMBOLTYPE_PERCENT
:
1251 if ( nDigitsPassed
> 0 && nDigitsPassed
< nIntegerSymbols
&& pElemStr
)
1253 // text (literal or underscore) within the integer part of a number:number element
1255 String aEmbeddedStr
;
1256 if ( nElemType
== NF_SYMBOLTYPE_STRING
|| nElemType
== NF_SYMBOLTYPE_PERCENT
)
1257 aEmbeddedStr
= *pElemStr
;
1259 SvNumberformat::InsertBlanks( aEmbeddedStr
, 0, pElemStr
->GetChar(1) );
1261 sal_Int32 nEmbedPos
= nIntegerSymbols
- nDigitsPassed
;
1263 SvXMLEmbeddedTextEntry
* pObj
= new SvXMLEmbeddedTextEntry( nPos
, nEmbedPos
, aEmbeddedStr
);
1264 aEmbeddedEntries
.push_back( pObj
);
1272 // final loop to write elements
1274 sal_Bool bNumWritten
= sal_False
;
1275 sal_Bool bCurrencyWritten
= sal_False
;
1276 short nPrevType
= 0;
1281 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1282 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1284 switch ( nElemType
)
1287 bEnd
= sal_True
; // end of format reached
1289 case NF_SYMBOLTYPE_STRING
:
1290 case NF_SYMBOLTYPE_DATESEP
:
1291 case NF_SYMBOLTYPE_TIMESEP
:
1292 case NF_SYMBOLTYPE_TIME100SECSEP
:
1293 case NF_SYMBOLTYPE_PERCENT
:
1296 if ( ( nPrevType
== NF_KEY_S
|| nPrevType
== NF_KEY_SS
) &&
1297 ( nElemType
== NF_SYMBOLTYPE_TIME100SECSEP
) &&
1300 // decimal separator after seconds is implied by
1301 // "decimal-places" attribute and must not be written
1303 //! difference between '.' and ',' is lost here
1305 else if ( lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1307 // text is written as embedded-text child of the number,
1308 // don't create a text element
1310 else if ( nFmtType
== NUMBERFORMAT_CURRENCY
&& !bCurrFound
&& !bCurrencyWritten
)
1312 // automatic currency symbol is implemented as part of
1313 // normal text -> search for the symbol
1314 bCurrencyWritten
= WriteTextWithCurrency_Impl( *pElemStr
,
1315 MsLangId::convertLanguageToLocale( nLang
) );
1316 bAnyContent
= sal_True
;
1319 AddToTextElement_Impl( *pElemStr
);
1322 case NF_SYMBOLTYPE_BLANK
:
1323 if ( pElemStr
&& !lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1325 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1326 // (#i20396# the spaces may also be in embedded-text elements)
1329 SvNumberformat::InsertBlanks( aBlanks
, 0, pElemStr
->GetChar(1) );
1330 AddToTextElement_Impl( aBlanks
);
1333 case NF_KEY_GENERAL
:
1334 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1339 if ( bCurrencyWritten
)
1340 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1343 //! must be different from short automatic format
1344 //! but should still be empty (meaning automatic)
1345 // pElemStr is "CCC"
1347 WriteCurrencyElement_Impl( *pElemStr
, OUString() );
1348 bAnyContent
= sal_True
;
1349 bCurrencyWritten
= sal_True
;
1353 case NF_SYMBOLTYPE_CURRENCY
:
1356 if ( bCurrencyWritten
)
1357 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1360 WriteCurrencyElement_Impl( *pElemStr
, sCurrExt
);
1361 bAnyContent
= sal_True
;
1362 bCurrencyWritten
= sal_True
;
1366 case NF_SYMBOLTYPE_DIGIT
:
1367 if (!bNumWritten
) // write number part
1371 // for type 0 (not recognized as a special type),
1372 // write a "normal" number
1374 case NUMBERFORMAT_NUMBER
:
1375 case NUMBERFORMAT_CURRENCY
:
1376 case NUMBERFORMAT_PERCENT
:
1379 // only some built-in formats have automatic decimals
1380 sal_Int32 nDecimals
= nPrecision
; // from GetFormatSpecialInfo
1381 if ( eBuiltIn
== NF_NUMBER_STANDARD
||
1382 eBuiltIn
== NF_CURRENCY_1000DEC2
||
1383 eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1384 eBuiltIn
== NF_CURRENCY_1000DEC2_CCC
||
1385 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
)
1389 // only one built-in format has automatic integer digits
1390 sal_Int32 nInteger
= nLeading
;
1391 if ( eBuiltIn
== NF_NUMBER_SYSTEM
)
1394 // string for decimal replacement
1395 // has to be taken from nPrecision
1396 // (positive number even for automatic decimals)
1398 if ( bDecDashes
&& nPrecision
> 0 )
1399 sDashStr
.Fill( nPrecision
, '-' );
1401 WriteNumberElement_Impl( nDecimals
, nInteger
, sDashStr
, bVarDecimals
,
1402 bThousand
, nTrailingThousands
, aEmbeddedEntries
);
1403 bAnyContent
= sal_True
;
1406 case NUMBERFORMAT_SCIENTIFIC
:
1407 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1408 // as integer digits: use nIntegerSymbols instead of nLeading
1409 // (use of '#' to select multiples in exponent might be added later)
1410 WriteScientificElement_Impl( nPrecision
, nIntegerSymbols
, bThousand
, nExpDigits
);
1411 bAnyContent
= sal_True
;
1413 case NUMBERFORMAT_FRACTION
:
1415 sal_Int32 nInteger
= nLeading
;
1416 if ( pElemStr
&& pElemStr
->GetChar(0) == '?' )
1418 // If the first digit character is a question mark,
1419 // the fraction doesn't have an integer part, and no
1420 // min-integer-digits attribute must be written.
1423 sal_Int32 nDenominator
= rFormat
.GetForcedDenominatorForType( nPart
);
1424 WriteFractionElement_Impl( nInteger
, bThousand
, nPrecision
, nPrecision
, nDenominator
);
1425 bAnyContent
= sal_True
;
1430 bNumWritten
= sal_True
;
1433 case NF_SYMBOLTYPE_DECSEP
:
1434 if ( pElemStr
&& nPrecision
== 0 )
1436 // A decimal separator after the number, without following decimal digits,
1437 // isn't modelled as part of the number element, so it's written as text
1438 // (the distinction between a quoted and non-quoted, locale-dependent
1439 // character is lost here).
1441 AddToTextElement_Impl( *pElemStr
);
1444 case NF_SYMBOLTYPE_DEL
:
1445 if ( pElemStr
&& *pElemStr
== XubString('@') )
1447 WriteTextContentElement_Impl();
1448 bAnyContent
= sal_True
;
1452 case NF_SYMBOLTYPE_CALENDAR
:
1454 aCalendar
= *pElemStr
;
1462 sal_Bool bLong
= ( nElemType
== NF_KEY_DD
);
1463 WriteDayElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1464 bAnyContent
= sal_True
;
1475 OUString aCalAttr
= aCalendar
;
1476 if ( nElemType
== NF_KEY_AAA
|| nElemType
== NF_KEY_AAAA
)
1478 // calendar attribute for AAA and AAAA is switched only for this element
1479 if (aCalAttr
.isEmpty())
1480 aCalAttr
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1483 sal_Bool bLong
= ( nElemType
== NF_KEY_NNN
|| nElemType
== NF_KEY_NNNN
||
1484 nElemType
== NF_KEY_DDDD
|| nElemType
== NF_KEY_AAAA
);
1485 WriteDayOfWeekElement_Impl( aCalAttr
, ( bSystemDate
? bLongSysDate
: bLong
) );
1486 bAnyContent
= sal_True
;
1487 if ( nElemType
== NF_KEY_NNNN
)
1489 // write additional text element for separator
1490 pLocaleData
->setLocale( MsLangId::convertLanguageToLocale( nLang
) );
1491 AddToTextElement_Impl( pLocaleData
->getLongDateDayOfWeekSep() );
1499 case NF_KEY_MMMMM
: //! first letter of month name, no attribute available
1501 sal_Bool bLong
= ( nElemType
== NF_KEY_MM
|| nElemType
== NF_KEY_MMMM
);
1502 sal_Bool bText
= ( nElemType
== NF_KEY_MMM
|| nElemType
== NF_KEY_MMMM
||
1503 nElemType
== NF_KEY_MMMMM
);
1504 WriteMonthElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
), bText
);
1505 bAnyContent
= sal_True
;
1512 case NF_KEY_R
: //! R acts as EE, no attribute available
1514 //! distinguish EE and R
1515 // calendar attribute for E and EE and R is set in first loop
1516 sal_Bool bLong
= ( nElemType
== NF_KEY_YYYY
|| nElemType
== NF_KEY_EEC
||
1517 nElemType
== NF_KEY_R
);
1518 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1519 bAnyContent
= sal_True
;
1525 case NF_KEY_RR
: //! RR acts as GGGEE, no attribute available
1527 //! distinguish GG and GGG and RR
1528 sal_Bool bLong
= ( nElemType
== NF_KEY_GGG
|| nElemType
== NF_KEY_RR
);
1529 WriteEraElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1530 bAnyContent
= sal_True
;
1531 if ( nElemType
== NF_KEY_RR
)
1533 // calendar attribute for RR is set in first loop
1534 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: sal_True
) );
1541 sal_Bool bLong
= ( nElemType
== NF_KEY_QQ
);
1542 WriteQuarterElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1543 bAnyContent
= sal_True
;
1547 WriteWeekElement_Impl( aCalendar
);
1548 bAnyContent
= sal_True
;
1551 // time elements (bSystemDate is not used):
1555 WriteHoursElement_Impl( nElemType
== NF_KEY_HH
);
1556 bAnyContent
= sal_True
;
1560 WriteMinutesElement_Impl( nElemType
== NF_KEY_MMI
);
1561 bAnyContent
= sal_True
;
1565 WriteSecondsElement_Impl( ( nElemType
== NF_KEY_SS
), nPrecision
);
1566 bAnyContent
= sal_True
;
1570 WriteAMPMElement_Impl(); // short/long?
1571 bAnyContent
= sal_True
;
1574 nPrevType
= nElemType
;
1579 if ( sTextContent
.getLength() )
1580 bAnyContent
= sal_True
; // element written in FinishTextElement_Impl
1582 FinishTextElement_Impl(); // final text element - before maps
1586 // for an empty format, write an empty text element
1587 SvXMLElementExport
aTElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
1588 sal_True
, sal_False
);
1592 // mapping (conditions) must be last elements
1597 SvNumberformatLimitOps eOp1
, eOp2
;
1598 double fLimit1
, fLimit2
;
1599 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1601 WriteMapElement_Impl( eOp1
, fLimit1
, nKey
, 0 );
1602 WriteMapElement_Impl( eOp2
, fLimit2
, nKey
, 1 );
1604 if ( rFormat
.HasTextFormat() )
1606 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1607 // by reversing the 2nd condition
1609 SvNumberformatLimitOps eOp3
= NUMBERFORMAT_OP_NO
;
1610 double fLimit3
= fLimit2
;
1613 case NUMBERFORMAT_OP_EQ
: eOp3
= NUMBERFORMAT_OP_NE
; break;
1614 case NUMBERFORMAT_OP_NE
: eOp3
= NUMBERFORMAT_OP_EQ
; break;
1615 case NUMBERFORMAT_OP_LT
: eOp3
= NUMBERFORMAT_OP_GE
; break;
1616 case NUMBERFORMAT_OP_LE
: eOp3
= NUMBERFORMAT_OP_GT
; break;
1617 case NUMBERFORMAT_OP_GT
: eOp3
= NUMBERFORMAT_OP_LE
; break;
1618 case NUMBERFORMAT_OP_GE
: eOp3
= NUMBERFORMAT_OP_LT
; break;
1623 if ( fLimit1
== fLimit2
&&
1624 ( ( eOp1
== NUMBERFORMAT_OP_LT
&& eOp2
== NUMBERFORMAT_OP_GT
) ||
1625 ( eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_LT
) ) )
1627 // For <x and >x, add =x as last condition
1628 // (just for readability, <=x would be valid, too)
1630 eOp3
= NUMBERFORMAT_OP_EQ
;
1633 WriteMapElement_Impl( eOp3
, fLimit3
, nKey
, 2 );
1638 //-------------------------------------------------------------------------
1641 // export one format
1644 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
)
1646 sal_uInt16 nUsedParts
= 0;
1648 for (nPart
=0; nPart
<XMLNUM_MAX_PARTS
; nPart
++)
1649 if (rFormat
.GetNumForType( nPart
, 0, sal_False
) != 0)
1650 nUsedParts
= nPart
+1;
1652 SvNumberformatLimitOps eOp1
, eOp2
;
1653 double fLimit1
, fLimit2
;
1654 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1656 // if conditions are set, even empty formats must be written
1658 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 2 )
1660 if ( eOp2
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 3 )
1662 if ( rFormat
.HasTextFormat() && nUsedParts
< 4 )
1665 for (nPart
=0; nPart
<nUsedParts
; nPart
++)
1667 sal_Bool bDefault
= ( nPart
+1 == nUsedParts
); // last = default
1668 ExportPart_Impl( rFormat
, nKey
, nPart
, bDefault
);
1672 //-------------------------------------------------------------------------
1675 // export method called by application
1678 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle
)
1681 return; // no formatter -> no entries
1684 const SvNumberformat
* pFormat
= NULL
;
1685 sal_Bool
bNext(pUsedList
->GetFirstUsed(nKey
));
1688 pFormat
= pFormatter
->GetEntry(nKey
);
1690 ExportFormat_Impl( *pFormat
, nKey
);
1691 bNext
= pUsedList
->GetNextUsed(nKey
);
1695 std::vector
<sal_uInt16
> aLanguages
;
1696 pFormatter
->GetUsedLanguages( aLanguages
);
1697 for (std::vector
<sal_uInt16
>::const_iterator
it(aLanguages
.begin()); it
!= aLanguages
.end(); ++it
)
1699 LanguageType nLang
= *it
;
1701 sal_uInt32 nDefaultIndex
= 0;
1702 SvNumberFormatTable
& rTable
= pFormatter
->GetEntryTable(
1703 NUMBERFORMAT_DEFINED
, nDefaultIndex
, nLang
);
1704 SvNumberFormatTable::iterator it2
= rTable
.begin();
1705 while (it2
!= rTable
.end())
1708 pFormat
= it2
->second
;
1709 if (!pUsedList
->IsUsed(nKey
))
1711 DBG_ASSERT((pFormat
->GetType() & NUMBERFORMAT_DEFINED
) != 0, "a not user defined numberformat found");
1712 // user-defined and used formats are exported
1713 ExportFormat_Impl( *pFormat
, nKey
);
1714 // if it is a user-defined Format it will be added else nothing will hapen
1715 pUsedList
->SetUsed(nKey
);
1722 pUsedList
->Export();
1725 OUString
SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey
)
1727 if(pUsedList
->IsUsed(nKey
) || pUsedList
->IsWasUsed(nKey
))
1728 return lcl_CreateStyleName( nKey
, 0, sal_True
, sPrefix
);
1731 OSL_FAIL("There is no written Data-Style");
1732 return rtl::OUString();
1736 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey
)
1738 DBG_ASSERT( pFormatter
!= NULL
, "missing formatter" );
1742 if (pFormatter
->GetEntry(nKey
))
1743 pUsedList
->SetUsed( nKey
);
1745 OSL_FAIL("no existing Numberformat found with this key");
1749 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
1752 pUsedList
->GetWasUsed(rWasUsed
);
1755 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
1758 pUsedList
->SetWasUsed(rWasUsed
);
1763 const SvNumberformat
* lcl_GetFormat( SvNumberFormatter
* pFormatter
,
1766 return ( pFormatter
!= NULL
) ? pFormatter
->GetEntry( nKey
) : NULL
;
1769 sal_uInt32
SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey
)
1771 sal_uInt32 nRet
= nKey
;
1773 const SvNumberformat
* pFormat
= lcl_GetFormat( pFormatter
, nKey
);
1774 if( pFormat
!= NULL
)
1776 DBG_ASSERT( pFormatter
!= NULL
, "format without formatter?" );
1778 xub_StrLen nErrorPos
;
1779 short nType
= pFormat
->GetType();
1781 sal_uInt32 nNewKey
= pFormatter
->GetFormatForLanguageIfBuiltIn(
1782 nKey
, LANGUAGE_SYSTEM
);
1784 if( nNewKey
!= nKey
)
1790 String
aFormatString( pFormat
->GetFormatstring() );
1791 pFormatter
->PutandConvertEntry(
1793 nErrorPos
, nType
, nNewKey
,
1794 pFormat
->GetLanguage(), LANGUAGE_SYSTEM
);
1796 // success? Then use new key.
1797 if( nErrorPos
== 0 )
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */