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