merge the formfield patch from ooo-build
[ooovba.git] / xmloff / source / style / xmlnumfe.cxx
blob1fb40b3d051fc0c3b4998e8ea6fc32494933b99f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xmlnumfe.cxx,v $
10 * $Revision: 1.51 $
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>
49 // #110680#
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>
68 #include <set>
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 //-------------------------------------------------------------------------
85 struct LessuInt32
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
97 SvXMLuInt32Set aUsed;
98 SvXMLuInt32Set aWasUsed;
99 SvXMLuInt32Set::iterator aCurrentUsedPos;
100 sal_uInt32 nUsedCount;
101 sal_uInt32 nWasUsedCount;
103 public:
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;
110 void Export();
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
125 rtl::OUString aText;
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() :
145 nUsedCount(0),
146 nWasUsedCount(0)
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 );
159 if (aPair.second)
160 nUsedCount++;
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 );
182 if (aPair.second)
183 nWasUsedCount++;
184 aItr++;
186 aUsed.clear();
187 nUsedCount = 0;
190 sal_Bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey)
192 sal_Bool bRet(sal_False);
193 aCurrentUsedPos = aUsed.begin();
194 if(nUsedCount)
196 DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
197 nKey = *aCurrentUsedPos;
198 bRet = sal_True;
200 return bRet;
203 sal_Bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey)
205 sal_Bool bRet(sal_False);
206 if (aCurrentUsedPos != aUsed.end())
208 aCurrentUsedPos++;
209 if (aCurrentUsedPos != aUsed.end())
211 nKey = *aCurrentUsedPos;
212 bRet = sal_True;
215 return bRet;
218 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
220 rWasUsed.realloc(nWasUsedCount);
221 sal_Int32* pWasUsed = rWasUsed.getArray();
222 if (pWasUsed)
224 SvXMLuInt32Set::iterator aItr = aWasUsed.begin();
225 while (aItr != aWasUsed.end())
227 *pWasUsed = *aItr;
228 aItr++;
229 pWasUsed++;
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 );
242 if (aPair.second)
243 nWasUsedCount++;
247 //-------------------------------------------------------------------------
249 SvXMLNumFmtExport::SvXMLNumFmtExport(
250 SvXMLExport& rExp,
251 const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
252 rExport( rExp ),
253 sPrefix( OUString::createFromAscii( "N" ) ),
254 pFormatter( NULL ),
255 pCharClass( NULL ),
256 pLocaleData( NULL )
258 // supplier must be SvNumberFormatsSupplierObj
259 SvNumberFormatsSupplierObj* pObj =
260 SvNumberFormatsSupplierObj::getImplementation( rSupp );
261 if (pObj)
262 pFormatter = pObj->GetNumberFormatter();
264 if ( pFormatter )
266 pCharClass = new CharClass( pFormatter->GetServiceManager(),
267 pFormatter->GetLocale() );
268 pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
269 pFormatter->GetLocale() );
271 else
273 lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
275 // #110680#
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(
286 SvXMLExport& rExp,
287 const ::com::sun::star::uno::Reference<
288 ::com::sun::star::util::XNumberFormatsSupplier >& rSupp,
289 const rtl::OUString& rPrefix ) :
290 rExport( rExp ),
291 sPrefix( rPrefix ),
292 pFormatter( NULL ),
293 pCharClass( NULL ),
294 pLocaleData( NULL )
296 // supplier must be SvNumberFormatsSupplierObj
297 SvNumberFormatsSupplierObj* pObj =
298 SvNumberFormatsSupplierObj::getImplementation( rSupp );
299 if (pObj)
300 pFormatter = pObj->GetNumberFormatter();
302 if ( pFormatter )
304 pCharClass = new CharClass( pFormatter->GetServiceManager(),
305 pFormatter->GetLocale() );
306 pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
307 pFormatter->GetLocale() );
309 else
311 lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
313 // #110680#
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()
325 delete pUsedList;
326 delete pLocaleData;
327 delete pCharClass;
330 //-------------------------------------------------------------------------
333 // helper methods
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 );
341 if (!bDefPart)
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
433 nLang = -nLang;
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 );
459 // date elements
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 );
538 // time elements
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
565 if ( nDecimals > 0 )
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 );
583 // numbers
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();
593 // decimals
594 if ( nDecimals >= 0 ) // negative = automatic
596 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
597 OUString::valueOf( nDecimals ) );
600 // integer digits
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,
612 rDashStr );
615 // (automatic) grouping separator
616 if ( bGrouping )
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;
656 ++nEntry;
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();
668 // decimals
669 if ( nDecimals >= 0 ) // negative = automatic
671 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
672 OUString::valueOf( nDecimals ) );
675 // integer digits
676 if ( nInteger >= 0 ) // negative = automatic
678 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
679 OUString::valueOf( nInteger ) );
682 // (automatic) grouping separator
683 if ( bGrouping )
685 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
688 // exponent digits
689 if ( nExp >= 0 )
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();
706 // integer digits
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
714 if ( bGrouping )
716 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
719 // numerator digits
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 )
746 // style namespace
748 OUStringBuffer aCondStr( 20L );
749 aCondStr.appendAscii( "value()" ); //! define constant
750 switch ( nOp )
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;
758 default:
759 DBG_ERROR("unknown operator");
761 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
762 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
763 '.', true );
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,
770 sPrefix ) ) );
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)
791 // in Quotes?
792 xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
793 if ( nQ == STRING_NOTFOUND )
795 // dm can be escaped as "dm or \d
796 sal_Unicode c;
797 if ( nCPos == 0 ||
798 ((c = sUpperStr.GetChar(xub_StrLen(nCPos-1))) != '"'
799 && c != '\\') )
801 return nCPos; // found
803 else
804 nCPos++; // continue
806 else
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
838 if ( nPos > 0 )
839 AddToTextElement_Impl( rString.copy( 0, nPos ) );
841 // currency symbol (empty string -> default)
842 OUString sEmpty;
843 WriteCurrencyElement_Impl( sEmpty, sEmpty );
844 bRet = sal_True;
846 // text after currency symbol
847 if ( nCont < nLength )
848 AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
850 else
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
862 OUString aCalendar;
863 CalendarWrapper* pCalendar = pFormatter->GetCalendar();
864 if (pCalendar)
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];
876 bFound = sal_True;
880 return aCalendar;
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 )
890 return sal_True;
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;
909 sal_uInt16 nPos = 0;
910 sal_Bool bEnd = sal_False;
911 short nLastType = 0;
912 while (!bEnd)
914 short nElemType = rFormat.GetNumForType( 0, nPos, sal_False );
915 switch ( nElemType )
917 case 0:
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
921 break;
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
927 break;
928 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
929 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
930 case NF_KEY_NNN:
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;
946 case NF_KEY_AP:
947 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
948 default:
949 bDateNoDefault = sal_True; // any other element -> no default format
951 nLastType = nElemType;
952 ++nPos;
955 if ( bDateNoDefault )
956 return FALSE; // additional elements
957 else
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!
976 // element name
979 NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
981 short nFmtType = 0;
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 )
1001 nFmtType = 0;
1003 XMLTokenEnum eType = XML_TOKEN_INVALID;
1004 switch ( nFmtType )
1006 // type is 0 if a format contains no recognized elements
1007 // (like text only) - this is handled as a number-style.
1008 case 0:
1009 case NUMBERFORMAT_NUMBER:
1010 case NUMBERFORMAT_SCIENTIFIC:
1011 case NUMBERFORMAT_FRACTION:
1012 eType = XML_NUMBER_STYLE;
1013 break;
1014 case NUMBERFORMAT_PERCENT:
1015 eType = XML_PERCENTAGE_STYLE;
1016 break;
1017 case NUMBERFORMAT_CURRENCY:
1018 eType = XML_CURRENCY_STYLE;
1019 break;
1020 case NUMBERFORMAT_DATE:
1021 case NUMBERFORMAT_DATETIME:
1022 eType = XML_DATE_STYLE;
1023 break;
1024 case NUMBERFORMAT_TIME:
1025 eType = XML_TIME_STYLE;
1026 break;
1027 case NUMBERFORMAT_TEXT:
1028 eType = XML_TEXT_STYLE;
1029 break;
1030 case NUMBERFORMAT_LOGICAL:
1031 eType = XML_BOOLEAN_STYLE;
1032 break;
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
1048 if ( !bDefPart )
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
1055 // title (comment)
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
1090 if ( bAutoOrder &&
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,
1097 XML_TRUE );
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,
1107 XML_LANGUAGE );
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,
1116 XML_FALSE );
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,
1127 aAttr.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,
1133 aAttr.Style );
1137 // The element
1139 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
1140 sal_True, sal_True );
1143 // color (properties element)
1146 const Color* pCol = rFormat.GetColor( nPart );
1147 if (pCol)
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;
1156 // format elements
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;
1172 else
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
1184 OUString sCurrExt;
1185 OUString aCalendar;
1186 sal_uInt16 nPos = 0;
1187 sal_Bool bEnd = sal_False;
1188 while (!bEnd)
1190 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1191 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1193 switch ( nElemType )
1195 case 0:
1196 bEnd = sal_True; // end of format reached
1197 break;
1198 case NF_SYMBOLTYPE_DIGIT:
1199 if ( bExpFound && pElemStr )
1200 nExpDigits += pElemStr->Len();
1201 else if ( !bDecDashes && pElemStr && pElemStr->GetChar(0) == '-' )
1202 bDecDashes = TRUE;
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;
1212 break;
1213 case NF_SYMBOLTYPE_DECSEP:
1214 bInInteger = sal_False;
1215 break;
1216 case NF_SYMBOLTYPE_THSEP:
1217 if (pElemStr)
1218 nTrailingThousands += pElemStr->Len(); // is reset to 0 if digits follow
1219 break;
1220 case NF_SYMBOLTYPE_EXP:
1221 bExpFound = sal_True; // following digits are exponent digits
1222 bInInteger = sal_False;
1223 break;
1224 case NF_SYMBOLTYPE_CURRENCY:
1225 bCurrFound = TRUE;
1226 break;
1227 case NF_SYMBOLTYPE_CURREXT:
1228 if (pElemStr)
1229 sCurrExt = *pElemStr;
1230 break;
1232 // E, EE, R, RR: select non-gregorian calendar
1233 // AAA, AAAA: calendar is switched at the position of the element
1234 case NF_KEY_EC:
1235 case NF_KEY_EEC:
1236 case NF_KEY_R:
1237 case NF_KEY_RR:
1238 if (!aCalendar.getLength())
1239 aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1240 break;
1242 ++nPos;
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;
1253 nPos = 0;
1254 bEnd = sal_False;
1255 while (!bEnd)
1257 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1258 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1260 switch ( nElemType )
1262 case 0:
1263 bEnd = sal_True; // end of format reached
1264 break;
1265 case NF_SYMBOLTYPE_DIGIT:
1266 if ( pElemStr )
1267 nDigitsPassed += pElemStr->Len();
1268 break;
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;
1279 else
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() );
1287 break;
1289 ++nPos;
1293 // final loop to write elements
1295 sal_Bool bNumWritten = sal_False;
1296 sal_Bool bCurrencyWritten = sal_False;
1297 short nPrevType = 0;
1298 nPos = 0;
1299 bEnd = sal_False;
1300 while (!bEnd)
1302 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1303 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1305 switch ( nElemType )
1307 case 0:
1308 bEnd = sal_True; // end of format reached
1309 break;
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:
1315 if (pElemStr)
1317 if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1318 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1319 nPrecision > 0 )
1321 // decimal separator after seconds is implied by
1322 // "decimal-places" attribute and must not be written
1323 // as text element
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;
1339 else
1340 AddToTextElement_Impl( *pElemStr );
1342 break;
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)
1349 String aBlanks;
1350 SvNumberformat::InsertBlanks( aBlanks, 0, pElemStr->GetChar(1) );
1351 AddToTextElement_Impl( aBlanks );
1353 break;
1354 case NF_KEY_GENERAL :
1355 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1356 break;
1357 case NF_KEY_CCC:
1358 if (pElemStr)
1360 if ( bCurrencyWritten )
1361 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1362 else
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;
1373 break;
1374 case NF_SYMBOLTYPE_CURRENCY:
1375 if (pElemStr)
1377 if ( bCurrencyWritten )
1378 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1379 else
1381 WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1382 bAnyContent = sal_True;
1383 bCurrencyWritten = sal_True;
1386 break;
1387 case NF_SYMBOLTYPE_DIGIT:
1388 if (!bNumWritten) // write number part
1390 switch ( nFmtType )
1392 // for type 0 (not recognized as a special type),
1393 // write a "normal" number
1394 case 0:
1395 case NUMBERFORMAT_NUMBER:
1396 case NUMBERFORMAT_CURRENCY:
1397 case NUMBERFORMAT_PERCENT:
1399 // decimals
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 )
1407 nDecimals = -1;
1409 // integer digits
1410 // only one built-in format has automatic integer digits
1411 sal_Int32 nInteger = nLeading;
1412 if ( eBuiltIn == NF_NUMBER_SYSTEM )
1413 nInteger = -1;
1415 // string for decimal replacement
1416 // has to be taken from nPrecision
1417 // (positive number even for automatic decimals)
1418 String sDashStr;
1419 if ( bDecDashes && nPrecision > 0 )
1420 sDashStr.Fill( nPrecision, '-' );
1422 WriteNumberElement_Impl( nDecimals, nInteger, sDashStr, bVarDecimals,
1423 bThousand, nTrailingThousands, aEmbeddedEntries );
1424 bAnyContent = sal_True;
1426 break;
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;
1433 break;
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.
1442 nInteger = -1;
1444 WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision );
1445 bAnyContent = sal_True;
1447 break;
1450 bNumWritten = sal_True;
1452 break;
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 );
1463 break;
1464 case NF_SYMBOLTYPE_DEL:
1465 if ( pElemStr && *pElemStr == XubString('@') )
1467 WriteTextContentElement_Impl();
1468 bAnyContent = sal_True;
1470 break;
1472 case NF_SYMBOLTYPE_CALENDAR:
1473 if ( pElemStr )
1474 aCalendar = *pElemStr;
1475 break;
1477 // date elements:
1479 case NF_KEY_D:
1480 case NF_KEY_DD:
1482 sal_Bool bLong = ( nElemType == NF_KEY_DD );
1483 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1484 bAnyContent = sal_True;
1486 break;
1487 case NF_KEY_DDD:
1488 case NF_KEY_DDDD:
1489 case NF_KEY_NN:
1490 case NF_KEY_NNN:
1491 case NF_KEY_NNNN:
1492 case NF_KEY_AAA:
1493 case NF_KEY_AAAA:
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() );
1514 break;
1515 case NF_KEY_M:
1516 case NF_KEY_MM:
1517 case NF_KEY_MMM:
1518 case NF_KEY_MMMM:
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;
1527 break;
1528 case NF_KEY_YY:
1529 case NF_KEY_YYYY:
1530 case NF_KEY_EC:
1531 case NF_KEY_EEC:
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;
1541 break;
1542 case NF_KEY_G:
1543 case NF_KEY_GG:
1544 case NF_KEY_GGG:
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 ) );
1557 break;
1558 case NF_KEY_Q:
1559 case NF_KEY_QQ:
1561 sal_Bool bLong = ( nElemType == NF_KEY_QQ );
1562 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1563 bAnyContent = sal_True;
1565 break;
1566 case NF_KEY_WW:
1567 WriteWeekElement_Impl( aCalendar );
1568 bAnyContent = sal_True;
1569 break;
1571 // time elements (bSystemDate is not used):
1573 case NF_KEY_H:
1574 case NF_KEY_HH:
1575 WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1576 bAnyContent = sal_True;
1577 break;
1578 case NF_KEY_MI:
1579 case NF_KEY_MMI:
1580 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1581 bAnyContent = sal_True;
1582 break;
1583 case NF_KEY_S:
1584 case NF_KEY_SS:
1585 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1586 bAnyContent = sal_True;
1587 break;
1588 case NF_KEY_AMPM:
1589 case NF_KEY_AP:
1590 WriteAMPMElement_Impl(); // short/long?
1591 bAnyContent = sal_True;
1592 break;
1594 nPrevType = nElemType;
1595 ++nPos;
1599 if ( sTextContent.getLength() )
1600 bAnyContent = sal_True; // element written in FinishTextElement_Impl
1602 FinishTextElement_Impl(); // final text element - before maps
1604 if ( !bAnyContent )
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
1615 if (bDefPart)
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;
1631 switch ( eOp2 )
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;
1639 default:
1640 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;
1667 sal_uInt16 nPart;
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 )
1679 nUsedParts = 2;
1680 if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
1681 nUsedParts = 3;
1682 if ( rFormat.HasTextFormat() && nUsedParts < 4 )
1683 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 )
1700 if ( !pFormatter )
1701 return; // no formatter -> no entries
1703 sal_uInt32 nKey;
1704 const SvNumberformat* pFormat = NULL;
1705 sal_Bool bNext(pUsedList->GetFirstUsed(nKey));
1706 while(bNext)
1708 pFormat = pFormatter->GetEntry(nKey);
1709 if(pFormat)
1710 ExportFormat_Impl( *pFormat, nKey );
1711 bNext = pUsedList->GetNextUsed(nKey);
1713 if (!bIsAutoStyle)
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();
1726 while (pFormat)
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 );
1749 else
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" );
1759 if( !pFormatter )
1760 return;
1762 if (pFormatter->GetEntry(nKey))
1763 pUsedList->SetUsed( nKey );
1764 else {
1765 DBG_ERROR("no existing Numberformat found with this key");
1769 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
1771 if (pUsedList)
1772 pUsedList->GetWasUsed(rWasUsed);
1775 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1777 if (pUsedList)
1778 pUsedList->SetWasUsed(rWasUsed);
1783 const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
1784 sal_uInt32 nKey )
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 )
1806 nRet = nNewKey;
1808 else
1810 String aFormatString( pFormat->GetFormatstring() );
1811 pFormatter->PutandConvertEntry(
1812 aFormatString,
1813 nErrorPos, nType, nNewKey,
1814 pFormat->GetLanguage(), LANGUAGE_SYSTEM );
1816 // success? Then use new key.
1817 if( nErrorPos == 0 )
1818 nRet = nNewKey;
1822 return nRet;