xref: /aoo42x/main/xmloff/source/style/xmlnumfe.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 
31 #define _SVSTDARR_ULONGS
32 #define _ZFORLIST_DECLARE_TABLE
33 
34 #include <svl/svstdarr.hxx>
35 #include <svl/zforlist.hxx>
36 #include <svl/zformat.hxx>
37 #include <svl/numuno.hxx>
38 #include <i18npool/mslangid.hxx>
39 #include <tools/debug.hxx>
40 #include <rtl/math.hxx>
41 #include <unotools/calendarwrapper.hxx>
42 #include <unotools/charclass.hxx>
43 #include <com/sun/star/lang/Locale.hpp>
44 #include <rtl/ustrbuf.hxx>
45 
46 // #110680#
47 //#include <comphelper/processfactory.hxx>
48 
49 #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
50 
51 #include <xmloff/xmlnumfe.hxx>
52 #include "xmloff/xmlnmspe.hxx"
53 #include <xmloff/xmluconv.hxx>
54 #include <xmloff/attrlist.hxx>
55 #include <xmloff/nmspmap.hxx>
56 #include <xmloff/families.hxx>
57 #include <xmloff/xmlnumfi.hxx>		// SvXMLNumFmtDefaults
58 
59 #define _SVSTDARR_USHORTS
60 #include <svl/svstdarr.hxx>
61 #include <svl/nfsymbol.hxx>
62 #include <xmloff/xmltoken.hxx>
63 #include <xmloff/xmlexp.hxx>
64 
65 #include <set>
66 
67 using ::rtl::OUString;
68 using ::rtl::OUStringBuffer;
69 
70 using namespace ::com::sun::star;
71 using namespace ::xmloff::token;
72 using namespace ::svt;
73 
74 //-------------------------------------------------------------------------
75 
76 //	4th condition for text formats doesn't work
77 //#define XMLNUM_MAX_PARTS	4
78 #define XMLNUM_MAX_PARTS	3
79 
80 //-------------------------------------------------------------------------
81 
82 struct LessuInt32
83 {
84 	sal_Bool operator() (const sal_uInt32 rValue1, const sal_uInt32 rValue2) const
85 	{
86 		return rValue1 < rValue2;
87 	}
88 };
89 
90 typedef std::set< sal_uInt32, LessuInt32 >	SvXMLuInt32Set;
91 
92 class SvXMLNumUsedList_Impl
93 {
94 	SvXMLuInt32Set				aUsed;
95 	SvXMLuInt32Set				aWasUsed;
96 	SvXMLuInt32Set::iterator	aCurrentUsedPos;
97 	sal_uInt32					nUsedCount;
98 	sal_uInt32					nWasUsedCount;
99 
100 public:
101 			SvXMLNumUsedList_Impl();
102 			~SvXMLNumUsedList_Impl();
103 
104 	void		SetUsed( sal_uInt32 nKey );
105 	sal_Bool	IsUsed( sal_uInt32 nKey ) const;
106 	sal_Bool	IsWasUsed( sal_uInt32 nKey ) const;
107 	void		Export();
108 
109 	sal_Bool	GetFirstUsed(sal_uInt32& nKey);
110 	sal_Bool	GetNextUsed(sal_uInt32& nKey);
111 
112 	void GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed);
113 	void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
114 };
115 
116 //-------------------------------------------------------------------------
117 
118 struct SvXMLEmbeddedTextEntry
119 {
120 	sal_uInt16		nSourcePos;		// position in NumberFormat (to skip later)
121 	sal_Int32		nFormatPos;		// resulting position in embedded-text element
122 	rtl::OUString	aText;
123 
124 	SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const rtl::OUString& rT ) :
125 		nSourcePos(nSP), nFormatPos(nFP), aText(rT) {}
126 };
127 
128 typedef SvXMLEmbeddedTextEntry* SvXMLEmbeddedTextEntryPtr;
129 SV_DECL_PTRARR_DEL( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr, 4, 4 )
130 
131 //-------------------------------------------------------------------------
132 
133 SV_IMPL_PTRARR( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr );
134 
135 //-------------------------------------------------------------------------
136 
137 //
138 //!	SvXMLNumUsedList_Impl should be optimized!
139 //
140 
141 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
142 	nUsedCount(0),
143 	nWasUsedCount(0)
144 {
145 }
146 
147 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
148 {
149 }
150 
151 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
152 {
153 	if ( !IsWasUsed(nKey) )
154 	{
155 		std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
156 		if (aPair.second)
157 			nUsedCount++;
158 	}
159 }
160 
161 sal_Bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
162 {
163 	SvXMLuInt32Set::iterator aItr = aUsed.find(nKey);
164 	return (aItr != aUsed.end());
165 }
166 
167 sal_Bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
168 {
169 	SvXMLuInt32Set::iterator aItr = aWasUsed.find(nKey);
170 	return (aItr != aWasUsed.end());
171 }
172 
173 void SvXMLNumUsedList_Impl::Export()
174 {
175 	SvXMLuInt32Set::iterator aItr = aUsed.begin();
176 	while (aItr != aUsed.end())
177 	{
178 		std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *aItr );
179 		if (aPair.second)
180 			nWasUsedCount++;
181 		aItr++;
182 	}
183 	aUsed.clear();
184 	nUsedCount = 0;
185 }
186 
187 sal_Bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey)
188 {
189 	sal_Bool bRet(sal_False);
190 	aCurrentUsedPos = aUsed.begin();
191 	if(nUsedCount)
192 	{
193 		DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
194 		nKey = *aCurrentUsedPos;
195 		bRet = sal_True;
196 	}
197 	return bRet;
198 }
199 
200 sal_Bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey)
201 {
202 	sal_Bool bRet(sal_False);
203 	if (aCurrentUsedPos != aUsed.end())
204 	{
205 		aCurrentUsedPos++;
206 		if (aCurrentUsedPos != aUsed.end())
207 		{
208 			nKey = *aCurrentUsedPos;
209 			bRet = sal_True;
210 		}
211 	}
212 	return bRet;
213 }
214 
215 void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
216 {
217 	rWasUsed.realloc(nWasUsedCount);
218 	sal_Int32* pWasUsed = rWasUsed.getArray();
219 	if (pWasUsed)
220 	{
221 		SvXMLuInt32Set::iterator aItr = aWasUsed.begin();
222 		while (aItr != aWasUsed.end())
223 		{
224 			*pWasUsed = *aItr;
225 			aItr++;
226 			pWasUsed++;
227 		}
228 	}
229 }
230 
231 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
232 {
233 	DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
234 	sal_Int32 nCount(rWasUsed.getLength());
235 	const sal_Int32* pWasUsed = rWasUsed.getConstArray();
236 	for (sal_uInt16 i = 0; i < nCount; i++, pWasUsed++)
237 	{
238 		std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *pWasUsed );
239 		if (aPair.second)
240 			nWasUsedCount++;
241 	}
242 }
243 
244 //-------------------------------------------------------------------------
245 
246 SvXMLNumFmtExport::SvXMLNumFmtExport(
247             SvXMLExport& rExp,
248 			const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
249 	rExport( rExp ),
250 	sPrefix( OUString::createFromAscii( "N" ) ),
251 	pFormatter( NULL ),
252 	pCharClass( NULL ),
253 	pLocaleData( NULL )
254 {
255 	//	supplier must be SvNumberFormatsSupplierObj
256 	SvNumberFormatsSupplierObj* pObj =
257 					SvNumberFormatsSupplierObj::getImplementation( rSupp );
258 	if (pObj)
259 		pFormatter = pObj->GetNumberFormatter();
260 
261 	if ( pFormatter )
262 	{
263 		pCharClass = new CharClass( pFormatter->GetServiceManager(),
264 			pFormatter->GetLocale() );
265 		pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
266 			pFormatter->GetLocale() );
267 	}
268 	else
269 	{
270 		lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
271 
272 		// #110680#
273 		// pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
274 		// pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
275 		pCharClass = new CharClass( rExport.getServiceFactory(), aLocale );
276 		pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale );
277 	}
278 
279 	pUsedList = new SvXMLNumUsedList_Impl;
280 }
281 
282 SvXMLNumFmtExport::SvXMLNumFmtExport(
283                        SvXMLExport& rExp,
284 					   const ::com::sun::star::uno::Reference<
285 						::com::sun::star::util::XNumberFormatsSupplier >& rSupp,
286 					   const rtl::OUString& rPrefix ) :
287 	rExport( rExp ),
288 	sPrefix( rPrefix ),
289 	pFormatter( NULL ),
290 	pCharClass( NULL ),
291 	pLocaleData( NULL )
292 {
293 	//	supplier must be SvNumberFormatsSupplierObj
294 	SvNumberFormatsSupplierObj* pObj =
295 					SvNumberFormatsSupplierObj::getImplementation( rSupp );
296 	if (pObj)
297 		pFormatter = pObj->GetNumberFormatter();
298 
299 	if ( pFormatter )
300 	{
301 		pCharClass = new CharClass( pFormatter->GetServiceManager(),
302 			pFormatter->GetLocale() );
303 		pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
304 			pFormatter->GetLocale() );
305 	}
306 	else
307 	{
308 		lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
309 
310 		// #110680#
311 		// pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
312 		// pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
313 		pCharClass = new CharClass( rExport.getServiceFactory(), aLocale );
314 		pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale );
315 	}
316 
317 	pUsedList = new SvXMLNumUsedList_Impl;
318 }
319 
320 SvXMLNumFmtExport::~SvXMLNumFmtExport()
321 {
322 	delete pUsedList;
323 	delete pLocaleData;
324 	delete pCharClass;
325 }
326 
327 //-------------------------------------------------------------------------
328 
329 //
330 //	helper methods
331 //
332 
333 OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, sal_Bool bDefPart, const rtl::OUString& rPrefix )
334 {
335 	OUStringBuffer aFmtName( 10L );
336 	aFmtName.append( rPrefix );
337 	aFmtName.append( nKey );
338 	if (!bDefPart)
339 	{
340 		aFmtName.append( (sal_Unicode)'P' );
341 		aFmtName.append( nPart );
342 	}
343 	return aFmtName.makeStringAndClear();
344 }
345 
346 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
347 {
348 	if ( rCalendar.getLength() )
349 	{
350 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar );
351 	}
352 }
353 
354 void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText )
355 {
356 	if ( bText )			// non-textual
357 	{
358 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE );
359 	}
360 }
361 
362 void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong )
363 {
364 	if ( bLong )			// short is default
365 	{
366 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG );
367 	}
368 }
369 
370 void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang )
371 {
372 	if ( nLang != LANGUAGE_SYSTEM )
373 	{
374 		OUString aLangStr, aCountryStr;
375         MsLangId::convertLanguageToIsoNames( (LanguageType)nLang, aLangStr, aCountryStr );
376 
377 		if (aLangStr.getLength())
378 			rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_LANGUAGE, aLangStr );
379 		if (aCountryStr.getLength())
380 			rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_COUNTRY, aCountryStr );
381 	}
382 }
383 
384 //-------------------------------------------------------------------------
385 
386 //
387 //	methods to write individual elements within a format
388 //
389 
390 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString )
391 {
392 	//	append to sTextContent, write element in FinishTextElement_Impl
393 	//	to avoid several text elements following each other
394 
395 	sTextContent.append( rString );
396 }
397 
398 void SvXMLNumFmtExport::FinishTextElement_Impl()
399 {
400 	if ( sTextContent.getLength() )
401 	{
402         SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
403                                   sal_True, sal_False );
404 		rExport.Characters( sTextContent.makeStringAndClear() );
405 	}
406 }
407 
408 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor )
409 {
410 	FinishTextElement_Impl();
411 
412 	OUStringBuffer aColStr( 7 );
413 	SvXMLUnitConverter::convertColor( aColStr, rColor );
414 	rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR,
415                           aColStr.makeStringAndClear() );
416 
417     SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES,
418                               sal_True, sal_False );
419 }
420 
421 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString,
422 													const OUString& rExt )
423 {
424 	FinishTextElement_Impl();
425 
426 	if ( rExt.getLength() )
427 	{
428 		sal_Int32 nLang = rExt.toInt32(16);		// hex
429 		if ( nLang < 0 )						// extension string may contain "-" separator
430 			nLang = -nLang;
431 		AddLanguageAttr_Impl( nLang );			// adds to pAttrList
432 	}
433 
434     SvXMLElementExport aElem( rExport,
435                               XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL,
436                               sal_True, sal_False );
437 	rExport.Characters( rString );
438 }
439 
440 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
441 {
442 	FinishTextElement_Impl();
443 
444     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN,
445                               sal_True, sal_False );
446 }
447 
448 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
449 {
450 	FinishTextElement_Impl();
451 
452     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT,
453                               sal_True, sal_False );
454 }
455 
456 //	date elements
457 
458 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, sal_Bool bLong )
459 {
460 	FinishTextElement_Impl();
461 
462 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
463 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
464 
465     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY,
466                               sal_True, sal_False );
467 }
468 
469 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, sal_Bool bLong, sal_Bool bText )
470 {
471 	FinishTextElement_Impl();
472 
473 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
474 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
475 	AddTextualAttr_Impl( bText );	// adds to pAttrList
476 
477     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH,
478                               sal_True, sal_False );
479 }
480 
481 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, sal_Bool bLong )
482 {
483 	FinishTextElement_Impl();
484 
485 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
486 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
487 
488     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR,
489                               sal_True, sal_False );
490 }
491 
492 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, sal_Bool bLong )
493 {
494 	FinishTextElement_Impl();
495 
496 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
497 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
498 
499     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA,
500                               sal_True, sal_False );
501 }
502 
503 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, sal_Bool bLong )
504 {
505 	FinishTextElement_Impl();
506 
507 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
508 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
509 
510     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK,
511                               sal_True, sal_False );
512 }
513 
514 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
515 {
516 	FinishTextElement_Impl();
517 
518 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
519 
520     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR,
521                               sal_True, sal_False );
522 }
523 
524 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, sal_Bool bLong )
525 {
526 	FinishTextElement_Impl();
527 
528 	AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
529 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
530 
531     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER,
532                               sal_True, sal_False );
533 }
534 
535 //	time elements
536 
537 void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong )
538 {
539 	FinishTextElement_Impl();
540 
541 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
542 
543     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS,
544                               sal_True, sal_False );
545 }
546 
547 void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong )
548 {
549 	FinishTextElement_Impl();
550 
551 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
552 
553     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES,
554                               sal_True, sal_False );
555 }
556 
557 void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong, sal_uInt16 nDecimals )
558 {
559 	FinishTextElement_Impl();
560 
561 	AddStyleAttr_Impl( bLong );		// adds to pAttrList
562 	if ( nDecimals > 0 )
563 	{
564 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
565                               OUString::valueOf( (sal_Int32) nDecimals ) );
566 	}
567 
568     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS,
569                               sal_True, sal_False );
570 }
571 
572 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
573 {
574 	FinishTextElement_Impl();
575 
576     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM,
577                               sal_True, sal_False );
578 }
579 
580 //	numbers
581 
582 void SvXMLNumFmtExport::WriteNumberElement_Impl(
583 							sal_Int32 nDecimals, sal_Int32 nInteger,
584 							const OUString& rDashStr, sal_Bool bVarDecimals,
585 							sal_Bool bGrouping, sal_Int32 nTrailingThousands,
586 							const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
587 {
588 	FinishTextElement_Impl();
589 
590 	//	decimals
591 	if ( nDecimals >= 0 )	// negative = automatic
592 	{
593         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
594                               OUString::valueOf( nDecimals ) );
595 	}
596 
597 	//	integer digits
598 	if ( nInteger >= 0 )	// negative = automatic
599 	{
600         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
601                               OUString::valueOf( nInteger ) );
602 	}
603 
604 	//	decimal replacement (dashes) or variable decimals (#)
605 	if ( rDashStr.getLength() || bVarDecimals )
606 	{
607 		//	variable decimals means an empty replacement string
608 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,
609                               rDashStr );
610 	}
611 
612 	//	(automatic) grouping separator
613 	if ( bGrouping )
614 	{
615 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
616 	}
617 
618 	//	display-factor if there are trailing thousands separators
619 	if ( nTrailingThousands )
620 	{
621 		//	each separator character removes three digits
622 		double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
623 
624 		OUStringBuffer aFactStr;
625 		SvXMLUnitConverter::convertDouble( aFactStr, fFactor );
626 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
627 	}
628 
629     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER,
630                               sal_True, sal_True );
631 
632 	//	number:embedded-text as child elements
633 
634 	sal_uInt16 nEntryCount = rEmbeddedEntries.Count();
635 	for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
636 	{
637 		SvXMLEmbeddedTextEntry* pObj = rEmbeddedEntries[nEntry];
638 
639 		//	position attribute
640 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION,
641 								OUString::valueOf( pObj->nFormatPos ) );
642 	    SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT,
643 			                              sal_True, sal_False );
644 
645 		//	text as element content
646         rtl::OUString aContent( pObj->aText );
647         while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1]->nFormatPos == pObj->nFormatPos )
648         {
649             // The array can contain several elements for the same position in the number
650             // (for example, literal text and space from underscores). They must be merged
651             // into a single embedded-text element.
652             aContent += rEmbeddedEntries[nEntry+1]->aText;
653             ++nEntry;
654         }
655         rExport.Characters( aContent );
656 	}
657 }
658 
659 void SvXMLNumFmtExport::WriteScientificElement_Impl(
660 							sal_Int32 nDecimals, sal_Int32 nInteger,
661 							sal_Bool bGrouping, sal_Int32 nExp )
662 {
663 	FinishTextElement_Impl();
664 
665 	//	decimals
666 	if ( nDecimals >= 0 )	// negative = automatic
667 	{
668 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
669                               OUString::valueOf( nDecimals ) );
670 	}
671 
672 	//	integer digits
673 	if ( nInteger >= 0 )	// negative = automatic
674 	{
675         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
676                               OUString::valueOf( nInteger ) );
677 	}
678 
679 	//	(automatic) grouping separator
680 	if ( bGrouping )
681 	{
682 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
683 	}
684 
685 	//	exponent digits
686 	if ( nExp >= 0 )
687 	{
688         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,
689                               OUString::valueOf( nExp ) );
690 	}
691 
692     SvXMLElementExport aElem( rExport,
693                               XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,
694                               sal_True, sal_False );
695 }
696 
697 void SvXMLNumFmtExport::WriteFractionElement_Impl(
698 							sal_Int32 nInteger, sal_Bool bGrouping,
699 							sal_Int32 nNumerator, sal_Int32 nDenominator )
700 {
701 	FinishTextElement_Impl();
702 
703 	//	integer digits
704 	if ( nInteger >= 0 )		// negative = default (no integer part)
705 	{
706 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
707                               OUString::valueOf( nInteger ) );
708 	}
709 
710 	//	(automatic) grouping separator
711 	if ( bGrouping )
712 	{
713 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
714 	}
715 
716 	//	numerator digits
717 	if ( nNumerator >= 0 )
718 	{
719 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,
720                                  OUString::valueOf( nNumerator ) );
721 	}
722 
723 	//	denominator digits
724 	if ( nDenominator >= 0 )
725 	{
726 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,
727                               OUString::valueOf( nDenominator ) );
728 	}
729 
730     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION,
731                               sal_True, sal_False );
732 }
733 
734 //	mapping (condition)
735 
736 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
737 												sal_Int32 nKey, sal_Int32 nPart )
738 {
739 	FinishTextElement_Impl();
740 
741 	if ( nOp != NUMBERFORMAT_OP_NO )
742 	{
743 		// style namespace
744 
745 		OUStringBuffer aCondStr( 20L );
746 		aCondStr.appendAscii( "value()" );			//! define constant
747 		switch ( nOp )
748 		{
749 			case NUMBERFORMAT_OP_EQ: aCondStr.append( (sal_Unicode) '=' );	break;
750 			case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "<>" );			break;
751 			case NUMBERFORMAT_OP_LT: aCondStr.append( (sal_Unicode) '<' );	break;
752 			case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" );			break;
753 			case NUMBERFORMAT_OP_GT: aCondStr.append( (sal_Unicode) '>' );	break;
754 			case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" );			break;
755 			default:
756 				DBG_ERROR("unknown operator");
757 		}
758         ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
759                 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
760                 '.', true );
761 
762 		rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION,
763                               aCondStr.makeStringAndClear() );
764 
765 		rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME,
766                               rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, sal_False,
767                                                    sPrefix ) ) );
768 
769         SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP,
770                                   sal_True, sal_False );
771 	}
772 }
773 
774 //-------------------------------------------------------------------------
775 //	for old (automatic) currency formats: parse currency symbol from text
776 
777 xub_StrLen lcl_FindSymbol( const String& sUpperStr, const String& sCurString )
778 {
779 	//	search for currency symbol
780 	//	Quoting as in ImpSvNumberformatScan::Symbol_Division
781 
782 	xub_StrLen nCPos = 0;
783 	while (nCPos != STRING_NOTFOUND)
784 	{
785 		nCPos = sUpperStr.Search( sCurString, nCPos );
786 		if (nCPos != STRING_NOTFOUND)
787 		{
788 			// in Quotes?
789 			xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
790 			if ( nQ == STRING_NOTFOUND )
791 			{
792 				//	dm can be escaped as "dm or \d
793 				sal_Unicode c;
794 				if ( nCPos == 0 ||
795 					((c = sUpperStr.GetChar(xub_StrLen(nCPos-1))) != '"'
796 							&& c != '\\') )
797 				{
798 					return nCPos;					// found
799 				}
800 				else
801 					nCPos++;						// continue
802 			}
803 			else
804 				nCPos = nQ + 1;						// continue after quote end
805 		}
806 	}
807 	return STRING_NOTFOUND;							// not found
808 }
809 
810 sal_Bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
811 							const ::com::sun::star::lang::Locale& rLocale )
812 {
813 	//	returns sal_True if currency element was written
814 
815 	sal_Bool bRet = sal_False;
816 
817 //	pLocaleData->setLocale( rLocale );
818 //	String sCurString = pLocaleData->getCurrSymbol();
819 
820 	LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale );
821 	pFormatter->ChangeIntl( nLang );
822 	String sCurString, sDummy;
823 	pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
824 
825 	pCharClass->setLocale( rLocale );
826 	String sUpperStr = pCharClass->upper(rString);
827 	xub_StrLen nPos = lcl_FindSymbol( sUpperStr, sCurString );
828 	if ( nPos != STRING_NOTFOUND )
829 	{
830 		sal_Int32 nLength = rString.getLength();
831 		sal_Int32 nCurLen = sCurString.Len();
832 		sal_Int32 nCont = nPos + nCurLen;
833 
834 		//	text before currency symbol
835 		if ( nPos > 0 )
836 			AddToTextElement_Impl( rString.copy( 0, nPos ) );
837 
838 		//	currency symbol (empty string -> default)
839 		OUString sEmpty;
840 		WriteCurrencyElement_Impl( sEmpty, sEmpty );
841 		bRet = sal_True;
842 
843 		//	text after currency symbol
844 		if ( nCont < nLength )
845 			AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
846 	}
847 	else
848 		AddToTextElement_Impl( rString );		// simple text
849 
850 	return bRet;		// sal_True: currency element written
851 }
852 
853 //-------------------------------------------------------------------------
854 
855 OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang )
856 {
857 	//	get name of first non-gregorian calendar for the language
858 
859 	OUString aCalendar;
860 	CalendarWrapper* pCalendar = pFormatter->GetCalendar();
861 	if (pCalendar)
862 	{
863 		lang::Locale aLocale( MsLangId::convertLanguageToLocale( nLang ) );
864 
865 		uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
866 		sal_Int32 nCnt = aCals.getLength();
867 		sal_Bool bFound = sal_False;
868 		for ( sal_Int32 j=0; j < nCnt && !bFound; j++ )
869 		{
870 			if ( !aCals[j].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gregorian") ) )
871 			{
872 				aCalendar = aCals[j];
873 				bFound = sal_True;
874 			}
875 		}
876 	}
877 	return aCalendar;
878 }
879 
880 //-------------------------------------------------------------------------
881 
882 sal_Bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
883 {
884 	sal_uInt16 nCount = rEmbeddedEntries.Count();
885 	for (sal_uInt16 i=0; i<nCount; i++)
886 		if ( rEmbeddedEntries[i]->nSourcePos == nPos )
887 			return sal_True;
888 
889 	return sal_False;		// not found
890 }
891 
892 sal_Bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, sal_Bool bSystemDate, NfIndexTableOffset eBuiltIn )
893 {
894 	//	make an extra loop to collect date elements, to check if it is a default format
895 	//	before adding the automatic-order attribute
896 
897 	SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE;
898 	SvXMLDateElementAttributes eDateDay = XML_DEA_NONE;
899 	SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE;
900 	SvXMLDateElementAttributes eDateYear = XML_DEA_NONE;
901 	SvXMLDateElementAttributes eDateHours = XML_DEA_NONE;
902 	SvXMLDateElementAttributes eDateMins = XML_DEA_NONE;
903 	SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE;
904 	sal_Bool bDateNoDefault = sal_False;
905 
906 	sal_uInt16 nPos = 0;
907 	sal_Bool bEnd = sal_False;
908 	short nLastType = 0;
909 	while (!bEnd)
910 	{
911 		short nElemType = rFormat.GetNumForType( 0, nPos, sal_False );
912 		switch ( nElemType )
913 		{
914 			case 0:
915 				if ( nLastType == NF_SYMBOLTYPE_STRING )
916 					bDateNoDefault = sal_True;	// text at the end -> no default date format
917 				bEnd = sal_True;				// end of format reached
918 				break;
919 			case NF_SYMBOLTYPE_STRING:
920 			case NF_SYMBOLTYPE_DATESEP:
921 			case NF_SYMBOLTYPE_TIMESEP:
922 			case NF_SYMBOLTYPE_TIME100SECSEP:
923 				// text is ignored, except at the end
924 				break;
925 			// same mapping as in SvXMLNumFormatContext::AddNfKeyword:
926 			case NF_KEY_NN:		eDateDOW = XML_DEA_SHORT;		break;
927 			case NF_KEY_NNN:
928 			case NF_KEY_NNNN:	eDateDOW = XML_DEA_LONG;		break;
929 			case NF_KEY_D:		eDateDay = XML_DEA_SHORT;		break;
930 			case NF_KEY_DD:		eDateDay = XML_DEA_LONG;		break;
931 			case NF_KEY_M:		eDateMonth = XML_DEA_SHORT;		break;
932 			case NF_KEY_MM:		eDateMonth = XML_DEA_LONG;		break;
933 			case NF_KEY_MMM:	eDateMonth = XML_DEA_TEXTSHORT;	break;
934 			case NF_KEY_MMMM:	eDateMonth = XML_DEA_TEXTLONG;	break;
935 			case NF_KEY_YY:		eDateYear = XML_DEA_SHORT;		break;
936 			case NF_KEY_YYYY:	eDateYear = XML_DEA_LONG;		break;
937 			case NF_KEY_H:		eDateHours = XML_DEA_SHORT;		break;
938 			case NF_KEY_HH:		eDateHours = XML_DEA_LONG;		break;
939 			case NF_KEY_MI:		eDateMins = XML_DEA_SHORT;		break;
940 			case NF_KEY_MMI:	eDateMins = XML_DEA_LONG;		break;
941 			case NF_KEY_S:		eDateSecs = XML_DEA_SHORT;		break;
942 			case NF_KEY_SS:		eDateSecs = XML_DEA_LONG;		break;
943 			case NF_KEY_AP:
944 			case NF_KEY_AMPM:	break;			// AM/PM may or may not be in date/time formats -> ignore by itself
945 			default:
946 				bDateNoDefault = sal_True;		// any other element -> no default format
947 		}
948 		nLastType = nElemType;
949 		++nPos;
950 	}
951 
952 	if ( bDateNoDefault )
953 		return sal_False;						// additional elements
954 	else
955 	{
956 		NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
957 				eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate );
958 
959 		return ( eFound == eBuiltIn );
960 	}
961 }
962 
963 //
964 //	export one part (condition)
965 //
966 
967 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
968 											sal_uInt16 nPart, sal_Bool bDefPart )
969 {
970 	//!	for the default part, pass the coditions from the other parts!
971 
972 	//
973 	//	element name
974 	//
975 
976 	NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
977 
978 	short nFmtType = 0;
979 	sal_Bool bThousand = sal_False;
980 	sal_uInt16 nPrecision = 0;
981 	sal_uInt16 nLeading = 0;
982 	rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
983 	nFmtType &= ~NUMBERFORMAT_DEFINED;
984 
985 	//	special treatment of builtin formats that aren't detected by normal parsing
986 	//	(the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
987 	if ( eBuiltIn == NF_NUMBER_STANDARD )
988 		nFmtType = NUMBERFORMAT_NUMBER;
989 	else if ( eBuiltIn == NF_BOOLEAN )
990 		nFmtType = NUMBERFORMAT_LOGICAL;
991 	else if ( eBuiltIn == NF_TEXT )
992 		nFmtType = NUMBERFORMAT_TEXT;
993 
994     // #101606# An empty subformat is a valid number-style resulting in an
995     // empty display string for the condition of the subformat.
996     if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart,
997                 0, sal_False ) == 0 )
998         nFmtType = 0;
999 
1000 	XMLTokenEnum eType = XML_TOKEN_INVALID;
1001 	switch ( nFmtType )
1002 	{
1003 		// type is 0 if a format contains no recognized elements
1004 		// (like text only) - this is handled as a number-style.
1005 		case 0:
1006 		case NUMBERFORMAT_NUMBER:
1007 		case NUMBERFORMAT_SCIENTIFIC:
1008 		case NUMBERFORMAT_FRACTION:
1009 			eType = XML_NUMBER_STYLE;
1010 			break;
1011 		case NUMBERFORMAT_PERCENT:
1012 			eType = XML_PERCENTAGE_STYLE;
1013 			break;
1014 		case NUMBERFORMAT_CURRENCY:
1015 			eType = XML_CURRENCY_STYLE;
1016 			break;
1017 		case NUMBERFORMAT_DATE:
1018 		case NUMBERFORMAT_DATETIME:
1019 			eType = XML_DATE_STYLE;
1020 			break;
1021 		case NUMBERFORMAT_TIME:
1022 			eType = XML_TIME_STYLE;
1023 			break;
1024 		case NUMBERFORMAT_TEXT:
1025 			eType = XML_TEXT_STYLE;
1026 			break;
1027 		case NUMBERFORMAT_LOGICAL:
1028 			eType = XML_BOOLEAN_STYLE;
1029 			break;
1030 	}
1031     DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" );
1032 
1033 	OUString sAttrValue;
1034 	sal_Bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 );
1035 
1036 	//
1037 	//	common attributes for format
1038 	//
1039 
1040 	//	format name (generated from key) - style namespace
1041 	rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
1042                         lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
1043 
1044 	//	"volatile" attribute for styles used only in maps
1045 	if ( !bDefPart )
1046 		rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE );
1047 
1048 	//	language / country
1049 	LanguageType nLang = rFormat.GetLanguage();
1050 	AddLanguageAttr_Impl( nLang );					// adds to pAttrList
1051 
1052 	//	title (comment)
1053 	//	titles for builtin formats are not written
1054 	sAttrValue = rFormat.GetComment();
1055 	if ( sAttrValue.getLength() && bUserDef && bDefPart )
1056 	{
1057 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue );
1058 	}
1059 
1060 	//	automatic ordering for currency and date formats
1061 	//	only used for some built-in formats
1062 	sal_Bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT     || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1063 						eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1064 						eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1065 						eBuiltIn == NF_DATE_SYSTEM_SHORT	|| eBuiltIn == NF_DATE_SYSTEM_LONG ||
1066 						eBuiltIn == NF_DATE_SYS_MMYY		|| eBuiltIn == NF_DATE_SYS_DDMMM ||
1067 						eBuiltIn == NF_DATE_SYS_DDMMYYYY	|| eBuiltIn == NF_DATE_SYS_DDMMYY ||
1068 						eBuiltIn == NF_DATE_SYS_DMMMYY		|| eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1069 						eBuiltIn == NF_DATE_SYS_DMMMMYYYY	|| eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1070 						eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1071 						eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1072 
1073 	//	format source (for date and time formats)
1074 	//	only used for some built-in formats
1075 	sal_Bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1076 						 eBuiltIn == NF_DATE_SYSTEM_LONG  ||
1077 						 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1078 	sal_Bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1079 
1080 	// check if the format definition matches the key
1081 	if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) &&
1082 			!lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1083 	{
1084 		bAutoOrder = bSystemDate = bLongSysDate = sal_False;		// don't write automatic-order attribute then
1085 	}
1086 
1087 	if ( bAutoOrder &&
1088 		( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1089 	{
1090 		//	#85109# format type must be checked to avoid dtd errors if
1091 		//	locale data contains other format types at the built-in positions
1092 
1093 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,
1094                               XML_TRUE );
1095 	}
1096 
1097 	if ( bSystemDate && bAutoOrder &&
1098 		( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1099 	{
1100 		//	#85109# format type must be checked to avoid dtd errors if
1101 		//	locale data contains other format types at the built-in positions
1102 
1103 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,
1104                               XML_LANGUAGE );
1105 	}
1106 
1107 	//	overflow for time formats as in [hh]:mm
1108 	//	controlled by bThousand from number format info
1109 	//	default for truncate-on-overflow is true
1110 	if ( nFmtType == NUMBERFORMAT_TIME && bThousand )
1111 	{
1112 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,
1113                               XML_FALSE );
1114 	}
1115 
1116     //
1117     // Native number transliteration
1118     //
1119     ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr;
1120     rFormat.GetNatNumXml( aAttr, nPart );
1121     if ( aAttr.Format.getLength() )
1122     {
1123 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,
1124                               aAttr.Format );
1125 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,
1126                               aAttr.Locale.Language );
1127 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,
1128                               aAttr.Locale.Country );
1129 		rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,
1130                               aAttr.Style );
1131     }
1132 
1133     //
1134     // The element
1135     //
1136     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
1137                               sal_True, sal_True );
1138 
1139 	//
1140 	//	color (properties element)
1141 	//
1142 
1143 	const Color* pCol = rFormat.GetColor( nPart );
1144 	if (pCol)
1145 		WriteColorElement_Impl(*pCol);
1146 
1147 
1148 	//	detect if there is "real" content, excluding color and maps
1149 	//!	move to implementation of Write... methods?
1150 	sal_Bool bAnyContent = sal_False;
1151 
1152 	//
1153 	//	format elements
1154 	//
1155 
1156 	SvXMLEmbeddedTextEntryArr aEmbeddedEntries(0);
1157 	if ( eBuiltIn == NF_NUMBER_STANDARD )
1158 	{
1159 		//	default number format contains just one number element
1160 		WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1161 		bAnyContent = sal_True;
1162 	}
1163 	else if ( eBuiltIn == NF_BOOLEAN )
1164 	{
1165 		//	boolean format contains just one boolean element
1166 		WriteBooleanElement_Impl();
1167 		bAnyContent = sal_True;
1168 	}
1169 	else
1170 	{
1171 		//	first loop to collect attributes
1172 
1173 		sal_Bool bDecDashes  = sal_False;
1174 		sal_Bool bVarDecimals = sal_False;
1175 		sal_Bool bExpFound   = sal_False;
1176 		sal_Bool bCurrFound  = sal_False;
1177 		sal_Bool bInInteger  = sal_True;
1178 		sal_Int32 nExpDigits = 0;
1179 		sal_Int32 nIntegerSymbols = 0;			// for embedded-text, including "#"
1180 		sal_Int32 nTrailingThousands = 0;		// thousands-separators after all digits
1181 		OUString sCurrExt;
1182 		OUString aCalendar;
1183 		sal_uInt16 nPos = 0;
1184 		sal_Bool bEnd = sal_False;
1185 		while (!bEnd)
1186 		{
1187 			short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1188 			const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1189 
1190 			switch ( nElemType )
1191 			{
1192 				case 0:
1193 					bEnd = sal_True;				// end of format reached
1194 					break;
1195 				case NF_SYMBOLTYPE_DIGIT:
1196 					if ( bExpFound && pElemStr )
1197 						nExpDigits += pElemStr->Len();
1198 					else if ( !bDecDashes && pElemStr && pElemStr->GetChar(0) == '-' )
1199 						bDecDashes = sal_True;
1200 					else if ( !bVarDecimals && !bInInteger && pElemStr && pElemStr->GetChar(0) == '#' )
1201 					{
1202 						//	If the decimal digits string starts with a '#', variable
1203 						//	decimals is assumed (for 0.###, but not 0.0##).
1204 						bVarDecimals = sal_True;
1205 					}
1206 					if ( bInInteger && pElemStr )
1207 						nIntegerSymbols += pElemStr->Len();
1208 					nTrailingThousands = 0;
1209 					break;
1210 				case NF_SYMBOLTYPE_DECSEP:
1211 					bInInteger = sal_False;
1212 					break;
1213 				case NF_SYMBOLTYPE_THSEP:
1214 					if (pElemStr)
1215 						nTrailingThousands += pElemStr->Len();		// is reset to 0 if digits follow
1216 					break;
1217 				case NF_SYMBOLTYPE_EXP:
1218 					bExpFound = sal_True;			// following digits are exponent digits
1219 					bInInteger = sal_False;
1220 					break;
1221 				case NF_SYMBOLTYPE_CURRENCY:
1222 					bCurrFound = sal_True;
1223 					break;
1224 				case NF_SYMBOLTYPE_CURREXT:
1225 					if (pElemStr)
1226 						sCurrExt = *pElemStr;
1227 					break;
1228 
1229 				// E, EE, R, RR: select non-gregorian calendar
1230 				// AAA, AAAA: calendar is switched at the position of the element
1231 				case NF_KEY_EC:
1232 				case NF_KEY_EEC:
1233 				case NF_KEY_R:
1234 				case NF_KEY_RR:
1235 					if (!aCalendar.getLength())
1236 						aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1237 					break;
1238 			}
1239 			++nPos;
1240 		}
1241 
1242 		//	collect strings for embedded-text (must be known before number element is written)
1243 
1244 		sal_Bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER ||
1245 										nFmtType == NUMBERFORMAT_CURRENCY ||
1246 										nFmtType == NUMBERFORMAT_PERCENT );
1247 		if ( bAllowEmbedded )
1248 		{
1249 			sal_Int32 nDigitsPassed = 0;
1250 			nPos = 0;
1251 			bEnd = sal_False;
1252 			while (!bEnd)
1253 			{
1254 				short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1255 				const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1256 
1257 				switch ( nElemType )
1258 				{
1259 					case 0:
1260 						bEnd = sal_True;				// end of format reached
1261 						break;
1262 					case NF_SYMBOLTYPE_DIGIT:
1263 						if ( pElemStr )
1264 							nDigitsPassed += pElemStr->Len();
1265 						break;
1266 					case NF_SYMBOLTYPE_STRING:
1267                     case NF_SYMBOLTYPE_BLANK:
1268                     case NF_SYMBOLTYPE_PERCENT:
1269 						if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
1270 						{
1271                             //	text (literal or underscore) within the integer part of a number:number element
1272 
1273                             String aEmbeddedStr;
1274                             if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1275                                 aEmbeddedStr = *pElemStr;
1276                             else
1277                                 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, pElemStr->GetChar(1) );
1278 
1279 							sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1280 
1281 							SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr );
1282 							aEmbeddedEntries.Insert( pObj, aEmbeddedEntries.Count() );
1283 						}
1284 						break;
1285 				}
1286 				++nPos;
1287 			}
1288 		}
1289 
1290 		//	final loop to write elements
1291 
1292 		sal_Bool bNumWritten = sal_False;
1293 		sal_Bool bCurrencyWritten = sal_False;
1294 		short nPrevType = 0;
1295 		nPos = 0;
1296 		bEnd = sal_False;
1297 		while (!bEnd)
1298 		{
1299 			short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1300 			const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1301 
1302 			switch ( nElemType )
1303 			{
1304 				case 0:
1305 					bEnd = sal_True;				// end of format reached
1306 					break;
1307 				case NF_SYMBOLTYPE_STRING:
1308                 case NF_SYMBOLTYPE_DATESEP:
1309                 case NF_SYMBOLTYPE_TIMESEP:
1310                 case NF_SYMBOLTYPE_TIME100SECSEP:
1311                 case NF_SYMBOLTYPE_PERCENT:
1312 					if (pElemStr)
1313 					{
1314 						if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1315 							 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1316 							 nPrecision > 0 )
1317 						{
1318 							//	decimal separator after seconds is implied by
1319 							//	"decimal-places" attribute and must not be written
1320 							//	as text element
1321 							//!	difference between '.' and ',' is lost here
1322 						}
1323 						else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1324 						{
1325 							//	text is written as embedded-text child of the number,
1326 							//	don't create a text element
1327 						}
1328 						else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten )
1329 						{
1330 							//	automatic currency symbol is implemented as part of
1331 							//	normal text -> search for the symbol
1332 							bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1333 								MsLangId::convertLanguageToLocale( nLang ) );
1334 							bAnyContent = sal_True;
1335 						}
1336 						else
1337 							AddToTextElement_Impl( *pElemStr );
1338 					}
1339 					break;
1340 				case NF_SYMBOLTYPE_BLANK:
1341 					if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1342 					{
1343 						//	turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1344                         //  (#i20396# the spaces may also be in embedded-text elements)
1345 
1346 						String aBlanks;
1347 						SvNumberformat::InsertBlanks( aBlanks, 0, pElemStr->GetChar(1) );
1348 						AddToTextElement_Impl( aBlanks );
1349 					}
1350 					break;
1351                 case NF_KEY_GENERAL :
1352                         WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1353                     break;
1354 				case NF_KEY_CCC:
1355 					if (pElemStr)
1356 					{
1357 						if ( bCurrencyWritten )
1358 							AddToTextElement_Impl( *pElemStr );		// never more than one currency element
1359 						else
1360 						{
1361 							//!	must be different from short automatic format
1362 							//!	but should still be empty (meaning automatic)
1363 							//	pElemStr is "CCC"
1364 
1365 							WriteCurrencyElement_Impl( *pElemStr, OUString() );
1366 							bAnyContent = sal_True;
1367 							bCurrencyWritten = sal_True;
1368 						}
1369 					}
1370 					break;
1371 				case NF_SYMBOLTYPE_CURRENCY:
1372 					if (pElemStr)
1373 					{
1374 						if ( bCurrencyWritten )
1375 							AddToTextElement_Impl( *pElemStr );		// never more than one currency element
1376 						else
1377 						{
1378 							WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1379 							bAnyContent = sal_True;
1380 							bCurrencyWritten = sal_True;
1381 						}
1382 					}
1383 					break;
1384 				case NF_SYMBOLTYPE_DIGIT:
1385 					if (!bNumWritten)			// write number part
1386 					{
1387 						switch ( nFmtType )
1388 						{
1389 							// for type 0 (not recognized as a special type),
1390 							// write a "normal" number
1391 							case 0:
1392 							case NUMBERFORMAT_NUMBER:
1393 							case NUMBERFORMAT_CURRENCY:
1394 							case NUMBERFORMAT_PERCENT:
1395 								{
1396 									//	decimals
1397 									//	only some built-in formats have automatic decimals
1398 									sal_Int32 nDecimals = nPrecision;	// from GetFormatSpecialInfo
1399 									if ( eBuiltIn == NF_NUMBER_STANDARD ||
1400 										 eBuiltIn == NF_CURRENCY_1000DEC2 ||
1401 										 eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1402 										 eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1403 										 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1404 										nDecimals = -1;
1405 
1406 									//	integer digits
1407 									//	only one built-in format has automatic integer digits
1408 									sal_Int32 nInteger = nLeading;
1409 									if ( eBuiltIn == NF_NUMBER_SYSTEM )
1410 										nInteger = -1;
1411 
1412 									//	string for decimal replacement
1413 									//	has to be taken from nPrecision
1414 									//	(positive number even for automatic decimals)
1415 									String sDashStr;
1416 									if ( bDecDashes && nPrecision > 0 )
1417 										sDashStr.Fill( nPrecision, '-' );
1418 
1419 									WriteNumberElement_Impl( nDecimals, nInteger, sDashStr, bVarDecimals,
1420 														bThousand, nTrailingThousands, aEmbeddedEntries );
1421 									bAnyContent = sal_True;
1422 								}
1423 								break;
1424 							case NUMBERFORMAT_SCIENTIFIC:
1425                                 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1426                                 // as integer digits: use nIntegerSymbols instead of nLeading
1427                                 // (use of '#' to select multiples in exponent might be added later)
1428                                 WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits );
1429 								bAnyContent = sal_True;
1430 								break;
1431 							case NUMBERFORMAT_FRACTION:
1432                                 {
1433                                     sal_Int32 nInteger = nLeading;
1434                                     if ( pElemStr && pElemStr->GetChar(0) == '?' )
1435                                     {
1436                                         //  If the first digit character is a question mark,
1437                                         //  the fraction doesn't have an integer part, and no
1438                                         //  min-integer-digits attribute must be written.
1439                                         nInteger = -1;
1440                                     }
1441                                     WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision );
1442                                     bAnyContent = sal_True;
1443                                 }
1444 								break;
1445 						}
1446 
1447 						bNumWritten = sal_True;
1448 					}
1449 					break;
1450                 case NF_SYMBOLTYPE_DECSEP:
1451                     if ( pElemStr && nPrecision == 0 )
1452                     {
1453                         //  A decimal separator after the number, without following decimal digits,
1454                         //  isn't modelled as part of the number element, so it's written as text
1455                         //  (the distinction between a quoted and non-quoted, locale-dependent
1456                         //  character is lost here).
1457 
1458                         AddToTextElement_Impl( *pElemStr );
1459                     }
1460                     break;
1461 				case NF_SYMBOLTYPE_DEL:
1462 					if ( pElemStr && *pElemStr == XubString('@') )
1463 					{
1464 						WriteTextContentElement_Impl();
1465 						bAnyContent = sal_True;
1466 					}
1467 					break;
1468 
1469 				case NF_SYMBOLTYPE_CALENDAR:
1470 					if ( pElemStr )
1471 						aCalendar = *pElemStr;
1472 					break;
1473 
1474 				// date elements:
1475 
1476 				case NF_KEY_D:
1477 				case NF_KEY_DD:
1478 					{
1479 						sal_Bool bLong = ( nElemType == NF_KEY_DD );
1480 						WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1481 						bAnyContent = sal_True;
1482 					}
1483 					break;
1484 				case NF_KEY_DDD:
1485 				case NF_KEY_DDDD:
1486 				case NF_KEY_NN:
1487 				case NF_KEY_NNN:
1488 				case NF_KEY_NNNN:
1489 				case NF_KEY_AAA:
1490 				case NF_KEY_AAAA:
1491 					{
1492 						OUString aCalAttr = aCalendar;
1493 						if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1494 						{
1495 							//	calendar attribute for AAA and AAAA is switched only for this element
1496 							if (!aCalAttr.getLength())
1497 								aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
1498 						}
1499 
1500 						sal_Bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1501 										   nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1502 						WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1503 						bAnyContent = sal_True;
1504 						if ( nElemType == NF_KEY_NNNN )
1505 						{
1506 							//	write additional text element for separator
1507 							pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
1508 							AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
1509 						}
1510 					}
1511 					break;
1512 				case NF_KEY_M:
1513 				case NF_KEY_MM:
1514 				case NF_KEY_MMM:
1515 				case NF_KEY_MMMM:
1516 				case NF_KEY_MMMMM:		//! first letter of month name, no attribute available
1517 					{
1518 						sal_Bool bLong = ( nElemType == NF_KEY_MM  || nElemType == NF_KEY_MMMM );
1519 						sal_Bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1520 											nElemType == NF_KEY_MMMMM );
1521 						WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1522 						bAnyContent = sal_True;
1523 					}
1524 					break;
1525 				case NF_KEY_YY:
1526 				case NF_KEY_YYYY:
1527 				case NF_KEY_EC:
1528 				case NF_KEY_EEC:
1529 				case NF_KEY_R:		//! R acts as EE, no attribute available
1530 					{
1531 						//! distinguish EE and R
1532 						//	calendar attribute for E and EE and R is set in first loop
1533 						sal_Bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1534 											nElemType == NF_KEY_R );
1535 						WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1536 						bAnyContent = sal_True;
1537 					}
1538 					break;
1539 				case NF_KEY_G:
1540 				case NF_KEY_GG:
1541 				case NF_KEY_GGG:
1542 				case NF_KEY_RR:		//! RR acts as GGGEE, no attribute available
1543 					{
1544 						//!	distinguish GG and GGG and RR
1545 						sal_Bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1546 						WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1547 						bAnyContent = sal_True;
1548 						if ( nElemType == NF_KEY_RR )
1549 						{
1550 							//	calendar attribute for RR is set in first loop
1551 							WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : sal_True ) );
1552 						}
1553 					}
1554 					break;
1555 				case NF_KEY_Q:
1556 				case NF_KEY_QQ:
1557 					{
1558 						sal_Bool bLong = ( nElemType == NF_KEY_QQ );
1559 						WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1560 						bAnyContent = sal_True;
1561 					}
1562 					break;
1563 				case NF_KEY_WW:
1564 					WriteWeekElement_Impl( aCalendar );
1565 					bAnyContent = sal_True;
1566 					break;
1567 
1568 				// time elements (bSystemDate is not used):
1569 
1570 				case NF_KEY_H:
1571 				case NF_KEY_HH:
1572 					WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1573 					bAnyContent = sal_True;
1574 					break;
1575 				case NF_KEY_MI:
1576 				case NF_KEY_MMI:
1577 					WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1578 					bAnyContent = sal_True;
1579 					break;
1580 				case NF_KEY_S:
1581 				case NF_KEY_SS:
1582 					WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1583 					bAnyContent = sal_True;
1584 					break;
1585 				case NF_KEY_AMPM:
1586 				case NF_KEY_AP:
1587 					WriteAMPMElement_Impl();		// short/long?
1588 					bAnyContent = sal_True;
1589 					break;
1590 			}
1591 			nPrevType = nElemType;
1592 			++nPos;
1593 		}
1594 	}
1595 
1596 	if ( sTextContent.getLength() )
1597 		bAnyContent = sal_True;		// element written in FinishTextElement_Impl
1598 
1599 	FinishTextElement_Impl();		// final text element - before maps
1600 
1601 	if ( !bAnyContent )
1602 	{
1603 		//	for an empty format, write an empty text element
1604         SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
1605                                    sal_True, sal_False );
1606 	}
1607 
1608 	//
1609 	//	mapping (conditions) must be last elements
1610 	//
1611 
1612 	if (bDefPart)
1613 	{
1614 		SvNumberformatLimitOps eOp1, eOp2;
1615 		double fLimit1, fLimit2;
1616 		rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1617 
1618 		WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1619 		WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1620 
1621 		if ( rFormat.HasTextFormat() )
1622 		{
1623 			//	4th part is for text -> make an "all other numbers" condition for the 3rd part
1624 			//	by reversing the 2nd condition
1625 
1626 			SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO;
1627 			double fLimit3 = fLimit2;
1628 			switch ( eOp2 )
1629 			{
1630 				case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1631 				case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1632 				case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1633 				case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1634 				case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1635 				case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1636 				default:
1637 					break;
1638 			}
1639 
1640 			if ( fLimit1 == fLimit2 &&
1641 					( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1642 					  ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1643 			{
1644 				//	For <x and >x, add =x as last condition
1645 				//	(just for readability, <=x would be valid, too)
1646 
1647 				eOp3 = NUMBERFORMAT_OP_EQ;
1648 			}
1649 
1650 			WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 );
1651 		}
1652 	}
1653 }
1654 
1655 //-------------------------------------------------------------------------
1656 
1657 //
1658 //	export one format
1659 //
1660 
1661 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
1662 {
1663 	sal_uInt16 nUsedParts = 0;
1664 	sal_uInt16 nPart;
1665 	for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++)
1666 		if (rFormat.GetNumForType( nPart, 0, sal_False ) != 0)
1667 			nUsedParts = nPart+1;
1668 
1669 	SvNumberformatLimitOps eOp1, eOp2;
1670 	double fLimit1, fLimit2;
1671 	rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1672 
1673 	//	if conditions are set, even empty formats must be written
1674 
1675 	if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 )
1676 		nUsedParts = 2;
1677 	if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
1678 		nUsedParts = 3;
1679 	if ( rFormat.HasTextFormat() && nUsedParts < 4 )
1680 		nUsedParts = 4;
1681 
1682 	for (nPart=0; nPart<nUsedParts; nPart++)
1683 	{
1684 		sal_Bool bDefault = ( nPart+1 == nUsedParts );			// last = default
1685 		ExportPart_Impl( rFormat, nKey, nPart, bDefault );
1686 	}
1687 }
1688 
1689 //-------------------------------------------------------------------------
1690 
1691 //
1692 //	export method called by application
1693 //
1694 
1695 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle )
1696 {
1697 	if ( !pFormatter )
1698 		return;							// no formatter -> no entries
1699 
1700 	sal_uInt32 nKey;
1701 	const SvNumberformat* pFormat = NULL;
1702 	sal_Bool bNext(pUsedList->GetFirstUsed(nKey));
1703 	while(bNext)
1704 	{
1705 		pFormat = pFormatter->GetEntry(nKey);
1706 		if(pFormat)
1707 			ExportFormat_Impl( *pFormat, nKey );
1708 		bNext = pUsedList->GetNextUsed(nKey);
1709 	}
1710 	if (!bIsAutoStyle)
1711 	{
1712 		SvUShorts aLanguages;
1713 		pFormatter->GetUsedLanguages( aLanguages );
1714 		sal_uInt16 nLangCount = aLanguages.Count();
1715 		for (sal_uInt16 nLangPos=0; nLangPos<nLangCount; nLangPos++)
1716 		{
1717 			LanguageType nLang = aLanguages[nLangPos];
1718 
1719 			sal_uInt32 nDefaultIndex = 0;
1720 			SvNumberFormatTable& rTable = pFormatter->GetEntryTable(
1721 											NUMBERFORMAT_DEFINED, nDefaultIndex, nLang );
1722 			pFormat = rTable.First();
1723 			while (pFormat)
1724 			{
1725 				nKey = rTable.GetCurKey();
1726 				if (!pUsedList->IsUsed(nKey))
1727 				{
1728 					DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found");
1729 					//	user-defined and used formats are exported
1730 					ExportFormat_Impl( *pFormat, nKey );
1731 					// if it is a user-defined Format it will be added else nothing will hapen
1732 					pUsedList->SetUsed(nKey);
1733 				}
1734 
1735 				pFormat = rTable.Next();
1736 			}
1737 		}
1738 	}
1739 	pUsedList->Export();
1740 }
1741 
1742 OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1743 {
1744 	if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
1745 		return lcl_CreateStyleName( nKey, 0, sal_True, sPrefix );
1746 	else
1747 	{
1748 		DBG_ERROR("There is no written Data-Style");
1749 		return rtl::OUString();
1750 	}
1751 }
1752 
1753 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1754 {
1755     DBG_ASSERT( pFormatter != NULL, "missing formatter" );
1756     if( !pFormatter )
1757         return;
1758 
1759 	if (pFormatter->GetEntry(nKey))
1760 		pUsedList->SetUsed( nKey );
1761 	else {
1762 		DBG_ERROR("no existing Numberformat found with this key");
1763     }
1764 }
1765 
1766 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
1767 {
1768 	if (pUsedList)
1769 		pUsedList->GetWasUsed(rWasUsed);
1770 }
1771 
1772 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1773 {
1774 	if (pUsedList)
1775 		pUsedList->SetWasUsed(rWasUsed);
1776 }
1777 
1778 
1779 
1780 const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
1781                            sal_uInt32 nKey )
1782 {
1783     return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL;
1784 }
1785 
1786 sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
1787 {
1788     sal_uInt32 nRet = nKey;
1789 
1790     const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
1791     if( pFormat != NULL )
1792     {
1793         DBG_ASSERT( pFormatter != NULL, "format without formatter?" );
1794 
1795         xub_StrLen nErrorPos;
1796         short nType = pFormat->GetType();
1797 
1798         sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
1799                        nKey, LANGUAGE_SYSTEM );
1800 
1801         if( nNewKey != nKey )
1802         {
1803             nRet = nNewKey;
1804         }
1805         else
1806         {
1807             String aFormatString( pFormat->GetFormatstring() );
1808             pFormatter->PutandConvertEntry(
1809                             aFormatString,
1810                             nErrorPos, nType, nNewKey,
1811                             pFormat->GetLanguage(), LANGUAGE_SYSTEM );
1812 
1813             // success? Then use new key.
1814             if( nErrorPos == 0 )
1815                 nRet = nNewKey;
1816         }
1817     }
1818 
1819     return nRet;
1820 }
1821