fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / xmloff / source / style / xmlnumfe.cxx
blobe1eb48a6b174c14ea4c14946ea169c7f7155f4ab
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <svl/zforlist.hxx>
22 #include <svl/zformat.hxx>
23 #include <svl/numuno.hxx>
24 #include <i18nlangtag/mslangid.hxx>
25 #include <i18nlangtag/languagetag.hxx>
26 #include <tools/debug.hxx>
27 #include <rtl/math.hxx>
28 #include <unotools/calendarwrapper.hxx>
29 #include <unotools/charclass.hxx>
30 #include <com/sun/star/lang/Locale.hpp>
31 #include <rtl/ustrbuf.hxx>
32 #include <tools/color.hxx>
33 #include <sax/tools/converter.hxx>
35 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
37 #include <xmloff/xmlnumfe.hxx>
38 #include "xmloff/xmlnmspe.hxx"
39 #include <xmloff/attrlist.hxx>
40 #include <xmloff/nmspmap.hxx>
41 #include <xmloff/families.hxx>
42 #include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults
44 #include <svl/nfsymbol.hxx>
45 #include <xmloff/xmltoken.hxx>
46 #include <xmloff/xmlexp.hxx>
48 #include <set>
49 #include <boost/ptr_container/ptr_vector.hpp>
52 using namespace ::com::sun::star;
53 using namespace ::xmloff::token;
54 using namespace ::svt;
56 //-------------------------------------------------------------------------
58 #define XMLNUM_MAX_PARTS 3
60 //-------------------------------------------------------------------------
62 struct LessuInt32
64 sal_Bool operator() (const sal_uInt32 rValue1, const sal_uInt32 rValue2) const
66 return rValue1 < rValue2;
70 typedef std::set< sal_uInt32, LessuInt32 > SvXMLuInt32Set;
72 class SvXMLNumUsedList_Impl
74 SvXMLuInt32Set aUsed;
75 SvXMLuInt32Set aWasUsed;
76 SvXMLuInt32Set::iterator aCurrentUsedPos;
77 sal_uInt32 nUsedCount;
78 sal_uInt32 nWasUsedCount;
80 public:
81 SvXMLNumUsedList_Impl();
82 ~SvXMLNumUsedList_Impl();
84 void SetUsed( sal_uInt32 nKey );
85 sal_Bool IsUsed( sal_uInt32 nKey ) const;
86 sal_Bool IsWasUsed( sal_uInt32 nKey ) const;
87 void Export();
89 sal_Bool GetFirstUsed(sal_uInt32& nKey);
90 sal_Bool GetNextUsed(sal_uInt32& nKey);
92 void GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed);
93 void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
96 //-------------------------------------------------------------------------
98 struct SvXMLEmbeddedTextEntry
100 sal_uInt16 nSourcePos; // position in NumberFormat (to skip later)
101 sal_Int32 nFormatPos; // resulting position in embedded-text element
102 OUString aText;
104 SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const OUString& rT ) :
105 nSourcePos(nSP), nFormatPos(nFP), aText(rT) {}
108 class SvXMLEmbeddedTextEntryArr : public boost::ptr_vector<SvXMLEmbeddedTextEntry> {};
110 //-------------------------------------------------------------------------
113 //! SvXMLNumUsedList_Impl should be optimized!
116 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
117 nUsedCount(0),
118 nWasUsedCount(0)
122 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
126 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
128 if ( !IsWasUsed(nKey) )
130 std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
131 if (aPair.second)
132 nUsedCount++;
136 sal_Bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
138 SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey);
139 return (aItr != aUsed.end());
142 sal_Bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
144 SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey);
145 return (aItr != aWasUsed.end());
148 void SvXMLNumUsedList_Impl::Export()
150 SvXMLuInt32Set::const_iterator aItr = aUsed.begin();
151 while (aItr != aUsed.end())
153 std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *aItr );
154 if (aPair.second)
155 nWasUsedCount++;
156 ++aItr;
158 aUsed.clear();
159 nUsedCount = 0;
162 sal_Bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey)
164 sal_Bool bRet(sal_False);
165 aCurrentUsedPos = aUsed.begin();
166 if(nUsedCount)
168 DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
169 nKey = *aCurrentUsedPos;
170 bRet = sal_True;
172 return bRet;
175 sal_Bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey)
177 sal_Bool bRet(sal_False);
178 if (aCurrentUsedPos != aUsed.end())
180 ++aCurrentUsedPos;
181 if (aCurrentUsedPos != aUsed.end())
183 nKey = *aCurrentUsedPos;
184 bRet = sal_True;
187 return bRet;
190 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
192 rWasUsed.realloc(nWasUsedCount);
193 sal_Int32* pWasUsed = rWasUsed.getArray();
194 if (pWasUsed)
196 SvXMLuInt32Set::const_iterator aItr = aWasUsed.begin();
197 while (aItr != aWasUsed.end())
199 *pWasUsed = *aItr;
200 ++aItr;
201 ++pWasUsed;
206 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
208 DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
209 sal_Int32 nCount(rWasUsed.getLength());
210 const sal_Int32* pWasUsed = rWasUsed.getConstArray();
211 for (sal_uInt16 i = 0; i < nCount; i++, pWasUsed++)
213 std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *pWasUsed );
214 if (aPair.second)
215 nWasUsedCount++;
219 //-------------------------------------------------------------------------
221 SvXMLNumFmtExport::SvXMLNumFmtExport(
222 SvXMLExport& rExp,
223 const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
224 rExport( rExp ),
225 sPrefix( OUString("N") ),
226 pFormatter( NULL ),
227 pCharClass( NULL ),
228 pLocaleData( NULL )
230 // supplier must be SvNumberFormatsSupplierObj
231 SvNumberFormatsSupplierObj* pObj =
232 SvNumberFormatsSupplierObj::getImplementation( rSupp );
233 if (pObj)
234 pFormatter = pObj->GetNumberFormatter();
236 if ( pFormatter )
238 pCharClass = new CharClass( pFormatter->GetComponentContext(),
239 pFormatter->GetLanguageTag() );
240 pLocaleData = new LocaleDataWrapper( pFormatter->GetComponentContext(),
241 pFormatter->GetLanguageTag() );
243 else
245 LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
247 pCharClass = new CharClass( rExport.getComponentContext(), aLanguageTag );
248 pLocaleData = new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag );
251 pUsedList = new SvXMLNumUsedList_Impl;
254 SvXMLNumFmtExport::SvXMLNumFmtExport(
255 SvXMLExport& rExp,
256 const ::com::sun::star::uno::Reference<
257 ::com::sun::star::util::XNumberFormatsSupplier >& rSupp,
258 const OUString& rPrefix ) :
259 rExport( rExp ),
260 sPrefix( rPrefix ),
261 pFormatter( NULL ),
262 pCharClass( NULL ),
263 pLocaleData( NULL )
265 // supplier must be SvNumberFormatsSupplierObj
266 SvNumberFormatsSupplierObj* pObj =
267 SvNumberFormatsSupplierObj::getImplementation( rSupp );
268 if (pObj)
269 pFormatter = pObj->GetNumberFormatter();
271 if ( pFormatter )
273 pCharClass = new CharClass( pFormatter->GetComponentContext(),
274 pFormatter->GetLanguageTag() );
275 pLocaleData = new LocaleDataWrapper( pFormatter->GetComponentContext(),
276 pFormatter->GetLanguageTag() );
278 else
280 LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
282 pCharClass = new CharClass( rExport.getComponentContext(), aLanguageTag );
283 pLocaleData = new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag );
286 pUsedList = new SvXMLNumUsedList_Impl;
289 SvXMLNumFmtExport::~SvXMLNumFmtExport()
291 delete pUsedList;
292 delete pLocaleData;
293 delete pCharClass;
296 //-------------------------------------------------------------------------
299 // helper methods
302 static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, sal_Bool bDefPart, const OUString& rPrefix )
304 OUStringBuffer aFmtName( 10L );
305 aFmtName.append( rPrefix );
306 aFmtName.append( nKey );
307 if (!bDefPart)
309 aFmtName.append( (sal_Unicode)'P' );
310 aFmtName.append( nPart );
312 return aFmtName.makeStringAndClear();
315 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
317 if ( !rCalendar.isEmpty() )
319 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar );
323 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText )
325 if ( bText ) // non-textual
327 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE );
331 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong )
333 if ( bLong ) // short is default
335 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG );
339 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang )
341 if ( nLang != LANGUAGE_SYSTEM )
343 /* FIXME-BCP47: handle language tags!
344 * ODF now provides fo:script, and rfc-language-tag attribute in case a
345 * locale can't be expressed using these three ISO codes.
346 * Of course these need to be read in xmlnumfi.cxx then..
347 * In general all places using XML_LANGUAGE and XML_COUNTRY need to be
348 * adapted once we really support bcp47. */
349 OUString aLangStr, aCountryStr;
350 LanguageTag( (LanguageType)nLang ).getIsoLanguageCountry( aLangStr, aCountryStr );
352 if (!aLangStr.isEmpty())
353 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_LANGUAGE, aLangStr );
354 if (!aCountryStr.isEmpty())
355 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_COUNTRY, aCountryStr );
359 //-------------------------------------------------------------------------
362 // methods to write individual elements within a format
365 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString )
367 // append to sTextContent, write element in FinishTextElement_Impl
368 // to avoid several text elements following each other
370 sTextContent.append( rString );
373 void SvXMLNumFmtExport::FinishTextElement_Impl()
375 if ( sTextContent.getLength() )
377 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
378 sal_True, sal_False );
379 rExport.Characters( sTextContent.makeStringAndClear() );
383 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor )
385 FinishTextElement_Impl();
387 OUStringBuffer aColStr( 7 );
388 ::sax::Converter::convertColor( aColStr, rColor.GetColor() );
389 rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR,
390 aColStr.makeStringAndClear() );
392 SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES,
393 sal_True, sal_False );
396 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString,
397 const OUString& rExt )
399 FinishTextElement_Impl();
401 if ( !rExt.isEmpty() )
403 sal_Int32 nLang = rExt.toInt32(16); // hex
404 if ( nLang < 0 ) // extension string may contain "-" separator
405 nLang = -nLang;
406 AddLanguageAttr_Impl( nLang ); // adds to pAttrList
409 SvXMLElementExport aElem( rExport,
410 XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL,
411 sal_True, sal_False );
412 rExport.Characters( rString );
415 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
417 FinishTextElement_Impl();
419 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN,
420 sal_True, sal_False );
423 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
425 FinishTextElement_Impl();
427 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT,
428 sal_True, sal_False );
431 // date elements
433 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, sal_Bool bLong )
435 FinishTextElement_Impl();
437 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
438 AddStyleAttr_Impl( bLong ); // adds to pAttrList
440 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY,
441 sal_True, sal_False );
444 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, sal_Bool bLong, sal_Bool bText )
446 FinishTextElement_Impl();
448 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
449 AddStyleAttr_Impl( bLong ); // adds to pAttrList
450 AddTextualAttr_Impl( bText ); // adds to pAttrList
452 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH,
453 sal_True, sal_False );
456 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, sal_Bool bLong )
458 FinishTextElement_Impl();
460 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
461 AddStyleAttr_Impl( bLong ); // adds to pAttrList
463 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR,
464 sal_True, sal_False );
467 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, sal_Bool bLong )
469 FinishTextElement_Impl();
471 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
472 AddStyleAttr_Impl( bLong ); // adds to pAttrList
474 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA,
475 sal_True, sal_False );
478 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, sal_Bool bLong )
480 FinishTextElement_Impl();
482 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
483 AddStyleAttr_Impl( bLong ); // adds to pAttrList
485 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK,
486 sal_True, sal_False );
489 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
491 FinishTextElement_Impl();
493 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
495 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR,
496 sal_True, sal_False );
499 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, sal_Bool bLong )
501 FinishTextElement_Impl();
503 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
504 AddStyleAttr_Impl( bLong ); // adds to pAttrList
506 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER,
507 sal_True, sal_False );
510 // time elements
512 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong )
514 FinishTextElement_Impl();
516 AddStyleAttr_Impl( bLong ); // adds to pAttrList
518 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS,
519 sal_True, sal_False );
522 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong )
524 FinishTextElement_Impl();
526 AddStyleAttr_Impl( bLong ); // adds to pAttrList
528 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES,
529 sal_True, sal_False );
532 void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar )
534 FinishTextElement_Impl();
535 SvXMLElementExport aElem( rExport, XML_NAMESPACE_LO_EXT, XML_FILL_CHARACTER,
536 sal_True, sal_False );
537 rExport.Characters( OUString::valueOf( nChar ) );
540 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong, sal_uInt16 nDecimals )
542 FinishTextElement_Impl();
544 AddStyleAttr_Impl( bLong ); // adds to pAttrList
545 if ( nDecimals > 0 )
547 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
548 OUString::valueOf( (sal_Int32) nDecimals ) );
551 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS,
552 sal_True, sal_False );
555 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
557 FinishTextElement_Impl();
559 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM,
560 sal_True, sal_False );
563 // numbers
565 void SvXMLNumFmtExport::WriteNumberElement_Impl(
566 sal_Int32 nDecimals, sal_Int32 nInteger,
567 const OUString& rDashStr, sal_Bool bVarDecimals,
568 sal_Bool bGrouping, sal_Int32 nTrailingThousands,
569 const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
571 FinishTextElement_Impl();
573 // decimals
574 if ( nDecimals >= 0 ) // negative = automatic
576 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
577 OUString::valueOf( nDecimals ) );
580 // integer digits
581 if ( nInteger >= 0 ) // negative = automatic
583 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
584 OUString::valueOf( nInteger ) );
587 // decimal replacement (dashes) or variable decimals (#)
588 if ( !rDashStr.isEmpty() || bVarDecimals )
590 // variable decimals means an empty replacement string
591 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,
592 rDashStr );
595 // (automatic) grouping separator
596 if ( bGrouping )
598 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
601 // display-factor if there are trailing thousands separators
602 if ( nTrailingThousands )
604 // each separator character removes three digits
605 double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
607 OUStringBuffer aFactStr;
608 ::sax::Converter::convertDouble( aFactStr, fFactor );
609 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
612 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER,
613 sal_True, sal_True );
615 // number:embedded-text as child elements
617 sal_uInt16 nEntryCount = rEmbeddedEntries.size();
618 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
620 const SvXMLEmbeddedTextEntry* pObj = &rEmbeddedEntries[nEntry];
622 // position attribute
623 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION,
624 OUString::valueOf( pObj->nFormatPos ) );
625 SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT,
626 sal_True, sal_False );
628 // text as element content
629 OUString aContent( pObj->aText );
630 while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos )
632 // The array can contain several elements for the same position in the number
633 // (for example, literal text and space from underscores). They must be merged
634 // into a single embedded-text element.
635 aContent += rEmbeddedEntries[nEntry+1].aText;
636 ++nEntry;
638 rExport.Characters( aContent );
642 void SvXMLNumFmtExport::WriteScientificElement_Impl(
643 sal_Int32 nDecimals, sal_Int32 nInteger,
644 sal_Bool bGrouping, sal_Int32 nExp )
646 FinishTextElement_Impl();
648 // decimals
649 if ( nDecimals >= 0 ) // negative = automatic
651 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
652 OUString::valueOf( nDecimals ) );
655 // integer digits
656 if ( nInteger >= 0 ) // negative = automatic
658 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
659 OUString::valueOf( nInteger ) );
662 // (automatic) grouping separator
663 if ( bGrouping )
665 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
668 // exponent digits
669 if ( nExp >= 0 )
671 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,
672 OUString::valueOf( nExp ) );
675 SvXMLElementExport aElem( rExport,
676 XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,
677 sal_True, sal_False );
680 void SvXMLNumFmtExport::WriteFractionElement_Impl(
681 sal_Int32 nInteger, sal_Bool bGrouping,
682 sal_Int32 nNumeratorDigits, sal_Int32 nDenominatorDigits, sal_Int32 nDenominator )
684 FinishTextElement_Impl();
686 // integer digits
687 if ( nInteger >= 0 ) // negative = default (no integer part)
689 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
690 OUString::valueOf( nInteger ) );
693 // (automatic) grouping separator
694 if ( bGrouping )
696 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
699 // numerator digits
700 if ( nNumeratorDigits >= 0 )
702 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,
703 OUString::valueOf( nNumeratorDigits ) );
706 if ( nDenominator )
708 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE,
709 OUString::valueOf( nDenominator) );
711 // I guess it's not necessary to export nDenominatorDigits
712 // if we have a forced denominator ( remove ? )
713 if ( nDenominatorDigits >= 0 )
715 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,
716 OUString::valueOf( nDenominatorDigits ) );
719 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION,
720 sal_True, sal_False );
723 // mapping (condition)
725 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
726 sal_Int32 nKey, sal_Int32 nPart )
728 FinishTextElement_Impl();
730 if ( nOp != NUMBERFORMAT_OP_NO )
732 // style namespace
734 OUStringBuffer aCondStr( 20L );
735 aCondStr.appendAscii( "value()" ); //! define constant
736 switch ( nOp )
738 case NUMBERFORMAT_OP_EQ: aCondStr.append( (sal_Unicode) '=' ); break;
739 case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "<>" ); break;
740 case NUMBERFORMAT_OP_LT: aCondStr.append( (sal_Unicode) '<' ); break;
741 case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" ); break;
742 case NUMBERFORMAT_OP_GT: aCondStr.append( (sal_Unicode) '>' ); break;
743 case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" ); break;
744 default:
745 OSL_FAIL("unknown operator");
747 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
748 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
749 '.', true );
751 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION,
752 aCondStr.makeStringAndClear() );
754 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME,
755 rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, sal_False,
756 sPrefix ) ) );
758 SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP,
759 sal_True, sal_False );
763 //-------------------------------------------------------------------------
764 // for old (automatic) currency formats: parse currency symbol from text
766 sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, const OUString& sCurString )
768 // search for currency symbol
769 // Quoting as in ImpSvNumberformatScan::Symbol_Division
771 sal_Int32 nCPos = 0;
772 while (nCPos >= 0)
774 nCPos = sUpperStr.indexOf( sCurString, nCPos );
775 if (nCPos >= 0)
777 // in Quotes?
778 sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
779 if ( nQ < 0 )
781 // dm can be escaped as "dm or \d
782 sal_Unicode c;
783 if ( nCPos == 0 ||
784 ((c = sUpperStr[nCPos-1]) != '"'
785 && c != '\\') )
787 return nCPos; // found
789 else
791 nCPos++; // continue
794 else
796 nCPos = nQ + 1; // continue after quote end
800 return -1;
803 sal_Bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
804 const ::com::sun::star::lang::Locale& rLocale )
806 // returns sal_True if currency element was written
808 sal_Bool bRet = sal_False;
810 LanguageTag aLanguageTag( rLocale );
811 pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) );
812 OUString sCurString, sDummy;
813 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
815 pCharClass->setLanguageTag( aLanguageTag );
816 OUString sUpperStr = pCharClass->uppercase(rString);
817 sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString );
818 if ( nPos >= 0 )
820 sal_Int32 nLength = rString.getLength();
821 sal_Int32 nCurLen = sCurString.getLength();
822 sal_Int32 nCont = nPos + nCurLen;
824 // text before currency symbol
825 if ( nPos > 0 )
827 AddToTextElement_Impl( rString.copy( 0, nPos ) );
829 // currency symbol (empty string -> default)
830 OUString sEmpty;
831 WriteCurrencyElement_Impl( sEmpty, sEmpty );
832 bRet = sal_True;
834 // text after currency symbol
835 if ( nCont < nLength )
837 AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
840 else
842 AddToTextElement_Impl( rString ); // simple text
845 return bRet; // sal_True: currency element written
848 //-------------------------------------------------------------------------
850 static OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang )
852 // get name of first non-gregorian calendar for the language
854 OUString aCalendar;
855 CalendarWrapper* pCalendar = pFormatter->GetCalendar();
856 if (pCalendar)
858 lang::Locale aLocale( LanguageTag( nLang ).getLocale() );
860 uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
861 sal_Int32 nCnt = aCals.getLength();
862 sal_Bool bFound = sal_False;
863 for ( sal_Int32 j=0; j < nCnt && !bFound; j++ )
865 if ( aCals[j] != "gregorian" )
867 aCalendar = aCals[j];
868 bFound = sal_True;
872 return aCalendar;
875 //-------------------------------------------------------------------------
877 static sal_Bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
879 sal_uInt16 nCount = rEmbeddedEntries.size();
880 for (sal_uInt16 i=0; i<nCount; i++)
881 if ( rEmbeddedEntries[i].nSourcePos == nPos )
882 return sal_True;
884 return sal_False; // not found
887 static sal_Bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, sal_Bool bSystemDate, NfIndexTableOffset eBuiltIn )
889 // make an extra loop to collect date elements, to check if it is a default format
890 // before adding the automatic-order attribute
892 SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE;
893 SvXMLDateElementAttributes eDateDay = XML_DEA_NONE;
894 SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE;
895 SvXMLDateElementAttributes eDateYear = XML_DEA_NONE;
896 SvXMLDateElementAttributes eDateHours = XML_DEA_NONE;
897 SvXMLDateElementAttributes eDateMins = XML_DEA_NONE;
898 SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE;
899 sal_Bool bDateNoDefault = sal_False;
901 sal_uInt16 nPos = 0;
902 sal_Bool bEnd = sal_False;
903 short nLastType = 0;
904 while (!bEnd)
906 short nElemType = rFormat.GetNumForType( 0, nPos, sal_False );
907 switch ( nElemType )
909 case 0:
910 if ( nLastType == NF_SYMBOLTYPE_STRING )
911 bDateNoDefault = sal_True; // text at the end -> no default date format
912 bEnd = sal_True; // end of format reached
913 break;
914 case NF_SYMBOLTYPE_STRING:
915 case NF_SYMBOLTYPE_DATESEP:
916 case NF_SYMBOLTYPE_TIMESEP:
917 case NF_SYMBOLTYPE_TIME100SECSEP:
918 // text is ignored, except at the end
919 break;
920 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
921 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
922 case NF_KEY_NNN:
923 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
924 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
925 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
926 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
927 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
928 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
929 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
930 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
931 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
932 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
933 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
934 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
935 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
936 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
937 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
938 case NF_KEY_AP:
939 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
940 default:
941 bDateNoDefault = sal_True; // any other element -> no default format
943 nLastType = nElemType;
944 ++nPos;
947 if ( bDateNoDefault )
948 return sal_False; // additional elements
949 else
951 NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
952 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate );
954 return ( eFound == eBuiltIn );
959 // export one part (condition)
962 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
963 sal_uInt16 nPart, sal_Bool bDefPart )
965 //! for the default part, pass the coditions from the other parts!
968 // element name
971 NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
973 short nFmtType = 0;
974 bool bThousand = false;
975 sal_uInt16 nPrecision = 0;
976 sal_uInt16 nLeading = 0;
977 rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
978 nFmtType &= ~NUMBERFORMAT_DEFINED;
980 // special treatment of builtin formats that aren't detected by normal parsing
981 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
982 if ( eBuiltIn == NF_NUMBER_STANDARD )
983 nFmtType = NUMBERFORMAT_NUMBER;
984 else if ( eBuiltIn == NF_BOOLEAN )
985 nFmtType = NUMBERFORMAT_LOGICAL;
986 else if ( eBuiltIn == NF_TEXT )
987 nFmtType = NUMBERFORMAT_TEXT;
989 // #101606# An empty subformat is a valid number-style resulting in an
990 // empty display string for the condition of the subformat.
991 if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart,
992 0, sal_False ) == 0 )
993 nFmtType = 0;
995 XMLTokenEnum eType = XML_TOKEN_INVALID;
996 switch ( nFmtType )
998 // type is 0 if a format contains no recognized elements
999 // (like text only) - this is handled as a number-style.
1000 case 0:
1001 case NUMBERFORMAT_NUMBER:
1002 case NUMBERFORMAT_SCIENTIFIC:
1003 case NUMBERFORMAT_FRACTION:
1004 eType = XML_NUMBER_STYLE;
1005 break;
1006 case NUMBERFORMAT_PERCENT:
1007 eType = XML_PERCENTAGE_STYLE;
1008 break;
1009 case NUMBERFORMAT_CURRENCY:
1010 eType = XML_CURRENCY_STYLE;
1011 break;
1012 case NUMBERFORMAT_DATE:
1013 case NUMBERFORMAT_DATETIME:
1014 eType = XML_DATE_STYLE;
1015 break;
1016 case NUMBERFORMAT_TIME:
1017 eType = XML_TIME_STYLE;
1018 break;
1019 case NUMBERFORMAT_TEXT:
1020 eType = XML_TEXT_STYLE;
1021 break;
1022 case NUMBERFORMAT_LOGICAL:
1023 eType = XML_BOOLEAN_STYLE;
1024 break;
1026 DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" );
1028 OUString sAttrValue;
1029 sal_Bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 );
1032 // common attributes for format
1035 // format name (generated from key) - style namespace
1036 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
1037 lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
1039 // "volatile" attribute for styles used only in maps
1040 if ( !bDefPart )
1041 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE );
1043 // language / country
1044 LanguageType nLang = rFormat.GetLanguage();
1045 AddLanguageAttr_Impl( nLang ); // adds to pAttrList
1047 // title (comment)
1048 // titles for builtin formats are not written
1049 sAttrValue = rFormat.GetComment();
1050 if ( !sAttrValue.isEmpty() && bUserDef && bDefPart )
1052 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue );
1055 // automatic ordering for currency and date formats
1056 // only used for some built-in formats
1057 sal_Bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1058 eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1059 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1060 eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
1061 eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
1062 eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
1063 eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1064 eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1065 eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1066 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1068 // format source (for date and time formats)
1069 // only used for some built-in formats
1070 sal_Bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1071 eBuiltIn == NF_DATE_SYSTEM_LONG ||
1072 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1073 sal_Bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1075 // check if the format definition matches the key
1076 if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) &&
1077 !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1079 bAutoOrder = bSystemDate = bLongSysDate = sal_False; // don't write automatic-order attribute then
1082 if ( bAutoOrder &&
1083 ( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1085 // #85109# format type must be checked to avoid dtd errors if
1086 // locale data contains other format types at the built-in positions
1088 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,
1089 XML_TRUE );
1092 if ( bSystemDate && bAutoOrder &&
1093 ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1095 // #85109# format type must be checked to avoid dtd errors if
1096 // locale data contains other format types at the built-in positions
1098 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,
1099 XML_LANGUAGE );
1102 // overflow for time formats as in [hh]:mm
1103 // controlled by bThousand from number format info
1104 // default for truncate-on-overflow is true
1105 if ( nFmtType == NUMBERFORMAT_TIME && bThousand )
1107 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,
1108 XML_FALSE );
1112 // Native number transliteration
1114 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr;
1115 rFormat.GetNatNumXml( aAttr, nPart );
1116 if ( !aAttr.Format.isEmpty() )
1118 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,
1119 aAttr.Format );
1120 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,
1121 aAttr.Locale.Language );
1122 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,
1123 aAttr.Locale.Country );
1124 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,
1125 aAttr.Style );
1129 // The element
1131 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
1132 sal_True, sal_True );
1135 // color (properties element)
1138 const Color* pCol = rFormat.GetColor( nPart );
1139 if (pCol)
1140 WriteColorElement_Impl(*pCol);
1143 // detect if there is "real" content, excluding color and maps
1144 //! move to implementation of Write... methods?
1145 sal_Bool bAnyContent = sal_False;
1148 // format elements
1151 SvXMLEmbeddedTextEntryArr aEmbeddedEntries;
1152 if ( eBuiltIn == NF_NUMBER_STANDARD )
1154 // default number format contains just one number element
1155 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1156 bAnyContent = sal_True;
1158 else if ( eBuiltIn == NF_BOOLEAN )
1160 // boolean format contains just one boolean element
1161 WriteBooleanElement_Impl();
1162 bAnyContent = sal_True;
1164 else
1166 // first loop to collect attributes
1168 sal_Bool bDecDashes = sal_False;
1169 sal_Bool bVarDecimals = sal_False;
1170 sal_Bool bExpFound = sal_False;
1171 sal_Bool bCurrFound = sal_False;
1172 sal_Bool bInInteger = sal_True;
1173 sal_Int32 nExpDigits = 0;
1174 sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
1175 sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
1176 OUString sCurrExt;
1177 OUString aCalendar;
1178 sal_uInt16 nPos = 0;
1179 sal_Bool bEnd = sal_False;
1180 while (!bEnd)
1182 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1183 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1185 switch ( nElemType )
1187 case 0:
1188 bEnd = sal_True; // end of format reached
1189 break;
1190 case NF_SYMBOLTYPE_DIGIT:
1191 if ( bExpFound && pElemStr )
1192 nExpDigits += pElemStr->getLength();
1193 else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' )
1194 bDecDashes = sal_True;
1195 else if ( !bVarDecimals && !bInInteger && pElemStr && (*pElemStr)[0] == '#' )
1197 // If the decimal digits string starts with a '#', variable
1198 // decimals is assumed (for 0.###, but not 0.0##).
1199 bVarDecimals = sal_True;
1201 if ( bInInteger && pElemStr )
1202 nIntegerSymbols += pElemStr->getLength();
1203 nTrailingThousands = 0;
1204 break;
1205 case NF_SYMBOLTYPE_DECSEP:
1206 bInInteger = sal_False;
1207 break;
1208 case NF_SYMBOLTYPE_THSEP:
1209 if (pElemStr)
1210 nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow
1211 break;
1212 case NF_SYMBOLTYPE_EXP:
1213 bExpFound = sal_True; // following digits are exponent digits
1214 bInInteger = sal_False;
1215 break;
1216 case NF_SYMBOLTYPE_CURRENCY:
1217 bCurrFound = sal_True;
1218 break;
1219 case NF_SYMBOLTYPE_CURREXT:
1220 if (pElemStr)
1221 sCurrExt = *pElemStr;
1222 break;
1224 // E, EE, R, RR: select non-gregorian calendar
1225 // AAA, AAAA: calendar is switched at the position of the element
1226 case NF_KEY_EC:
1227 case NF_KEY_EEC:
1228 case NF_KEY_R:
1229 case NF_KEY_RR:
1230 if (aCalendar.isEmpty())
1231 aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1232 break;
1234 ++nPos;
1237 // collect strings for embedded-text (must be known before number element is written)
1239 sal_Bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER ||
1240 nFmtType == NUMBERFORMAT_CURRENCY ||
1241 nFmtType == NUMBERFORMAT_PERCENT );
1242 if ( bAllowEmbedded )
1244 sal_Int32 nDigitsPassed = 0;
1245 nPos = 0;
1246 bEnd = sal_False;
1247 while (!bEnd)
1249 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1250 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1252 switch ( nElemType )
1254 case 0:
1255 bEnd = sal_True; // end of format reached
1256 break;
1257 case NF_SYMBOLTYPE_DIGIT:
1258 if ( pElemStr )
1259 nDigitsPassed += pElemStr->getLength();
1260 break;
1261 case NF_SYMBOLTYPE_STRING:
1262 case NF_SYMBOLTYPE_BLANK:
1263 case NF_SYMBOLTYPE_PERCENT:
1264 if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
1266 // text (literal or underscore) within the integer part of a number:number element
1268 OUString aEmbeddedStr;
1269 if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1271 aEmbeddedStr = *pElemStr;
1273 else
1275 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] );
1277 sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1279 SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr );
1280 aEmbeddedEntries.push_back( pObj );
1282 break;
1284 ++nPos;
1288 // final loop to write elements
1290 sal_Bool bNumWritten = sal_False;
1291 sal_Bool bCurrencyWritten = sal_False;
1292 short nPrevType = 0;
1293 nPos = 0;
1294 bEnd = sal_False;
1295 while (!bEnd)
1297 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1298 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1300 switch ( nElemType )
1302 case 0:
1303 bEnd = sal_True; // end of format reached
1304 break;
1305 case NF_SYMBOLTYPE_STRING:
1306 case NF_SYMBOLTYPE_DATESEP:
1307 case NF_SYMBOLTYPE_TIMESEP:
1308 case NF_SYMBOLTYPE_TIME100SECSEP:
1309 case NF_SYMBOLTYPE_PERCENT:
1310 if (pElemStr)
1312 if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1313 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1314 nPrecision > 0 )
1316 // decimal separator after seconds is implied by
1317 // "decimal-places" attribute and must not be written
1318 // as text element
1319 //! difference between '.' and ',' is lost here
1321 else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1323 // text is written as embedded-text child of the number,
1324 // don't create a text element
1326 else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten )
1328 // automatic currency symbol is implemented as part of
1329 // normal text -> search for the symbol
1330 bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1331 LanguageTag( nLang ).getLocale() );
1332 bAnyContent = sal_True;
1334 else
1335 AddToTextElement_Impl( *pElemStr );
1337 break;
1338 case NF_SYMBOLTYPE_BLANK:
1339 if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1341 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1342 // (#i20396# the spaces may also be in embedded-text elements)
1344 OUString aBlanks;
1345 SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] );
1346 AddToTextElement_Impl( aBlanks );
1348 break;
1349 case NF_KEY_GENERAL :
1350 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1351 break;
1352 case NF_KEY_CCC:
1353 if (pElemStr)
1355 if ( bCurrencyWritten )
1356 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1357 else
1359 //! must be different from short automatic format
1360 //! but should still be empty (meaning automatic)
1361 // pElemStr is "CCC"
1363 WriteCurrencyElement_Impl( *pElemStr, OUString() );
1364 bAnyContent = sal_True;
1365 bCurrencyWritten = sal_True;
1368 break;
1369 case NF_SYMBOLTYPE_CURRENCY:
1370 if (pElemStr)
1372 if ( bCurrencyWritten )
1373 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1374 else
1376 WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1377 bAnyContent = sal_True;
1378 bCurrencyWritten = sal_True;
1381 break;
1382 case NF_SYMBOLTYPE_DIGIT:
1383 if (!bNumWritten) // write number part
1385 switch ( nFmtType )
1387 // for type 0 (not recognized as a special type),
1388 // write a "normal" number
1389 case 0:
1390 case NUMBERFORMAT_NUMBER:
1391 case NUMBERFORMAT_CURRENCY:
1392 case NUMBERFORMAT_PERCENT:
1394 // decimals
1395 // only some built-in formats have automatic decimals
1396 sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
1397 if ( eBuiltIn == NF_NUMBER_STANDARD ||
1398 eBuiltIn == NF_CURRENCY_1000DEC2 ||
1399 eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1400 eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1401 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1402 nDecimals = -1;
1404 // integer digits
1405 // only one built-in format has automatic integer digits
1406 sal_Int32 nInteger = nLeading;
1407 if ( eBuiltIn == NF_NUMBER_SYSTEM )
1408 nInteger = -1;
1410 // string for decimal replacement
1411 // has to be taken from nPrecision
1412 // (positive number even for automatic decimals)
1413 OUStringBuffer sDashStr;
1414 if (bDecDashes && nPrecision > 0)
1415 comphelper::string::padToLength(sDashStr, nPrecision, '-');
1417 WriteNumberElement_Impl(nDecimals, nInteger, sDashStr.makeStringAndClear(),
1418 bVarDecimals, bThousand, nTrailingThousands, aEmbeddedEntries);
1419 bAnyContent = sal_True;
1421 break;
1422 case NUMBERFORMAT_SCIENTIFIC:
1423 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1424 // as integer digits: use nIntegerSymbols instead of nLeading
1425 // (use of '#' to select multiples in exponent might be added later)
1426 WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits );
1427 bAnyContent = sal_True;
1428 break;
1429 case NUMBERFORMAT_FRACTION:
1431 sal_Int32 nInteger = nLeading;
1432 if ( pElemStr && (*pElemStr)[0] == '?' )
1434 // If the first digit character is a question mark,
1435 // the fraction doesn't have an integer part, and no
1436 // min-integer-digits attribute must be written.
1437 nInteger = -1;
1439 sal_Int32 nDenominator = rFormat.GetForcedDenominatorForType( nPart );
1440 WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision, nDenominator );
1441 bAnyContent = sal_True;
1443 break;
1446 bNumWritten = sal_True;
1448 break;
1449 case NF_SYMBOLTYPE_DECSEP:
1450 if ( pElemStr && nPrecision == 0 )
1452 // A decimal separator after the number, without following decimal digits,
1453 // isn't modelled as part of the number element, so it's written as text
1454 // (the distinction between a quoted and non-quoted, locale-dependent
1455 // character is lost here).
1457 AddToTextElement_Impl( *pElemStr );
1459 break;
1460 case NF_SYMBOLTYPE_DEL:
1461 if ( pElemStr && comphelper::string::equals(*pElemStr, '@') )
1463 WriteTextContentElement_Impl();
1464 bAnyContent = sal_True;
1466 break;
1468 case NF_SYMBOLTYPE_CALENDAR:
1469 if ( pElemStr )
1470 aCalendar = *pElemStr;
1471 break;
1473 // date elements:
1475 case NF_KEY_D:
1476 case NF_KEY_DD:
1478 sal_Bool bLong = ( nElemType == NF_KEY_DD );
1479 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1480 bAnyContent = sal_True;
1482 break;
1483 case NF_KEY_DDD:
1484 case NF_KEY_DDDD:
1485 case NF_KEY_NN:
1486 case NF_KEY_NNN:
1487 case NF_KEY_NNNN:
1488 case NF_KEY_AAA:
1489 case NF_KEY_AAAA:
1491 OUString aCalAttr = aCalendar;
1492 if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1494 // calendar attribute for AAA and AAAA is switched only for this element
1495 if (aCalAttr.isEmpty())
1496 aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
1499 sal_Bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1500 nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1501 WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1502 bAnyContent = sal_True;
1503 if ( nElemType == NF_KEY_NNNN )
1505 // write additional text element for separator
1506 pLocaleData->setLanguageTag( LanguageTag( nLang ) );
1507 AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
1510 break;
1511 case NF_KEY_M:
1512 case NF_KEY_MM:
1513 case NF_KEY_MMM:
1514 case NF_KEY_MMMM:
1515 case NF_KEY_MMMMM: //! first letter of month name, no attribute available
1517 sal_Bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
1518 sal_Bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1519 nElemType == NF_KEY_MMMMM );
1520 WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1521 bAnyContent = sal_True;
1523 break;
1524 case NF_KEY_YY:
1525 case NF_KEY_YYYY:
1526 case NF_KEY_EC:
1527 case NF_KEY_EEC:
1528 case NF_KEY_R: //! R acts as EE, no attribute available
1530 //! distinguish EE and R
1531 // calendar attribute for E and EE and R is set in first loop
1532 sal_Bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1533 nElemType == NF_KEY_R );
1534 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1535 bAnyContent = sal_True;
1537 break;
1538 case NF_KEY_G:
1539 case NF_KEY_GG:
1540 case NF_KEY_GGG:
1541 case NF_KEY_RR: //! RR acts as GGGEE, no attribute available
1543 //! distinguish GG and GGG and RR
1544 sal_Bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1545 WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1546 bAnyContent = sal_True;
1547 if ( nElemType == NF_KEY_RR )
1549 // calendar attribute for RR is set in first loop
1550 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : sal_True ) );
1553 break;
1554 case NF_KEY_Q:
1555 case NF_KEY_QQ:
1557 sal_Bool bLong = ( nElemType == NF_KEY_QQ );
1558 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1559 bAnyContent = sal_True;
1561 break;
1562 case NF_KEY_WW:
1563 WriteWeekElement_Impl( aCalendar );
1564 bAnyContent = sal_True;
1565 break;
1567 // time elements (bSystemDate is not used):
1569 case NF_KEY_H:
1570 case NF_KEY_HH:
1571 WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1572 bAnyContent = sal_True;
1573 break;
1574 case NF_KEY_MI:
1575 case NF_KEY_MMI:
1576 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1577 bAnyContent = sal_True;
1578 break;
1579 case NF_KEY_S:
1580 case NF_KEY_SS:
1581 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1582 bAnyContent = sal_True;
1583 break;
1584 case NF_KEY_AMPM:
1585 case NF_KEY_AP:
1586 WriteAMPMElement_Impl(); // short/long?
1587 bAnyContent = sal_True;
1588 break;
1589 case NF_SYMBOLTYPE_STAR :
1590 // export only if ODF 1.2 extensions are enabled
1591 if( SvtSaveOptions().GetODFDefaultVersion() > SvtSaveOptions::ODFVER_012 )
1593 if ( pElemStr && pElemStr->getLength() > 1 )
1594 WriteRepeatedElement_Impl( (*pElemStr)[1] );
1596 break;
1598 nPrevType = nElemType;
1599 ++nPos;
1603 if ( sTextContent.getLength() )
1604 bAnyContent = sal_True; // element written in FinishTextElement_Impl
1606 FinishTextElement_Impl(); // final text element - before maps
1608 if ( !bAnyContent )
1610 // for an empty format, write an empty text element
1611 SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
1612 sal_True, sal_False );
1616 // mapping (conditions) must be last elements
1619 if (bDefPart)
1621 SvNumberformatLimitOps eOp1, eOp2;
1622 double fLimit1, fLimit2;
1623 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1625 WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1626 WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1628 if ( rFormat.HasTextFormat() )
1630 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1631 // by reversing the 2nd condition
1633 SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO;
1634 double fLimit3 = fLimit2;
1635 switch ( eOp2 )
1637 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1638 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1639 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1640 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1641 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1642 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1643 default:
1644 break;
1647 if ( fLimit1 == fLimit2 &&
1648 ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1649 ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1651 // For <x and >x, add =x as last condition
1652 // (just for readability, <=x would be valid, too)
1654 eOp3 = NUMBERFORMAT_OP_EQ;
1657 WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 );
1662 //-------------------------------------------------------------------------
1665 // export one format
1668 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
1670 sal_uInt16 nUsedParts = 0;
1671 sal_uInt16 nPart;
1672 for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++)
1673 if (rFormat.GetNumForType( nPart, 0, sal_False ) != 0)
1674 nUsedParts = nPart+1;
1676 SvNumberformatLimitOps eOp1, eOp2;
1677 double fLimit1, fLimit2;
1678 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1680 // if conditions are set, even empty formats must be written
1682 if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 )
1683 nUsedParts = 2;
1684 if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
1685 nUsedParts = 3;
1686 if ( rFormat.HasTextFormat() && nUsedParts < 4 )
1687 nUsedParts = 4;
1689 for (nPart=0; nPart<nUsedParts; nPart++)
1691 sal_Bool bDefault = ( nPart+1 == nUsedParts ); // last = default
1692 ExportPart_Impl( rFormat, nKey, nPart, bDefault );
1696 //-------------------------------------------------------------------------
1699 // export method called by application
1702 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle )
1704 if ( !pFormatter )
1705 return; // no formatter -> no entries
1707 sal_uInt32 nKey;
1708 const SvNumberformat* pFormat = NULL;
1709 sal_Bool bNext(pUsedList->GetFirstUsed(nKey));
1710 while(bNext)
1712 pFormat = pFormatter->GetEntry(nKey);
1713 if(pFormat)
1714 ExportFormat_Impl( *pFormat, nKey );
1715 bNext = pUsedList->GetNextUsed(nKey);
1717 if (!bIsAutoStyle)
1719 std::vector<sal_uInt16> aLanguages;
1720 pFormatter->GetUsedLanguages( aLanguages );
1721 for (std::vector<sal_uInt16>::const_iterator it(aLanguages.begin()); it != aLanguages.end(); ++it)
1723 LanguageType nLang = *it;
1725 sal_uInt32 nDefaultIndex = 0;
1726 SvNumberFormatTable& rTable = pFormatter->GetEntryTable(
1727 NUMBERFORMAT_DEFINED, nDefaultIndex, nLang );
1728 SvNumberFormatTable::iterator it2 = rTable.begin();
1729 while (it2 != rTable.end())
1731 nKey = it2->first;
1732 pFormat = it2->second;
1733 if (!pUsedList->IsUsed(nKey))
1735 DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found");
1736 // user-defined and used formats are exported
1737 ExportFormat_Impl( *pFormat, nKey );
1738 // if it is a user-defined Format it will be added else nothing will happen
1739 pUsedList->SetUsed(nKey);
1742 ++it2;
1746 pUsedList->Export();
1749 OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1751 if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
1752 return lcl_CreateStyleName( nKey, 0, sal_True, sPrefix );
1753 else
1755 OSL_FAIL("There is no written Data-Style");
1756 return OUString();
1760 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1762 DBG_ASSERT( pFormatter != NULL, "missing formatter" );
1763 if( !pFormatter )
1764 return;
1766 if (pFormatter->GetEntry(nKey))
1767 pUsedList->SetUsed( nKey );
1768 else {
1769 OSL_FAIL("no existing Numberformat found with this key");
1773 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
1775 if (pUsedList)
1776 pUsedList->GetWasUsed(rWasUsed);
1779 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1781 if (pUsedList)
1782 pUsedList->SetWasUsed(rWasUsed);
1787 static const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
1788 sal_uInt32 nKey )
1790 return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL;
1793 sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
1795 sal_uInt32 nRet = nKey;
1797 const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
1798 if( pFormat != NULL )
1800 DBG_ASSERT( pFormatter != NULL, "format without formatter?" );
1802 sal_Int32 nErrorPos;
1803 short nType = pFormat->GetType();
1805 sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
1806 nKey, LANGUAGE_SYSTEM );
1808 if( nNewKey != nKey )
1810 nRet = nNewKey;
1812 else
1814 OUString aFormatString( pFormat->GetFormatstring() );
1815 pFormatter->PutandConvertEntry(
1816 aFormatString,
1817 nErrorPos, nType, nNewKey,
1818 pFormat->GetLanguage(), LANGUAGE_SYSTEM );
1820 // success? Then use new key.
1821 if( nErrorPos == 0 )
1822 nRet = nNewKey;
1826 return nRet;
1829 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */