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