1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xmlnumfe.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmloff.hxx"
34 #define _SVSTDARR_ULONGS
35 #define _ZFORLIST_DECLARE_TABLE
37 #include <svtools/svstdarr.hxx>
38 #include <svtools/zforlist.hxx>
39 #include <svtools/zformat.hxx>
40 #include <svtools/numuno.hxx>
41 #include <i18npool/mslangid.hxx>
42 #include <tools/debug.hxx>
43 #include <rtl/math.hxx>
44 #include <unotools/calendarwrapper.hxx>
45 #include <unotools/charclass.hxx>
46 #include <com/sun/star/lang/Locale.hpp>
47 #include <rtl/ustrbuf.hxx>
50 //#include <comphelper/processfactory.hxx>
52 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
54 #include <xmloff/xmlnumfe.hxx>
55 #include "xmlnmspe.hxx"
56 #include <xmloff/xmluconv.hxx>
57 #include <xmloff/attrlist.hxx>
58 #include <xmloff/nmspmap.hxx>
59 #include <xmloff/families.hxx>
60 #include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults
62 #define _SVSTDARR_USHORTS
63 #include <svtools/svstdarr.hxx>
64 #include <svtools/nfsymbol.hxx>
65 #include <xmloff/xmltoken.hxx>
66 #include <xmloff/xmlexp.hxx>
70 using ::rtl::OUString
;
71 using ::rtl::OUStringBuffer
;
73 using namespace ::com::sun::star
;
74 using namespace ::xmloff::token
;
75 using namespace ::svt
;
77 //-------------------------------------------------------------------------
79 // 4th condition for text formats doesn't work
80 //#define XMLNUM_MAX_PARTS 4
81 #define XMLNUM_MAX_PARTS 3
83 //-------------------------------------------------------------------------
87 sal_Bool
operator() (const sal_uInt32 rValue1
, const sal_uInt32 rValue2
) const
89 return rValue1
< rValue2
;
93 typedef std::set
< sal_uInt32
, LessuInt32
> SvXMLuInt32Set
;
95 class SvXMLNumUsedList_Impl
98 SvXMLuInt32Set aWasUsed
;
99 SvXMLuInt32Set::iterator aCurrentUsedPos
;
100 sal_uInt32 nUsedCount
;
101 sal_uInt32 nWasUsedCount
;
104 SvXMLNumUsedList_Impl();
105 ~SvXMLNumUsedList_Impl();
107 void SetUsed( sal_uInt32 nKey
);
108 sal_Bool
IsUsed( sal_uInt32 nKey
) const;
109 sal_Bool
IsWasUsed( sal_uInt32 nKey
) const;
112 sal_Bool
GetFirstUsed(sal_uInt32
& nKey
);
113 sal_Bool
GetNextUsed(sal_uInt32
& nKey
);
115 void GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
);
116 void SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
);
119 //-------------------------------------------------------------------------
121 struct SvXMLEmbeddedTextEntry
123 sal_uInt16 nSourcePos
; // position in NumberFormat (to skip later)
124 sal_Int32 nFormatPos
; // resulting position in embedded-text element
127 SvXMLEmbeddedTextEntry( sal_uInt16 nSP
, sal_Int32 nFP
, const rtl::OUString
& rT
) :
128 nSourcePos(nSP
), nFormatPos(nFP
), aText(rT
) {}
131 typedef SvXMLEmbeddedTextEntry
* SvXMLEmbeddedTextEntryPtr
;
132 SV_DECL_PTRARR_DEL( SvXMLEmbeddedTextEntryArr
, SvXMLEmbeddedTextEntryPtr
, 4, 4 )
134 //-------------------------------------------------------------------------
136 SV_IMPL_PTRARR( SvXMLEmbeddedTextEntryArr
, SvXMLEmbeddedTextEntryPtr
);
138 //-------------------------------------------------------------------------
141 //! SvXMLNumUsedList_Impl should be optimized!
144 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
150 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
154 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey
)
156 if ( !IsWasUsed(nKey
) )
158 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aUsed
.insert( nKey
);
164 sal_Bool
SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey
) const
166 SvXMLuInt32Set::iterator aItr
= aUsed
.find(nKey
);
167 return (aItr
!= aUsed
.end());
170 sal_Bool
SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey
) const
172 SvXMLuInt32Set::iterator aItr
= aWasUsed
.find(nKey
);
173 return (aItr
!= aWasUsed
.end());
176 void SvXMLNumUsedList_Impl::Export()
178 SvXMLuInt32Set::iterator aItr
= aUsed
.begin();
179 while (aItr
!= aUsed
.end())
181 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aWasUsed
.insert( *aItr
);
190 sal_Bool
SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32
& nKey
)
192 sal_Bool
bRet(sal_False
);
193 aCurrentUsedPos
= aUsed
.begin();
196 DBG_ASSERT(aCurrentUsedPos
!= aUsed
.end(), "something went wrong");
197 nKey
= *aCurrentUsedPos
;
203 sal_Bool
SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32
& nKey
)
205 sal_Bool
bRet(sal_False
);
206 if (aCurrentUsedPos
!= aUsed
.end())
209 if (aCurrentUsedPos
!= aUsed
.end())
211 nKey
= *aCurrentUsedPos
;
218 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
220 rWasUsed
.realloc(nWasUsedCount
);
221 sal_Int32
* pWasUsed
= rWasUsed
.getArray();
224 SvXMLuInt32Set::iterator aItr
= aWasUsed
.begin();
225 while (aItr
!= aWasUsed
.end())
234 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
236 DBG_ASSERT(nWasUsedCount
== 0, "WasUsed should be empty");
237 sal_Int32
nCount(rWasUsed
.getLength());
238 const sal_Int32
* pWasUsed
= rWasUsed
.getConstArray();
239 for (sal_uInt16 i
= 0; i
< nCount
; i
++, pWasUsed
++)
241 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aWasUsed
.insert( *pWasUsed
);
247 //-------------------------------------------------------------------------
249 SvXMLNumFmtExport::SvXMLNumFmtExport(
251 const uno::Reference
< util::XNumberFormatsSupplier
>& rSupp
) :
253 sPrefix( OUString::createFromAscii( "N" ) ),
258 // supplier must be SvNumberFormatsSupplierObj
259 SvNumberFormatsSupplierObj
* pObj
=
260 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
262 pFormatter
= pObj
->GetNumberFormatter();
266 pCharClass
= new CharClass( pFormatter
->GetServiceManager(),
267 pFormatter
->GetLocale() );
268 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetServiceManager(),
269 pFormatter
->GetLocale() );
273 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
276 // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
277 // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
278 pCharClass
= new CharClass( rExport
.getServiceFactory(), aLocale
);
279 pLocaleData
= new LocaleDataWrapper( rExport
.getServiceFactory(), aLocale
);
282 pUsedList
= new SvXMLNumUsedList_Impl
;
285 SvXMLNumFmtExport::SvXMLNumFmtExport(
287 const ::com::sun::star::uno::Reference
<
288 ::com::sun::star::util::XNumberFormatsSupplier
>& rSupp
,
289 const rtl::OUString
& rPrefix
) :
296 // supplier must be SvNumberFormatsSupplierObj
297 SvNumberFormatsSupplierObj
* pObj
=
298 SvNumberFormatsSupplierObj::getImplementation( rSupp
);
300 pFormatter
= pObj
->GetNumberFormatter();
304 pCharClass
= new CharClass( pFormatter
->GetServiceManager(),
305 pFormatter
->GetLocale() );
306 pLocaleData
= new LocaleDataWrapper( pFormatter
->GetServiceManager(),
307 pFormatter
->GetLocale() );
311 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
314 // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
315 // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
316 pCharClass
= new CharClass( rExport
.getServiceFactory(), aLocale
);
317 pLocaleData
= new LocaleDataWrapper( rExport
.getServiceFactory(), aLocale
);
320 pUsedList
= new SvXMLNumUsedList_Impl
;
323 SvXMLNumFmtExport::~SvXMLNumFmtExport()
330 //-------------------------------------------------------------------------
336 OUString
lcl_CreateStyleName( sal_Int32 nKey
, sal_Int32 nPart
, sal_Bool bDefPart
, const rtl::OUString
& rPrefix
)
338 OUStringBuffer
aFmtName( 10L );
339 aFmtName
.append( rPrefix
);
340 aFmtName
.append( nKey
);
343 aFmtName
.append( (sal_Unicode
)'P' );
344 aFmtName
.append( nPart
);
346 return aFmtName
.makeStringAndClear();
349 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString
& rCalendar
)
351 if ( rCalendar
.getLength() )
353 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_CALENDAR
, rCalendar
);
357 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText
)
359 if ( bText
) // non-textual
361 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TEXTUAL
, XML_TRUE
);
365 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong
)
367 if ( bLong
) // short is default
369 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_STYLE
, XML_LONG
);
373 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang
)
375 if ( nLang
!= LANGUAGE_SYSTEM
)
377 OUString aLangStr
, aCountryStr
;
378 MsLangId::convertLanguageToIsoNames( (LanguageType
)nLang
, aLangStr
, aCountryStr
);
380 if (aLangStr
.getLength())
381 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_LANGUAGE
, aLangStr
);
382 if (aCountryStr
.getLength())
383 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_COUNTRY
, aCountryStr
);
387 //-------------------------------------------------------------------------
390 // methods to write individual elements within a format
393 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString
& rString
)
395 // append to sTextContent, write element in FinishTextElement_Impl
396 // to avoid several text elements following each other
398 sTextContent
.append( rString
);
401 void SvXMLNumFmtExport::FinishTextElement_Impl()
403 if ( sTextContent
.getLength() )
405 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
406 sal_True
, sal_False
);
407 rExport
.Characters( sTextContent
.makeStringAndClear() );
411 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color
& rColor
)
413 FinishTextElement_Impl();
415 OUStringBuffer
aColStr( 7 );
416 SvXMLUnitConverter::convertColor( aColStr
, rColor
);
417 rExport
.AddAttribute( XML_NAMESPACE_FO
, XML_COLOR
,
418 aColStr
.makeStringAndClear() );
420 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_TEXT_PROPERTIES
,
421 sal_True
, sal_False
);
424 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString
& rString
,
425 const OUString
& rExt
)
427 FinishTextElement_Impl();
429 if ( rExt
.getLength() )
431 sal_Int32 nLang
= rExt
.toInt32(16); // hex
432 if ( nLang
< 0 ) // extension string may contain "-" separator
434 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
437 SvXMLElementExport
aElem( rExport
,
438 XML_NAMESPACE_NUMBER
, XML_CURRENCY_SYMBOL
,
439 sal_True
, sal_False
);
440 rExport
.Characters( rString
);
443 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
445 FinishTextElement_Impl();
447 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_BOOLEAN
,
448 sal_True
, sal_False
);
451 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
453 FinishTextElement_Impl();
455 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT_CONTENT
,
456 sal_True
, sal_False
);
461 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
463 FinishTextElement_Impl();
465 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
466 AddStyleAttr_Impl( bLong
); // adds to pAttrList
468 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY
,
469 sal_True
, sal_False
);
472 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
, sal_Bool bText
)
474 FinishTextElement_Impl();
476 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
477 AddStyleAttr_Impl( bLong
); // adds to pAttrList
478 AddTextualAttr_Impl( bText
); // adds to pAttrList
480 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MONTH
,
481 sal_True
, sal_False
);
484 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
486 FinishTextElement_Impl();
488 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
489 AddStyleAttr_Impl( bLong
); // adds to pAttrList
491 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_YEAR
,
492 sal_True
, sal_False
);
495 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
497 FinishTextElement_Impl();
499 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
500 AddStyleAttr_Impl( bLong
); // adds to pAttrList
502 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_ERA
,
503 sal_True
, sal_False
);
506 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
508 FinishTextElement_Impl();
510 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
511 AddStyleAttr_Impl( bLong
); // adds to pAttrList
513 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY_OF_WEEK
,
514 sal_True
, sal_False
);
517 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString
& rCalendar
)
519 FinishTextElement_Impl();
521 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
523 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_WEEK_OF_YEAR
,
524 sal_True
, sal_False
);
527 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString
& rCalendar
, sal_Bool bLong
)
529 FinishTextElement_Impl();
531 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
532 AddStyleAttr_Impl( bLong
); // adds to pAttrList
534 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_QUARTER
,
535 sal_True
, sal_False
);
540 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong
)
542 FinishTextElement_Impl();
544 AddStyleAttr_Impl( bLong
); // adds to pAttrList
546 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_HOURS
,
547 sal_True
, sal_False
);
550 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong
)
552 FinishTextElement_Impl();
554 AddStyleAttr_Impl( bLong
); // adds to pAttrList
556 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MINUTES
,
557 sal_True
, sal_False
);
560 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong
, sal_uInt16 nDecimals
)
562 FinishTextElement_Impl();
564 AddStyleAttr_Impl( bLong
); // adds to pAttrList
567 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
568 OUString::valueOf( (sal_Int32
) nDecimals
) );
571 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_SECONDS
,
572 sal_True
, sal_False
);
575 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
577 FinishTextElement_Impl();
579 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_AM_PM
,
580 sal_True
, sal_False
);
585 void SvXMLNumFmtExport::WriteNumberElement_Impl(
586 sal_Int32 nDecimals
, sal_Int32 nInteger
,
587 const OUString
& rDashStr
, sal_Bool bVarDecimals
,
588 sal_Bool bGrouping
, sal_Int32 nTrailingThousands
,
589 const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
)
591 FinishTextElement_Impl();
594 if ( nDecimals
>= 0 ) // negative = automatic
596 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
597 OUString::valueOf( nDecimals
) );
601 if ( nInteger
>= 0 ) // negative = automatic
603 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
604 OUString::valueOf( nInteger
) );
607 // decimal replacement (dashes) or variable decimals (#)
608 if ( rDashStr
.getLength() || bVarDecimals
)
610 // variable decimals means an empty replacement string
611 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_REPLACEMENT
,
615 // (automatic) grouping separator
618 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
621 // display-factor if there are trailing thousands separators
622 if ( nTrailingThousands
)
624 // each separator character removes three digits
625 double fFactor
= ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands
);
627 OUStringBuffer aFactStr
;
628 SvXMLUnitConverter::convertDouble( aFactStr
, fFactor
);
629 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DISPLAY_FACTOR
, aFactStr
.makeStringAndClear() );
632 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_NUMBER
,
633 sal_True
, sal_True
);
635 // number:embedded-text as child elements
637 sal_uInt16 nEntryCount
= rEmbeddedEntries
.Count();
638 for (sal_uInt16 nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
640 SvXMLEmbeddedTextEntry
* pObj
= rEmbeddedEntries
[nEntry
];
642 // position attribute
643 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_POSITION
,
644 OUString::valueOf( pObj
->nFormatPos
) );
645 SvXMLElementExport
aChildElem( rExport
, XML_NAMESPACE_NUMBER
, XML_EMBEDDED_TEXT
,
646 sal_True
, sal_False
);
648 // text as element content
649 rtl::OUString
aContent( pObj
->aText
);
650 while ( nEntry
+1 < nEntryCount
&& rEmbeddedEntries
[nEntry
+1]->nFormatPos
== pObj
->nFormatPos
)
652 // The array can contain several elements for the same position in the number
653 // (for example, literal text and space from underscores). They must be merged
654 // into a single embedded-text element.
655 aContent
+= rEmbeddedEntries
[nEntry
+1]->aText
;
658 rExport
.Characters( aContent
);
662 void SvXMLNumFmtExport::WriteScientificElement_Impl(
663 sal_Int32 nDecimals
, sal_Int32 nInteger
,
664 sal_Bool bGrouping
, sal_Int32 nExp
)
666 FinishTextElement_Impl();
669 if ( nDecimals
>= 0 ) // negative = automatic
671 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
672 OUString::valueOf( nDecimals
) );
676 if ( nInteger
>= 0 ) // negative = automatic
678 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
679 OUString::valueOf( nInteger
) );
682 // (automatic) grouping separator
685 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
691 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_EXPONENT_DIGITS
,
692 OUString::valueOf( nExp
) );
695 SvXMLElementExport
aElem( rExport
,
696 XML_NAMESPACE_NUMBER
, XML_SCIENTIFIC_NUMBER
,
697 sal_True
, sal_False
);
700 void SvXMLNumFmtExport::WriteFractionElement_Impl(
701 sal_Int32 nInteger
, sal_Bool bGrouping
,
702 sal_Int32 nNumerator
, sal_Int32 nDenominator
)
704 FinishTextElement_Impl();
707 if ( nInteger
>= 0 ) // negative = default (no integer part)
709 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
710 OUString::valueOf( nInteger
) );
713 // (automatic) grouping separator
716 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
720 if ( nNumerator
>= 0 )
722 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_NUMERATOR_DIGITS
,
723 OUString::valueOf( nNumerator
) );
726 // denominator digits
727 if ( nDenominator
>= 0 )
729 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_DENOMINATOR_DIGITS
,
730 OUString::valueOf( nDenominator
) );
733 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_FRACTION
,
734 sal_True
, sal_False
);
737 // mapping (condition)
739 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp
, double fLimit
,
740 sal_Int32 nKey
, sal_Int32 nPart
)
742 FinishTextElement_Impl();
744 if ( nOp
!= NUMBERFORMAT_OP_NO
)
748 OUStringBuffer
aCondStr( 20L );
749 aCondStr
.appendAscii( "value()" ); //! define constant
752 case NUMBERFORMAT_OP_EQ
: aCondStr
.append( (sal_Unicode
) '=' ); break;
753 case NUMBERFORMAT_OP_NE
: aCondStr
.appendAscii( "<>" ); break;
754 case NUMBERFORMAT_OP_LT
: aCondStr
.append( (sal_Unicode
) '<' ); break;
755 case NUMBERFORMAT_OP_LE
: aCondStr
.appendAscii( "<=" ); break;
756 case NUMBERFORMAT_OP_GT
: aCondStr
.append( (sal_Unicode
) '>' ); break;
757 case NUMBERFORMAT_OP_GE
: aCondStr
.appendAscii( ">=" ); break;
759 DBG_ERROR("unknown operator");
761 ::rtl::math::doubleToUStringBuffer( aCondStr
, fLimit
,
762 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
765 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_CONDITION
,
766 aCondStr
.makeStringAndClear() );
768 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_APPLY_STYLE_NAME
,
769 rExport
.EncodeStyleName( lcl_CreateStyleName( nKey
, nPart
, sal_False
,
772 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_MAP
,
773 sal_True
, sal_False
);
777 //-------------------------------------------------------------------------
778 // for old (automatic) currency formats: parse currency symbol from text
780 xub_StrLen
lcl_FindSymbol( const String
& sUpperStr
, const String
& sCurString
)
782 // search for currency symbol
783 // Quoting as in ImpSvNumberformatScan::Symbol_Division
785 xub_StrLen nCPos
= 0;
786 while (nCPos
!= STRING_NOTFOUND
)
788 nCPos
= sUpperStr
.Search( sCurString
, nCPos
);
789 if (nCPos
!= STRING_NOTFOUND
)
792 xub_StrLen nQ
= SvNumberformat::GetQuoteEnd( sUpperStr
, nCPos
);
793 if ( nQ
== STRING_NOTFOUND
)
795 // dm can be escaped as "dm or \d
798 ((c
= sUpperStr
.GetChar(xub_StrLen(nCPos
-1))) != '"'
801 return nCPos
; // found
807 nCPos
= nQ
+ 1; // continue after quote end
810 return STRING_NOTFOUND
; // not found
813 sal_Bool
SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString
& rString
,
814 const ::com::sun::star::lang::Locale
& rLocale
)
816 // returns TRUE if currency element was written
818 sal_Bool bRet
= sal_False
;
820 // pLocaleData->setLocale( rLocale );
821 // String sCurString = pLocaleData->getCurrSymbol();
823 LanguageType nLang
= MsLangId::convertLocaleToLanguage( rLocale
);
824 pFormatter
->ChangeIntl( nLang
);
825 String sCurString
, sDummy
;
826 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
828 pCharClass
->setLocale( rLocale
);
829 String sUpperStr
= pCharClass
->upper(rString
);
830 xub_StrLen nPos
= lcl_FindSymbol( sUpperStr
, sCurString
);
831 if ( nPos
!= STRING_NOTFOUND
)
833 sal_Int32 nLength
= rString
.getLength();
834 sal_Int32 nCurLen
= sCurString
.Len();
835 sal_Int32 nCont
= nPos
+ nCurLen
;
837 // text before currency symbol
839 AddToTextElement_Impl( rString
.copy( 0, nPos
) );
841 // currency symbol (empty string -> default)
843 WriteCurrencyElement_Impl( sEmpty
, sEmpty
);
846 // text after currency symbol
847 if ( nCont
< nLength
)
848 AddToTextElement_Impl( rString
.copy( nCont
, nLength
-nCont
) );
851 AddToTextElement_Impl( rString
); // simple text
853 return bRet
; // TRUE: currency element written
856 //-------------------------------------------------------------------------
858 OUString
lcl_GetDefaultCalendar( SvNumberFormatter
* pFormatter
, LanguageType nLang
)
860 // get name of first non-gregorian calendar for the language
863 CalendarWrapper
* pCalendar
= pFormatter
->GetCalendar();
866 lang::Locale
aLocale( MsLangId::convertLanguageToLocale( nLang
) );
868 uno::Sequence
<OUString
> aCals
= pCalendar
->getAllCalendars( aLocale
);
869 sal_Int32 nCnt
= aCals
.getLength();
870 sal_Bool bFound
= sal_False
;
871 for ( sal_Int32 j
=0; j
< nCnt
&& !bFound
; j
++ )
873 if ( !aCals
[j
].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gregorian") ) )
875 aCalendar
= aCals
[j
];
883 //-------------------------------------------------------------------------
885 sal_Bool
lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
, sal_uInt16 nPos
)
887 sal_uInt16 nCount
= rEmbeddedEntries
.Count();
888 for (sal_uInt16 i
=0; i
<nCount
; i
++)
889 if ( rEmbeddedEntries
[i
]->nSourcePos
== nPos
)
892 return sal_False
; // not found
895 BOOL
lcl_IsDefaultDateFormat( const SvNumberformat
& rFormat
, sal_Bool bSystemDate
, NfIndexTableOffset eBuiltIn
)
897 // make an extra loop to collect date elements, to check if it is a default format
898 // before adding the automatic-order attribute
900 SvXMLDateElementAttributes eDateDOW
= XML_DEA_NONE
;
901 SvXMLDateElementAttributes eDateDay
= XML_DEA_NONE
;
902 SvXMLDateElementAttributes eDateMonth
= XML_DEA_NONE
;
903 SvXMLDateElementAttributes eDateYear
= XML_DEA_NONE
;
904 SvXMLDateElementAttributes eDateHours
= XML_DEA_NONE
;
905 SvXMLDateElementAttributes eDateMins
= XML_DEA_NONE
;
906 SvXMLDateElementAttributes eDateSecs
= XML_DEA_NONE
;
907 sal_Bool bDateNoDefault
= sal_False
;
910 sal_Bool bEnd
= sal_False
;
914 short nElemType
= rFormat
.GetNumForType( 0, nPos
, sal_False
);
918 if ( nLastType
== NF_SYMBOLTYPE_STRING
)
919 bDateNoDefault
= sal_True
; // text at the end -> no default date format
920 bEnd
= sal_True
; // end of format reached
922 case NF_SYMBOLTYPE_STRING
:
923 case NF_SYMBOLTYPE_DATESEP
:
924 case NF_SYMBOLTYPE_TIMESEP
:
925 case NF_SYMBOLTYPE_TIME100SECSEP
:
926 // text is ignored, except at the end
928 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
929 case NF_KEY_NN
: eDateDOW
= XML_DEA_SHORT
; break;
931 case NF_KEY_NNNN
: eDateDOW
= XML_DEA_LONG
; break;
932 case NF_KEY_D
: eDateDay
= XML_DEA_SHORT
; break;
933 case NF_KEY_DD
: eDateDay
= XML_DEA_LONG
; break;
934 case NF_KEY_M
: eDateMonth
= XML_DEA_SHORT
; break;
935 case NF_KEY_MM
: eDateMonth
= XML_DEA_LONG
; break;
936 case NF_KEY_MMM
: eDateMonth
= XML_DEA_TEXTSHORT
; break;
937 case NF_KEY_MMMM
: eDateMonth
= XML_DEA_TEXTLONG
; break;
938 case NF_KEY_YY
: eDateYear
= XML_DEA_SHORT
; break;
939 case NF_KEY_YYYY
: eDateYear
= XML_DEA_LONG
; break;
940 case NF_KEY_H
: eDateHours
= XML_DEA_SHORT
; break;
941 case NF_KEY_HH
: eDateHours
= XML_DEA_LONG
; break;
942 case NF_KEY_MI
: eDateMins
= XML_DEA_SHORT
; break;
943 case NF_KEY_MMI
: eDateMins
= XML_DEA_LONG
; break;
944 case NF_KEY_S
: eDateSecs
= XML_DEA_SHORT
; break;
945 case NF_KEY_SS
: eDateSecs
= XML_DEA_LONG
; break;
947 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
949 bDateNoDefault
= sal_True
; // any other element -> no default format
951 nLastType
= nElemType
;
955 if ( bDateNoDefault
)
956 return FALSE
; // additional elements
959 NfIndexTableOffset eFound
= (NfIndexTableOffset
) SvXMLNumFmtDefaults::GetDefaultDateFormat(
960 eDateDOW
, eDateDay
, eDateMonth
, eDateYear
, eDateHours
, eDateMins
, eDateSecs
, bSystemDate
);
962 return ( eFound
== eBuiltIn
);
967 // export one part (condition)
970 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
,
971 sal_uInt16 nPart
, sal_Bool bDefPart
)
973 //! for the default part, pass the coditions from the other parts!
979 NfIndexTableOffset eBuiltIn
= pFormatter
->GetIndexTableOffset( nKey
);
982 sal_Bool bThousand
= sal_False
;
983 sal_uInt16 nPrecision
= 0;
984 sal_uInt16 nLeading
= 0;
985 rFormat
.GetNumForInfo( nPart
, nFmtType
, bThousand
, nPrecision
, nLeading
);
986 nFmtType
&= ~NUMBERFORMAT_DEFINED
;
988 // special treatment of builtin formats that aren't detected by normal parsing
989 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
990 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
991 nFmtType
= NUMBERFORMAT_NUMBER
;
992 else if ( eBuiltIn
== NF_BOOLEAN
)
993 nFmtType
= NUMBERFORMAT_LOGICAL
;
994 else if ( eBuiltIn
== NF_TEXT
)
995 nFmtType
= NUMBERFORMAT_TEXT
;
997 // #101606# An empty subformat is a valid number-style resulting in an
998 // empty display string for the condition of the subformat.
999 if ( nFmtType
== NUMBERFORMAT_UNDEFINED
&& rFormat
.GetNumForType( nPart
,
1000 0, sal_False
) == 0 )
1003 XMLTokenEnum eType
= XML_TOKEN_INVALID
;
1006 // type is 0 if a format contains no recognized elements
1007 // (like text only) - this is handled as a number-style.
1009 case NUMBERFORMAT_NUMBER
:
1010 case NUMBERFORMAT_SCIENTIFIC
:
1011 case NUMBERFORMAT_FRACTION
:
1012 eType
= XML_NUMBER_STYLE
;
1014 case NUMBERFORMAT_PERCENT
:
1015 eType
= XML_PERCENTAGE_STYLE
;
1017 case NUMBERFORMAT_CURRENCY
:
1018 eType
= XML_CURRENCY_STYLE
;
1020 case NUMBERFORMAT_DATE
:
1021 case NUMBERFORMAT_DATETIME
:
1022 eType
= XML_DATE_STYLE
;
1024 case NUMBERFORMAT_TIME
:
1025 eType
= XML_TIME_STYLE
;
1027 case NUMBERFORMAT_TEXT
:
1028 eType
= XML_TEXT_STYLE
;
1030 case NUMBERFORMAT_LOGICAL
:
1031 eType
= XML_BOOLEAN_STYLE
;
1034 DBG_ASSERT( eType
!= XML_TOKEN_INVALID
, "unknown format type" );
1036 OUString sAttrValue
;
1037 sal_Bool bUserDef
= ( ( rFormat
.GetType() & NUMBERFORMAT_DEFINED
) != 0 );
1040 // common attributes for format
1043 // format name (generated from key) - style namespace
1044 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
1045 lcl_CreateStyleName( nKey
, nPart
, bDefPart
, sPrefix
) );
1047 // "volatile" attribute for styles used only in maps
1049 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_VOLATILE
, XML_TRUE
);
1051 // language / country
1052 LanguageType nLang
= rFormat
.GetLanguage();
1053 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
1056 // titles for builtin formats are not written
1057 sAttrValue
= rFormat
.GetComment();
1058 if ( sAttrValue
.getLength() && bUserDef
&& bDefPart
)
1060 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TITLE
, sAttrValue
);
1063 // automatic ordering for currency and date formats
1064 // only used for some built-in formats
1065 BOOL bAutoOrder
= ( eBuiltIn
== NF_CURRENCY_1000INT
|| eBuiltIn
== NF_CURRENCY_1000DEC2
||
1066 eBuiltIn
== NF_CURRENCY_1000INT_RED
|| eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1067 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
||
1068 eBuiltIn
== NF_DATE_SYSTEM_SHORT
|| eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1069 eBuiltIn
== NF_DATE_SYS_MMYY
|| eBuiltIn
== NF_DATE_SYS_DDMMM
||
1070 eBuiltIn
== NF_DATE_SYS_DDMMYYYY
|| eBuiltIn
== NF_DATE_SYS_DDMMYY
||
1071 eBuiltIn
== NF_DATE_SYS_DMMMYY
|| eBuiltIn
== NF_DATE_SYS_DMMMYYYY
||
1072 eBuiltIn
== NF_DATE_SYS_DMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNDMMMYY
||
1073 eBuiltIn
== NF_DATE_SYS_NNDMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNNNDMMMMYYYY
||
1074 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
|| eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
1076 // format source (for date and time formats)
1077 // only used for some built-in formats
1078 BOOL bSystemDate
= ( eBuiltIn
== NF_DATE_SYSTEM_SHORT
||
1079 eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1080 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
);
1081 BOOL bLongSysDate
= ( eBuiltIn
== NF_DATE_SYSTEM_LONG
);
1083 // check if the format definition matches the key
1084 if ( bAutoOrder
&& ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) &&
1085 !lcl_IsDefaultDateFormat( rFormat
, bSystemDate
, eBuiltIn
) )
1087 bAutoOrder
= bSystemDate
= bLongSysDate
= FALSE
; // don't write automatic-order attribute then
1091 ( nFmtType
== NUMBERFORMAT_CURRENCY
|| nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== NUMBERFORMAT_DATETIME
) )
1093 // #85109# format type must be checked to avoid dtd errors if
1094 // locale data contains other format types at the built-in positions
1096 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_AUTOMATIC_ORDER
,
1100 if ( bSystemDate
&& bAutoOrder
&&
1101 ( nFmtType
== NUMBERFORMAT_DATE
|| nFmtType
== 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_FORMAT_SOURCE
,
1110 // overflow for time formats as in [hh]:mm
1111 // controlled by bThousand from number format info
1112 // default for truncate-on-overflow is true
1113 if ( nFmtType
== NUMBERFORMAT_TIME
&& bThousand
)
1115 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRUNCATE_ON_OVERFLOW
,
1120 // Native number transliteration
1122 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr
;
1123 rFormat
.GetNatNumXml( aAttr
, nPart
);
1124 if ( aAttr
.Format
.getLength() )
1126 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_FORMAT
,
1128 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1129 aAttr
.Locale
.Language
);
1130 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1131 aAttr
.Locale
.Country
);
1132 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_STYLE
,
1139 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, eType
,
1140 sal_True
, sal_True
);
1143 // color (properties element)
1146 const Color
* pCol
= rFormat
.GetColor( nPart
);
1148 WriteColorElement_Impl(*pCol
);
1151 // detect if there is "real" content, excluding color and maps
1152 //! move to implementation of Write... methods?
1153 sal_Bool bAnyContent
= sal_False
;
1159 SvXMLEmbeddedTextEntryArr
aEmbeddedEntries(0);
1160 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1162 // default number format contains just one number element
1163 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1164 bAnyContent
= sal_True
;
1166 else if ( eBuiltIn
== NF_BOOLEAN
)
1168 // boolean format contains just one boolean element
1169 WriteBooleanElement_Impl();
1170 bAnyContent
= sal_True
;
1174 // first loop to collect attributes
1176 sal_Bool bDecDashes
= sal_False
;
1177 sal_Bool bVarDecimals
= sal_False
;
1178 sal_Bool bExpFound
= sal_False
;
1179 sal_Bool bCurrFound
= sal_False
;
1180 sal_Bool bInInteger
= sal_True
;
1181 sal_Int32 nExpDigits
= 0;
1182 sal_Int32 nIntegerSymbols
= 0; // for embedded-text, including "#"
1183 sal_Int32 nTrailingThousands
= 0; // thousands-separators after all digits
1186 sal_uInt16 nPos
= 0;
1187 sal_Bool bEnd
= sal_False
;
1190 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1191 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1193 switch ( nElemType
)
1196 bEnd
= sal_True
; // end of format reached
1198 case NF_SYMBOLTYPE_DIGIT
:
1199 if ( bExpFound
&& pElemStr
)
1200 nExpDigits
+= pElemStr
->Len();
1201 else if ( !bDecDashes
&& pElemStr
&& pElemStr
->GetChar(0) == '-' )
1203 else if ( !bVarDecimals
&& !bInInteger
&& pElemStr
&& pElemStr
->GetChar(0) == '#' )
1205 // If the decimal digits string starts with a '#', variable
1206 // decimals is assumed (for 0.###, but not 0.0##).
1207 bVarDecimals
= sal_True
;
1209 if ( bInInteger
&& pElemStr
)
1210 nIntegerSymbols
+= pElemStr
->Len();
1211 nTrailingThousands
= 0;
1213 case NF_SYMBOLTYPE_DECSEP
:
1214 bInInteger
= sal_False
;
1216 case NF_SYMBOLTYPE_THSEP
:
1218 nTrailingThousands
+= pElemStr
->Len(); // is reset to 0 if digits follow
1220 case NF_SYMBOLTYPE_EXP
:
1221 bExpFound
= sal_True
; // following digits are exponent digits
1222 bInInteger
= sal_False
;
1224 case NF_SYMBOLTYPE_CURRENCY
:
1227 case NF_SYMBOLTYPE_CURREXT
:
1229 sCurrExt
= *pElemStr
;
1232 // E, EE, R, RR: select non-gregorian calendar
1233 // AAA, AAAA: calendar is switched at the position of the element
1238 if (!aCalendar
.getLength())
1239 aCalendar
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1245 // collect strings for embedded-text (must be known before number element is written)
1247 sal_Bool bAllowEmbedded
= ( nFmtType
== 0 || nFmtType
== NUMBERFORMAT_NUMBER
||
1248 nFmtType
== NUMBERFORMAT_CURRENCY
||
1249 nFmtType
== NUMBERFORMAT_PERCENT
);
1250 if ( bAllowEmbedded
)
1252 sal_Int32 nDigitsPassed
= 0;
1257 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1258 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1260 switch ( nElemType
)
1263 bEnd
= sal_True
; // end of format reached
1265 case NF_SYMBOLTYPE_DIGIT
:
1267 nDigitsPassed
+= pElemStr
->Len();
1269 case NF_SYMBOLTYPE_STRING
:
1270 case NF_SYMBOLTYPE_BLANK
:
1271 case NF_SYMBOLTYPE_PERCENT
:
1272 if ( nDigitsPassed
> 0 && nDigitsPassed
< nIntegerSymbols
&& pElemStr
)
1274 // text (literal or underscore) within the integer part of a number:number element
1276 String aEmbeddedStr
;
1277 if ( nElemType
== NF_SYMBOLTYPE_STRING
|| nElemType
== NF_SYMBOLTYPE_PERCENT
)
1278 aEmbeddedStr
= *pElemStr
;
1280 SvNumberformat::InsertBlanks( aEmbeddedStr
, 0, pElemStr
->GetChar(1) );
1282 sal_Int32 nEmbedPos
= nIntegerSymbols
- nDigitsPassed
;
1284 SvXMLEmbeddedTextEntry
* pObj
= new SvXMLEmbeddedTextEntry( nPos
, nEmbedPos
, aEmbeddedStr
);
1285 aEmbeddedEntries
.Insert( pObj
, aEmbeddedEntries
.Count() );
1293 // final loop to write elements
1295 sal_Bool bNumWritten
= sal_False
;
1296 sal_Bool bCurrencyWritten
= sal_False
;
1297 short nPrevType
= 0;
1302 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
, sal_False
);
1303 const XubString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
, sal_False
);
1305 switch ( nElemType
)
1308 bEnd
= sal_True
; // end of format reached
1310 case NF_SYMBOLTYPE_STRING
:
1311 case NF_SYMBOLTYPE_DATESEP
:
1312 case NF_SYMBOLTYPE_TIMESEP
:
1313 case NF_SYMBOLTYPE_TIME100SECSEP
:
1314 case NF_SYMBOLTYPE_PERCENT
:
1317 if ( ( nPrevType
== NF_KEY_S
|| nPrevType
== NF_KEY_SS
) &&
1318 ( nElemType
== NF_SYMBOLTYPE_TIME100SECSEP
) &&
1321 // decimal separator after seconds is implied by
1322 // "decimal-places" attribute and must not be written
1324 //! difference between '.' and ',' is lost here
1326 else if ( lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1328 // text is written as embedded-text child of the number,
1329 // don't create a text element
1331 else if ( nFmtType
== NUMBERFORMAT_CURRENCY
&& !bCurrFound
&& !bCurrencyWritten
)
1333 // automatic currency symbol is implemented as part of
1334 // normal text -> search for the symbol
1335 bCurrencyWritten
= WriteTextWithCurrency_Impl( *pElemStr
,
1336 MsLangId::convertLanguageToLocale( nLang
) );
1337 bAnyContent
= sal_True
;
1340 AddToTextElement_Impl( *pElemStr
);
1343 case NF_SYMBOLTYPE_BLANK
:
1344 if ( pElemStr
&& !lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1346 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1347 // (#i20396# the spaces may also be in embedded-text elements)
1350 SvNumberformat::InsertBlanks( aBlanks
, 0, pElemStr
->GetChar(1) );
1351 AddToTextElement_Impl( aBlanks
);
1354 case NF_KEY_GENERAL
:
1355 WriteNumberElement_Impl( -1, 1, OUString(), sal_False
, sal_False
, 0, aEmbeddedEntries
);
1360 if ( bCurrencyWritten
)
1361 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1364 //! must be different from short automatic format
1365 //! but should still be empty (meaning automatic)
1366 // pElemStr is "CCC"
1368 WriteCurrencyElement_Impl( *pElemStr
, OUString() );
1369 bAnyContent
= sal_True
;
1370 bCurrencyWritten
= sal_True
;
1374 case NF_SYMBOLTYPE_CURRENCY
:
1377 if ( bCurrencyWritten
)
1378 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1381 WriteCurrencyElement_Impl( *pElemStr
, sCurrExt
);
1382 bAnyContent
= sal_True
;
1383 bCurrencyWritten
= sal_True
;
1387 case NF_SYMBOLTYPE_DIGIT
:
1388 if (!bNumWritten
) // write number part
1392 // for type 0 (not recognized as a special type),
1393 // write a "normal" number
1395 case NUMBERFORMAT_NUMBER
:
1396 case NUMBERFORMAT_CURRENCY
:
1397 case NUMBERFORMAT_PERCENT
:
1400 // only some built-in formats have automatic decimals
1401 sal_Int32 nDecimals
= nPrecision
; // from GetFormatSpecialInfo
1402 if ( eBuiltIn
== NF_NUMBER_STANDARD
||
1403 eBuiltIn
== NF_CURRENCY_1000DEC2
||
1404 eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1405 eBuiltIn
== NF_CURRENCY_1000DEC2_CCC
||
1406 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
)
1410 // only one built-in format has automatic integer digits
1411 sal_Int32 nInteger
= nLeading
;
1412 if ( eBuiltIn
== NF_NUMBER_SYSTEM
)
1415 // string for decimal replacement
1416 // has to be taken from nPrecision
1417 // (positive number even for automatic decimals)
1419 if ( bDecDashes
&& nPrecision
> 0 )
1420 sDashStr
.Fill( nPrecision
, '-' );
1422 WriteNumberElement_Impl( nDecimals
, nInteger
, sDashStr
, bVarDecimals
,
1423 bThousand
, nTrailingThousands
, aEmbeddedEntries
);
1424 bAnyContent
= sal_True
;
1427 case NUMBERFORMAT_SCIENTIFIC
:
1428 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1429 // as integer digits: use nIntegerSymbols instead of nLeading
1430 // (use of '#' to select multiples in exponent might be added later)
1431 WriteScientificElement_Impl( nPrecision
, nIntegerSymbols
, bThousand
, nExpDigits
);
1432 bAnyContent
= sal_True
;
1434 case NUMBERFORMAT_FRACTION
:
1436 sal_Int32 nInteger
= nLeading
;
1437 if ( pElemStr
&& pElemStr
->GetChar(0) == '?' )
1439 // If the first digit character is a question mark,
1440 // the fraction doesn't have an integer part, and no
1441 // min-integer-digits attribute must be written.
1444 WriteFractionElement_Impl( nInteger
, bThousand
, nPrecision
, nPrecision
);
1445 bAnyContent
= sal_True
;
1450 bNumWritten
= sal_True
;
1453 case NF_SYMBOLTYPE_DECSEP
:
1454 if ( pElemStr
&& nPrecision
== 0 )
1456 // A decimal separator after the number, without following decimal digits,
1457 // isn't modelled as part of the number element, so it's written as text
1458 // (the distinction between a quoted and non-quoted, locale-dependent
1459 // character is lost here).
1461 AddToTextElement_Impl( *pElemStr
);
1464 case NF_SYMBOLTYPE_DEL
:
1465 if ( pElemStr
&& *pElemStr
== XubString('@') )
1467 WriteTextContentElement_Impl();
1468 bAnyContent
= sal_True
;
1472 case NF_SYMBOLTYPE_CALENDAR
:
1474 aCalendar
= *pElemStr
;
1482 sal_Bool bLong
= ( nElemType
== NF_KEY_DD
);
1483 WriteDayElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1484 bAnyContent
= sal_True
;
1495 OUString aCalAttr
= aCalendar
;
1496 if ( nElemType
== NF_KEY_AAA
|| nElemType
== NF_KEY_AAAA
)
1498 // calendar attribute for AAA and AAAA is switched only for this element
1499 if (!aCalAttr
.getLength())
1500 aCalAttr
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1503 sal_Bool bLong
= ( nElemType
== NF_KEY_NNN
|| nElemType
== NF_KEY_NNNN
||
1504 nElemType
== NF_KEY_DDDD
|| nElemType
== NF_KEY_AAAA
);
1505 WriteDayOfWeekElement_Impl( aCalAttr
, ( bSystemDate
? bLongSysDate
: bLong
) );
1506 bAnyContent
= sal_True
;
1507 if ( nElemType
== NF_KEY_NNNN
)
1509 // write additional text element for separator
1510 pLocaleData
->setLocale( MsLangId::convertLanguageToLocale( nLang
) );
1511 AddToTextElement_Impl( pLocaleData
->getLongDateDayOfWeekSep() );
1519 case NF_KEY_MMMMM
: //! first letter of month name, no attribute available
1521 sal_Bool bLong
= ( nElemType
== NF_KEY_MM
|| nElemType
== NF_KEY_MMMM
);
1522 sal_Bool bText
= ( nElemType
== NF_KEY_MMM
|| nElemType
== NF_KEY_MMMM
||
1523 nElemType
== NF_KEY_MMMMM
);
1524 WriteMonthElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
), bText
);
1525 bAnyContent
= sal_True
;
1532 case NF_KEY_R
: //! R acts as EE, no attribute available
1534 //! distinguish EE and R
1535 // calendar attribute for E and EE and R is set in first loop
1536 sal_Bool bLong
= ( nElemType
== NF_KEY_YYYY
|| nElemType
== NF_KEY_EEC
||
1537 nElemType
== NF_KEY_R
);
1538 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1539 bAnyContent
= sal_True
;
1545 case NF_KEY_RR
: //! RR acts as GGGEE, no attribute available
1547 //! distinguish GG and GGG and RR
1548 sal_Bool bLong
= ( nElemType
== NF_KEY_GGG
|| nElemType
== NF_KEY_RR
);
1549 WriteEraElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1550 bAnyContent
= sal_True
;
1551 if ( nElemType
== NF_KEY_RR
)
1553 // calendar attribute for RR is set in first loop
1554 WriteYearElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: sal_True
) );
1561 sal_Bool bLong
= ( nElemType
== NF_KEY_QQ
);
1562 WriteQuarterElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1563 bAnyContent
= sal_True
;
1567 WriteWeekElement_Impl( aCalendar
);
1568 bAnyContent
= sal_True
;
1571 // time elements (bSystemDate is not used):
1575 WriteHoursElement_Impl( nElemType
== NF_KEY_HH
);
1576 bAnyContent
= sal_True
;
1580 WriteMinutesElement_Impl( nElemType
== NF_KEY_MMI
);
1581 bAnyContent
= sal_True
;
1585 WriteSecondsElement_Impl( ( nElemType
== NF_KEY_SS
), nPrecision
);
1586 bAnyContent
= sal_True
;
1590 WriteAMPMElement_Impl(); // short/long?
1591 bAnyContent
= sal_True
;
1594 nPrevType
= nElemType
;
1599 if ( sTextContent
.getLength() )
1600 bAnyContent
= sal_True
; // element written in FinishTextElement_Impl
1602 FinishTextElement_Impl(); // final text element - before maps
1606 // for an empty format, write an empty text element
1607 SvXMLElementExport
aTElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
1608 sal_True
, sal_False
);
1612 // mapping (conditions) must be last elements
1617 SvNumberformatLimitOps eOp1
, eOp2
;
1618 double fLimit1
, fLimit2
;
1619 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1621 WriteMapElement_Impl( eOp1
, fLimit1
, nKey
, 0 );
1622 WriteMapElement_Impl( eOp2
, fLimit2
, nKey
, 1 );
1624 if ( rFormat
.HasTextFormat() )
1626 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1627 // by reversing the 2nd condition
1629 SvNumberformatLimitOps eOp3
= NUMBERFORMAT_OP_NO
;
1630 double fLimit3
= fLimit2
;
1633 case NUMBERFORMAT_OP_EQ
: eOp3
= NUMBERFORMAT_OP_NE
; break;
1634 case NUMBERFORMAT_OP_NE
: eOp3
= NUMBERFORMAT_OP_EQ
; break;
1635 case NUMBERFORMAT_OP_LT
: eOp3
= NUMBERFORMAT_OP_GE
; break;
1636 case NUMBERFORMAT_OP_LE
: eOp3
= NUMBERFORMAT_OP_GT
; break;
1637 case NUMBERFORMAT_OP_GT
: eOp3
= NUMBERFORMAT_OP_LE
; break;
1638 case NUMBERFORMAT_OP_GE
: eOp3
= NUMBERFORMAT_OP_LT
; break;
1643 if ( fLimit1
== fLimit2
&&
1644 ( ( eOp1
== NUMBERFORMAT_OP_LT
&& eOp2
== NUMBERFORMAT_OP_GT
) ||
1645 ( eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_LT
) ) )
1647 // For <x and >x, add =x as last condition
1648 // (just for readability, <=x would be valid, too)
1650 eOp3
= NUMBERFORMAT_OP_EQ
;
1653 WriteMapElement_Impl( eOp3
, fLimit3
, nKey
, 2 );
1658 //-------------------------------------------------------------------------
1661 // export one format
1664 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
)
1666 sal_uInt16 nUsedParts
= 0;
1668 for (nPart
=0; nPart
<XMLNUM_MAX_PARTS
; nPart
++)
1669 if (rFormat
.GetNumForType( nPart
, 0, sal_False
) != 0)
1670 nUsedParts
= nPart
+1;
1672 SvNumberformatLimitOps eOp1
, eOp2
;
1673 double fLimit1
, fLimit2
;
1674 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1676 // if conditions are set, even empty formats must be written
1678 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 2 )
1680 if ( eOp2
!= NUMBERFORMAT_OP_NO
&& nUsedParts
< 3 )
1682 if ( rFormat
.HasTextFormat() && nUsedParts
< 4 )
1685 for (nPart
=0; nPart
<nUsedParts
; nPart
++)
1687 sal_Bool bDefault
= ( nPart
+1 == nUsedParts
); // last = default
1688 ExportPart_Impl( rFormat
, nKey
, nPart
, bDefault
);
1692 //-------------------------------------------------------------------------
1695 // export method called by application
1698 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle
)
1701 return; // no formatter -> no entries
1704 const SvNumberformat
* pFormat
= NULL
;
1705 sal_Bool
bNext(pUsedList
->GetFirstUsed(nKey
));
1708 pFormat
= pFormatter
->GetEntry(nKey
);
1710 ExportFormat_Impl( *pFormat
, nKey
);
1711 bNext
= pUsedList
->GetNextUsed(nKey
);
1715 SvUShorts aLanguages
;
1716 pFormatter
->GetUsedLanguages( aLanguages
);
1717 sal_uInt16 nLangCount
= aLanguages
.Count();
1718 for (sal_uInt16 nLangPos
=0; nLangPos
<nLangCount
; nLangPos
++)
1720 LanguageType nLang
= aLanguages
[nLangPos
];
1722 sal_uInt32 nDefaultIndex
= 0;
1723 SvNumberFormatTable
& rTable
= pFormatter
->GetEntryTable(
1724 NUMBERFORMAT_DEFINED
, nDefaultIndex
, nLang
);
1725 pFormat
= rTable
.First();
1728 nKey
= rTable
.GetCurKey();
1729 if (!pUsedList
->IsUsed(nKey
))
1731 DBG_ASSERT((pFormat
->GetType() & NUMBERFORMAT_DEFINED
) != 0, "a not user defined numberformat found");
1732 // user-defined and used formats are exported
1733 ExportFormat_Impl( *pFormat
, nKey
);
1734 // if it is a user-defined Format it will be added else nothing will hapen
1735 pUsedList
->SetUsed(nKey
);
1738 pFormat
= rTable
.Next();
1742 pUsedList
->Export();
1745 OUString
SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey
)
1747 if(pUsedList
->IsUsed(nKey
) || pUsedList
->IsWasUsed(nKey
))
1748 return lcl_CreateStyleName( nKey
, 0, sal_True
, sPrefix
);
1751 DBG_ERROR("There is no written Data-Style");
1752 return rtl::OUString();
1756 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey
)
1758 DBG_ASSERT( pFormatter
!= NULL
, "missing formatter" );
1762 if (pFormatter
->GetEntry(nKey
))
1763 pUsedList
->SetUsed( nKey
);
1765 DBG_ERROR("no existing Numberformat found with this key");
1769 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence
<sal_Int32
>& rWasUsed
)
1772 pUsedList
->GetWasUsed(rWasUsed
);
1775 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
1778 pUsedList
->SetWasUsed(rWasUsed
);
1783 const SvNumberformat
* lcl_GetFormat( SvNumberFormatter
* pFormatter
,
1786 return ( pFormatter
!= NULL
) ? pFormatter
->GetEntry( nKey
) : NULL
;
1789 sal_uInt32
SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey
)
1791 sal_uInt32 nRet
= nKey
;
1793 const SvNumberformat
* pFormat
= lcl_GetFormat( pFormatter
, nKey
);
1794 if( pFormat
!= NULL
)
1796 DBG_ASSERT( pFormatter
!= NULL
, "format without formatter?" );
1798 xub_StrLen nErrorPos
;
1799 short nType
= pFormat
->GetType();
1801 sal_uInt32 nNewKey
= pFormatter
->GetFormatForLanguageIfBuiltIn(
1802 nKey
, LANGUAGE_SYSTEM
);
1804 if( nNewKey
!= nKey
)
1810 String
aFormatString( pFormat
->GetFormatstring() );
1811 pFormatter
->PutandConvertEntry(
1813 nErrorPos
, nType
, nNewKey
,
1814 pFormat
->GetLanguage(), LANGUAGE_SYSTEM
);
1816 // success? Then use new key.
1817 if( nErrorPos
== 0 )