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 {
operator ()LessuInt3280 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
SvXMLEmbeddedTextEntrySvXMLEmbeddedTextEntry120 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
SvXMLNumUsedList_Impl()137 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
138 nUsedCount(0),
139 nWasUsedCount(0)
140 {
141 }
142
~SvXMLNumUsedList_Impl()143 SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
144 {
145 }
146
SetUsed(sal_uInt32 nKey)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
IsUsed(sal_uInt32 nKey) const157 sal_Bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
158 {
159 SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey);
160 return (aItr != aUsed.end());
161 }
162
IsWasUsed(sal_uInt32 nKey) const163 sal_Bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
164 {
165 SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey);
166 return (aItr != aWasUsed.end());
167 }
168
Export()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
GetFirstUsed(sal_uInt32 & nKey)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
GetNextUsed(sal_uInt32 & nKey)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
GetWasUsed(uno::Sequence<sal_Int32> & rWasUsed)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
SetWasUsed(const uno::Sequence<sal_Int32> & rWasUsed)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
SvXMLNumFmtExport(SvXMLExport & rExp,const uno::Reference<util::XNumberFormatsSupplier> & rSupp)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
SvXMLNumFmtExport(SvXMLExport & rExp,const::com::sun::star::uno::Reference<::com::sun::star::util::XNumberFormatsSupplier> & rSupp,const rtl::OUString & rPrefix)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
~SvXMLNumFmtExport()316 SvXMLNumFmtExport::~SvXMLNumFmtExport()
317 {
318 delete pUsedList;
319 delete pLocaleData;
320 delete pCharClass;
321 }
322
323 //-------------------------------------------------------------------------
324
325 //
326 // helper methods
327 //
328
lcl_CreateStyleName(sal_Int32 nKey,sal_Int32 nPart,sal_Bool bDefPart,const rtl::OUString & rPrefix)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
AddCalendarAttr_Impl(const OUString & rCalendar)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
AddTextualAttr_Impl(sal_Bool bText)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
AddStyleAttr_Impl(sal_Bool bLong)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
AddLanguageAttr_Impl(sal_Int32 nLang)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
AddToTextElement_Impl(const OUString & rString)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
FinishTextElement_Impl()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
WriteColorElement_Impl(const Color & rColor)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
WriteCurrencyElement_Impl(const OUString & rString,const OUString & rExt)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
WriteBooleanElement_Impl()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
WriteTextContentElement_Impl()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
WriteDayElement_Impl(const OUString & rCalendar,sal_Bool bLong)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
WriteMonthElement_Impl(const OUString & rCalendar,sal_Bool bLong,sal_Bool bText)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
WriteYearElement_Impl(const OUString & rCalendar,sal_Bool bLong)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
WriteEraElement_Impl(const OUString & rCalendar,sal_Bool bLong)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
WriteDayOfWeekElement_Impl(const OUString & rCalendar,sal_Bool bLong)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
WriteWeekElement_Impl(const OUString & rCalendar)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
WriteQuarterElement_Impl(const OUString & rCalendar,sal_Bool bLong)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
WriteHoursElement_Impl(sal_Bool bLong)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
WriteMinutesElement_Impl(sal_Bool bLong)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
WriteSecondsElement_Impl(sal_Bool bLong,sal_uInt16 nDecimals)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
WriteAMPMElement_Impl()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
WriteNumberElement_Impl(sal_Int32 nDecimals,sal_Int32 nInteger,const OUString & rDashStr,sal_Bool bVarDecimals,sal_Bool bGrouping,sal_Int32 nTrailingThousands,const SvXMLEmbeddedTextEntryArr & rEmbeddedEntries,sal_Int32 nMinDecimals)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 sal_Int32 nMinDecimals )
584 {
585 FinishTextElement_Impl();
586
587 // decimals
588 if ( nDecimals >= 0 ) // negative = automatic
589 {
590 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
591 OUString::valueOf( nDecimals ) );
592 }
593
594 // minimum decimals (ODF 1.3), if some of the decimals are optional
595 if ( nMinDecimals > 0 && nMinDecimals < nDecimals )
596 {
597 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DECIMAL_PLACES,
598 OUString::valueOf( nMinDecimals ) );
599 }
600
601 // integer digits
602 if ( nInteger >= 0 ) // negative = automatic
603 {
604 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
605 OUString::valueOf( nInteger ) );
606 }
607
608 // decimal replacement (dashes) or variable decimals (#)
609 if ( rDashStr.getLength() || bVarDecimals )
610 {
611 // variable decimals means an empty replacement string
612 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,
613 rDashStr );
614 }
615
616 // (automatic) grouping separator
617 if ( bGrouping )
618 {
619 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
620 }
621
622 // display-factor if there are trailing thousands separators
623 if ( nTrailingThousands )
624 {
625 // each separator character removes three digits
626 double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
627
628 OUStringBuffer aFactStr;
629 SvXMLUnitConverter::convertDouble( aFactStr, fFactor );
630 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
631 }
632
633 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER,
634 sal_True, sal_True );
635
636 // number:embedded-text as child elements
637
638 sal_uInt16 nEntryCount = rEmbeddedEntries.Count();
639 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
640 {
641 SvXMLEmbeddedTextEntry* pObj = rEmbeddedEntries[nEntry];
642
643 // position attribute
644 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION,
645 OUString::valueOf( pObj->nFormatPos ) );
646 SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT,
647 sal_True, sal_False );
648
649 // text as element content
650 rtl::OUString aContent( pObj->aText );
651 while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1]->nFormatPos == pObj->nFormatPos )
652 {
653 // The array can contain several elements for the same position in the number
654 // (for example, literal text and space from underscores). They must be merged
655 // into a single embedded-text element.
656 aContent += rEmbeddedEntries[nEntry+1]->aText;
657 ++nEntry;
658 }
659 rExport.Characters( aContent );
660 }
661 }
662
WriteScientificElement_Impl(sal_Int32 nDecimals,sal_Int32 nInteger,sal_Bool bGrouping,sal_Int32 nExp,sal_Int32 nMinDecimals)663 void SvXMLNumFmtExport::WriteScientificElement_Impl(
664 sal_Int32 nDecimals, sal_Int32 nInteger,
665 sal_Bool bGrouping, sal_Int32 nExp, sal_Int32 nMinDecimals )
666 {
667 FinishTextElement_Impl();
668
669 // decimals
670 if ( nDecimals >= 0 ) // negative = automatic
671 {
672 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
673 OUString::valueOf( nDecimals ) );
674 }
675
676 // minimum decimals (ODF 1.3); without it all decimals are mandatory
677 if ( nMinDecimals >= 0 && nMinDecimals < nDecimals )
678 {
679 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DECIMAL_PLACES,
680 OUString::valueOf( nMinDecimals ) );
681 }
682
683 // integer digits
684 if ( nInteger >= 0 ) // negative = automatic
685 {
686 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
687 OUString::valueOf( nInteger ) );
688 }
689
690 // (automatic) grouping separator
691 if ( bGrouping )
692 {
693 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
694 }
695
696 // exponent digits
697 if ( nExp >= 0 )
698 {
699 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,
700 OUString::valueOf( nExp ) );
701 }
702
703 SvXMLElementExport aElem( rExport,
704 XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,
705 sal_True, sal_False );
706 }
707
WriteFractionElement_Impl(sal_Int32 nInteger,sal_Bool bGrouping,sal_Int32 nNumerator,sal_Int32 nDenominator)708 void SvXMLNumFmtExport::WriteFractionElement_Impl(
709 sal_Int32 nInteger, sal_Bool bGrouping,
710 sal_Int32 nNumerator, sal_Int32 nDenominator )
711 {
712 FinishTextElement_Impl();
713
714 // integer digits
715 if ( nInteger >= 0 ) // negative = default (no integer part)
716 {
717 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
718 OUString::valueOf( nInteger ) );
719 }
720
721 // (automatic) grouping separator
722 if ( bGrouping )
723 {
724 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
725 }
726
727 // numerator digits
728 if ( nNumerator >= 0 )
729 {
730 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,
731 OUString::valueOf( nNumerator ) );
732 }
733
734 // denominator digits
735 if ( nDenominator >= 0 )
736 {
737 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,
738 OUString::valueOf( nDenominator ) );
739 }
740
741 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION,
742 sal_True, sal_False );
743 }
744
745 // mapping (condition)
746
WriteMapElement_Impl(sal_Int32 nOp,double fLimit,sal_Int32 nKey,sal_Int32 nPart)747 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
748 sal_Int32 nKey, sal_Int32 nPart )
749 {
750 FinishTextElement_Impl();
751
752 if ( nOp != NUMBERFORMAT_OP_NO )
753 {
754 // style namespace
755
756 OUStringBuffer aCondStr( 20L );
757 aCondStr.appendAscii( "value()" ); //! define constant
758 switch ( nOp )
759 {
760 case NUMBERFORMAT_OP_EQ: aCondStr.append( (sal_Unicode) '=' ); break;
761 case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "<>" ); break;
762 case NUMBERFORMAT_OP_LT: aCondStr.append( (sal_Unicode) '<' ); break;
763 case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" ); break;
764 case NUMBERFORMAT_OP_GT: aCondStr.append( (sal_Unicode) '>' ); break;
765 case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" ); break;
766 default:
767 DBG_ERROR("unknown operator");
768 }
769 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
770 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
771 '.', true );
772
773 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION,
774 aCondStr.makeStringAndClear() );
775
776 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME,
777 rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, sal_False,
778 sPrefix ) ) );
779
780 SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP,
781 sal_True, sal_False );
782 }
783 }
784
785 //-------------------------------------------------------------------------
786 // for old (automatic) currency formats: parse currency symbol from text
787
lcl_FindSymbol(const String & sUpperStr,const String & sCurString)788 xub_StrLen lcl_FindSymbol( const String& sUpperStr, const String& sCurString )
789 {
790 // search for currency symbol
791 // Quoting as in ImpSvNumberformatScan::Symbol_Division
792
793 xub_StrLen nCPos = 0;
794 while (nCPos != STRING_NOTFOUND)
795 {
796 nCPos = sUpperStr.Search( sCurString, nCPos );
797 if (nCPos != STRING_NOTFOUND)
798 {
799 // in Quotes?
800 xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
801 if ( nQ == STRING_NOTFOUND )
802 {
803 // dm can be escaped as "dm or \d
804 sal_Unicode c;
805 if ( nCPos == 0 ||
806 ((c = sUpperStr.GetChar(xub_StrLen(nCPos-1))) != '"'
807 && c != '\\') )
808 {
809 return nCPos; // found
810 }
811 else
812 nCPos++; // continue
813 }
814 else
815 nCPos = nQ + 1; // continue after quote end
816 }
817 }
818 return STRING_NOTFOUND; // not found
819 }
820
WriteTextWithCurrency_Impl(const OUString & rString,const::com::sun::star::lang::Locale & rLocale)821 sal_Bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
822 const ::com::sun::star::lang::Locale& rLocale )
823 {
824 // returns sal_True if currency element was written
825
826 sal_Bool bRet = sal_False;
827
828 // pLocaleData->setLocale( rLocale );
829 // String sCurString = pLocaleData->getCurrSymbol();
830
831 LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale );
832 pFormatter->ChangeIntl( nLang );
833 String sCurString, sDummy;
834 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
835
836 pCharClass->setLocale( rLocale );
837 String sUpperStr = pCharClass->upper(rString);
838 xub_StrLen nPos = lcl_FindSymbol( sUpperStr, sCurString );
839 if ( nPos != STRING_NOTFOUND )
840 {
841 sal_Int32 nLength = rString.getLength();
842 sal_Int32 nCurLen = sCurString.Len();
843 sal_Int32 nCont = nPos + nCurLen;
844
845 // text before currency symbol
846 if ( nPos > 0 )
847 AddToTextElement_Impl( rString.copy( 0, nPos ) );
848
849 // currency symbol (empty string -> default)
850 OUString sEmpty;
851 WriteCurrencyElement_Impl( sEmpty, sEmpty );
852 bRet = sal_True;
853
854 // text after currency symbol
855 if ( nCont < nLength )
856 AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
857 }
858 else
859 AddToTextElement_Impl( rString ); // simple text
860
861 return bRet; // sal_True: currency element written
862 }
863
864 //-------------------------------------------------------------------------
865
lcl_GetDefaultCalendar(SvNumberFormatter * pFormatter,LanguageType nLang)866 OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang )
867 {
868 // get name of first non-gregorian calendar for the language
869
870 OUString aCalendar;
871 CalendarWrapper* pCalendar = pFormatter->GetCalendar();
872 if (pCalendar)
873 {
874 lang::Locale aLocale( MsLangId::convertLanguageToLocale( nLang ) );
875
876 uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
877 sal_Int32 nCnt = aCals.getLength();
878 sal_Bool bFound = sal_False;
879 for ( sal_Int32 j=0; j < nCnt && !bFound; j++ )
880 {
881 if ( !aCals[j].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gregorian") ) )
882 {
883 aCalendar = aCals[j];
884 bFound = sal_True;
885 }
886 }
887 }
888 return aCalendar;
889 }
890
891 //-------------------------------------------------------------------------
892
lcl_IsInEmbedded(const SvXMLEmbeddedTextEntryArr & rEmbeddedEntries,sal_uInt16 nPos)893 sal_Bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
894 {
895 sal_uInt16 nCount = rEmbeddedEntries.Count();
896 for (sal_uInt16 i=0; i<nCount; i++)
897 if ( rEmbeddedEntries[i]->nSourcePos == nPos )
898 return sal_True;
899
900 return sal_False; // not found
901 }
902
lcl_IsDefaultDateFormat(const SvNumberformat & rFormat,sal_Bool bSystemDate,NfIndexTableOffset eBuiltIn)903 sal_Bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, sal_Bool bSystemDate, NfIndexTableOffset eBuiltIn )
904 {
905 // make an extra loop to collect date elements, to check if it is a default format
906 // before adding the automatic-order attribute
907
908 SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE;
909 SvXMLDateElementAttributes eDateDay = XML_DEA_NONE;
910 SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE;
911 SvXMLDateElementAttributes eDateYear = XML_DEA_NONE;
912 SvXMLDateElementAttributes eDateHours = XML_DEA_NONE;
913 SvXMLDateElementAttributes eDateMins = XML_DEA_NONE;
914 SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE;
915 sal_Bool bDateNoDefault = sal_False;
916
917 sal_uInt16 nPos = 0;
918 sal_Bool bEnd = sal_False;
919 short nLastType = 0;
920 while (!bEnd)
921 {
922 short nElemType = rFormat.GetNumForType( 0, nPos, sal_False );
923 switch ( nElemType )
924 {
925 case 0:
926 if ( nLastType == NF_SYMBOLTYPE_STRING )
927 bDateNoDefault = sal_True; // text at the end -> no default date format
928 bEnd = sal_True; // end of format reached
929 break;
930 case NF_SYMBOLTYPE_STRING:
931 case NF_SYMBOLTYPE_DATESEP:
932 case NF_SYMBOLTYPE_TIMESEP:
933 case NF_SYMBOLTYPE_TIME100SECSEP:
934 // text is ignored, except at the end
935 break;
936 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
937 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
938 case NF_KEY_NNN:
939 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
940 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
941 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
942 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
943 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
944 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
945 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
946 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
947 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
948 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
949 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
950 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
951 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
952 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
953 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
954 case NF_KEY_AP:
955 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
956 default:
957 bDateNoDefault = sal_True; // any other element -> no default format
958 }
959 nLastType = nElemType;
960 ++nPos;
961 }
962
963 if ( bDateNoDefault )
964 return sal_False; // additional elements
965 else
966 {
967 NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
968 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate );
969
970 return ( eFound == eBuiltIn );
971 }
972 }
973
974 //
975 // export one part (condition)
976 //
977
ExportPart_Impl(const SvNumberformat & rFormat,sal_uInt32 nKey,sal_uInt16 nPart,sal_Bool bDefPart)978 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
979 sal_uInt16 nPart, sal_Bool bDefPart )
980 {
981 //! for the default part, pass the conditions from the other parts!
982
983 //
984 // element name
985 //
986
987 NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
988
989 short nFmtType = 0;
990 sal_Bool bThousand = sal_False;
991 sal_uInt16 nPrecision = 0;
992 sal_uInt16 nLeading = 0;
993 rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
994 nFmtType &= ~NUMBERFORMAT_DEFINED;
995
996 // special treatment of builtin formats that aren't detected by normal parsing
997 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
998 if ( eBuiltIn == NF_NUMBER_STANDARD )
999 nFmtType = NUMBERFORMAT_NUMBER;
1000 else if ( eBuiltIn == NF_BOOLEAN )
1001 nFmtType = NUMBERFORMAT_LOGICAL;
1002 else if ( eBuiltIn == NF_TEXT )
1003 nFmtType = NUMBERFORMAT_TEXT;
1004
1005 // #101606# An empty subformat is a valid number-style resulting in an
1006 // empty display string for the condition of the subformat.
1007 if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart,
1008 0, sal_False ) == 0 )
1009 nFmtType = 0;
1010
1011 XMLTokenEnum eType = XML_TOKEN_INVALID;
1012 switch ( nFmtType )
1013 {
1014 // type is 0 if a format contains no recognized elements
1015 // (like text only) - this is handled as a number-style.
1016 case 0:
1017 case NUMBERFORMAT_NUMBER:
1018 case NUMBERFORMAT_SCIENTIFIC:
1019 case NUMBERFORMAT_FRACTION:
1020 eType = XML_NUMBER_STYLE;
1021 break;
1022 case NUMBERFORMAT_PERCENT:
1023 eType = XML_PERCENTAGE_STYLE;
1024 break;
1025 case NUMBERFORMAT_CURRENCY:
1026 eType = XML_CURRENCY_STYLE;
1027 break;
1028 case NUMBERFORMAT_DATE:
1029 case NUMBERFORMAT_DATETIME:
1030 eType = XML_DATE_STYLE;
1031 break;
1032 case NUMBERFORMAT_TIME:
1033 eType = XML_TIME_STYLE;
1034 break;
1035 case NUMBERFORMAT_TEXT:
1036 eType = XML_TEXT_STYLE;
1037 break;
1038 case NUMBERFORMAT_LOGICAL:
1039 eType = XML_BOOLEAN_STYLE;
1040 break;
1041 }
1042 DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" );
1043
1044 OUString sAttrValue;
1045 sal_Bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 );
1046
1047 //
1048 // common attributes for format
1049 //
1050
1051 // format name (generated from key) - style namespace
1052 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
1053 lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
1054
1055 // "volatile" attribute for styles used only in maps
1056 if ( !bDefPart )
1057 rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE );
1058
1059 // language / country
1060 LanguageType nLang = rFormat.GetLanguage();
1061 AddLanguageAttr_Impl( nLang ); // adds to pAttrList
1062
1063 // title (comment)
1064 // titles for builtin formats are not written
1065 sAttrValue = rFormat.GetComment();
1066 if ( sAttrValue.getLength() && bUserDef && bDefPart )
1067 {
1068 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue );
1069 }
1070
1071 // automatic ordering for currency and date formats
1072 // only used for some built-in formats
1073 sal_Bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1074 eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1075 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1076 eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
1077 eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
1078 eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
1079 eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1080 eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1081 eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1082 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1083
1084 // format source (for date and time formats)
1085 // only used for some built-in formats
1086 sal_Bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1087 eBuiltIn == NF_DATE_SYSTEM_LONG ||
1088 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1089 sal_Bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1090
1091 // check if the format definition matches the key
1092 if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) &&
1093 !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1094 {
1095 bAutoOrder = bSystemDate = bLongSysDate = sal_False; // don't write automatic-order attribute then
1096 }
1097
1098 if ( bAutoOrder &&
1099 ( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1100 {
1101 // #85109# format type must be checked to avoid dtd errors if
1102 // locale data contains other format types at the built-in positions
1103
1104 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,
1105 XML_TRUE );
1106 }
1107
1108 if ( bSystemDate && bAutoOrder &&
1109 ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
1110 {
1111 // #85109# format type must be checked to avoid dtd errors if
1112 // locale data contains other format types at the built-in positions
1113
1114 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,
1115 XML_LANGUAGE );
1116 }
1117
1118 // overflow for time formats as in [hh]:mm
1119 // controlled by bThousand from number format info
1120 // default for truncate-on-overflow is true
1121 if ( nFmtType == NUMBERFORMAT_TIME && bThousand )
1122 {
1123 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,
1124 XML_FALSE );
1125 }
1126
1127 //
1128 // Native number transliteration
1129 //
1130 ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr;
1131 rFormat.GetNatNumXml( aAttr, nPart );
1132 if ( aAttr.Format.getLength() )
1133 {
1134 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,
1135 aAttr.Format );
1136 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,
1137 aAttr.Locale.Language );
1138 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,
1139 aAttr.Locale.Country );
1140 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,
1141 aAttr.Style );
1142 }
1143
1144 //
1145 // The element
1146 //
1147 SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
1148 sal_True, sal_True );
1149
1150 //
1151 // color (properties element)
1152 //
1153
1154 const Color* pCol = rFormat.GetColor( nPart );
1155 if (pCol)
1156 WriteColorElement_Impl(*pCol);
1157
1158
1159 // detect if there is "real" content, excluding color and maps
1160 //! move to implementation of Write... methods?
1161 sal_Bool bAnyContent = sal_False;
1162
1163 //
1164 // format elements
1165 //
1166
1167 SvXMLEmbeddedTextEntryArr aEmbeddedEntries(0);
1168 if ( eBuiltIn == NF_NUMBER_STANDARD )
1169 {
1170 // default number format contains just one number element
1171 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1172 bAnyContent = sal_True;
1173 }
1174 else if ( eBuiltIn == NF_BOOLEAN )
1175 {
1176 // boolean format contains just one boolean element
1177 WriteBooleanElement_Impl();
1178 bAnyContent = sal_True;
1179 }
1180 else
1181 {
1182 // first loop to collect attributes
1183
1184 sal_Bool bDecDashes = sal_False;
1185 sal_Bool bVarDecimals = sal_False;
1186 sal_Bool bExpFound = sal_False;
1187 sal_Bool bCurrFound = sal_False;
1188 sal_Bool bInInteger = sal_True;
1189 sal_Int32 nExpDigits = 0;
1190 sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
1191 sal_Int32 nDecZeros = 0; // mandatory decimals: '0's before the first '#'
1192 sal_Bool bDecHash = sal_False; // a '#' was found in the decimals
1193 sal_Bool bDecIrregular = sal_False; // decimals other than 0... followed by #...
1194 sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
1195 OUString sCurrExt;
1196 OUString aCalendar;
1197 sal_uInt16 nPos = 0;
1198 sal_Bool bEnd = sal_False;
1199 while (!bEnd)
1200 {
1201 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1202 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1203
1204 switch ( nElemType )
1205 {
1206 case 0:
1207 bEnd = sal_True; // end of format reached
1208 break;
1209 case NF_SYMBOLTYPE_DIGIT:
1210 if ( bExpFound && pElemStr )
1211 nExpDigits += pElemStr->Len();
1212 else if ( !bDecDashes && pElemStr && pElemStr->GetChar(0) == '-' )
1213 bDecDashes = sal_True;
1214 else if ( !bVarDecimals && !bInInteger && pElemStr && pElemStr->GetChar(0) == '#' )
1215 {
1216 // If the decimal digits string starts with a '#', variable
1217 // decimals is assumed (for 0.###, but not 0.0##).
1218 bVarDecimals = sal_True;
1219 }
1220 if ( !bExpFound && !bInInteger && !bDecDashes && pElemStr && pElemStr->GetChar(0) != '-' )
1221 {
1222 for ( xub_StrLen nDec = 0; nDec < pElemStr->Len(); nDec++ )
1223 {
1224 sal_Unicode cDec = pElemStr->GetChar( nDec );
1225 if ( cDec == '0' && !bDecHash )
1226 nDecZeros++;
1227 else if ( cDec == '#' )
1228 bDecHash = sal_True;
1229 else
1230 bDecIrregular = sal_True;
1231 }
1232 }
1233 if ( bInInteger && pElemStr )
1234 nIntegerSymbols += pElemStr->Len();
1235 nTrailingThousands = 0;
1236 break;
1237 case NF_SYMBOLTYPE_DECSEP:
1238 bInInteger = sal_False;
1239 break;
1240 case NF_SYMBOLTYPE_THSEP:
1241 if (pElemStr)
1242 nTrailingThousands += pElemStr->Len(); // is reset to 0 if digits follow
1243 break;
1244 case NF_SYMBOLTYPE_EXP:
1245 bExpFound = sal_True; // following digits are exponent digits
1246 bInInteger = sal_False;
1247 break;
1248 case NF_SYMBOLTYPE_CURRENCY:
1249 bCurrFound = sal_True;
1250 break;
1251 case NF_SYMBOLTYPE_CURREXT:
1252 if (pElemStr)
1253 sCurrExt = *pElemStr;
1254 break;
1255
1256 // E, EE, R, RR: select non-gregorian calendar
1257 // AAA, AAAA: calendar is switched at the position of the element
1258 case NF_KEY_EC:
1259 case NF_KEY_EEC:
1260 case NF_KEY_R:
1261 case NF_KEY_RR:
1262 if (!aCalendar.getLength())
1263 aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1264 break;
1265 }
1266 ++nPos;
1267 }
1268
1269 // collect strings for embedded-text (must be known before number element is written)
1270
1271 sal_Bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER ||
1272 nFmtType == NUMBERFORMAT_CURRENCY ||
1273 nFmtType == NUMBERFORMAT_PERCENT );
1274 if ( bAllowEmbedded )
1275 {
1276 sal_Int32 nDigitsPassed = 0;
1277 nPos = 0;
1278 bEnd = sal_False;
1279 while (!bEnd)
1280 {
1281 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1282 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1283
1284 switch ( nElemType )
1285 {
1286 case 0:
1287 bEnd = sal_True; // end of format reached
1288 break;
1289 case NF_SYMBOLTYPE_DIGIT:
1290 if ( pElemStr )
1291 nDigitsPassed += pElemStr->Len();
1292 break;
1293 case NF_SYMBOLTYPE_STRING:
1294 case NF_SYMBOLTYPE_BLANK:
1295 case NF_SYMBOLTYPE_PERCENT:
1296 if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
1297 {
1298 // text (literal or underscore) within the integer part of a number:number element
1299
1300 String aEmbeddedStr;
1301 if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1302 aEmbeddedStr = *pElemStr;
1303 else
1304 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, pElemStr->GetChar(1) );
1305
1306 sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1307
1308 SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr );
1309 aEmbeddedEntries.Insert( pObj, aEmbeddedEntries.Count() );
1310 }
1311 break;
1312 }
1313 ++nPos;
1314 }
1315 }
1316
1317 // final loop to write elements
1318
1319 sal_Bool bNumWritten = sal_False;
1320 sal_Bool bCurrencyWritten = sal_False;
1321 short nPrevType = 0;
1322 nPos = 0;
1323 bEnd = sal_False;
1324 while (!bEnd)
1325 {
1326 short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
1327 const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
1328
1329 switch ( nElemType )
1330 {
1331 case 0:
1332 bEnd = sal_True; // end of format reached
1333 break;
1334 case NF_SYMBOLTYPE_STRING:
1335 case NF_SYMBOLTYPE_DATESEP:
1336 case NF_SYMBOLTYPE_TIMESEP:
1337 case NF_SYMBOLTYPE_TIME100SECSEP:
1338 case NF_SYMBOLTYPE_PERCENT:
1339 if (pElemStr)
1340 {
1341 if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1342 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1343 nPrecision > 0 )
1344 {
1345 // decimal separator after seconds is implied by
1346 // "decimal-places" attribute and must not be written
1347 // as text element
1348 //! difference between '.' and ',' is lost here
1349 }
1350 else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1351 {
1352 // text is written as embedded-text child of the number,
1353 // don't create a text element
1354 }
1355 else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten )
1356 {
1357 // automatic currency symbol is implemented as part of
1358 // normal text -> search for the symbol
1359 bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1360 MsLangId::convertLanguageToLocale( nLang ) );
1361 bAnyContent = sal_True;
1362 }
1363 else
1364 AddToTextElement_Impl( *pElemStr );
1365 }
1366 break;
1367 case NF_SYMBOLTYPE_BLANK:
1368 if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1369 {
1370 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1371 // (#i20396# the spaces may also be in embedded-text elements)
1372
1373 String aBlanks;
1374 SvNumberformat::InsertBlanks( aBlanks, 0, pElemStr->GetChar(1) );
1375 AddToTextElement_Impl( aBlanks );
1376 }
1377 break;
1378 case NF_KEY_GENERAL :
1379 WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
1380 break;
1381 case NF_KEY_CCC:
1382 if (pElemStr)
1383 {
1384 if ( bCurrencyWritten )
1385 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1386 else
1387 {
1388 //! must be different from short automatic format
1389 //! but should still be empty (meaning automatic)
1390 // pElemStr is "CCC"
1391
1392 WriteCurrencyElement_Impl( *pElemStr, OUString() );
1393 bAnyContent = sal_True;
1394 bCurrencyWritten = sal_True;
1395 }
1396 }
1397 break;
1398 case NF_SYMBOLTYPE_CURRENCY:
1399 if (pElemStr)
1400 {
1401 if ( bCurrencyWritten )
1402 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1403 else
1404 {
1405 WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1406 bAnyContent = sal_True;
1407 bCurrencyWritten = sal_True;
1408 }
1409 }
1410 break;
1411 case NF_SYMBOLTYPE_DIGIT:
1412 if (!bNumWritten) // write number part
1413 {
1414 // only ODF 1.3 can express mandatory decimals followed by optional ones
1415 sal_Int32 nMinDecimals = -1;
1416 if ( rExport.getDefaultVersion() >= SvtSaveOptions::ODFVER_013 &&
1417 bDecHash && !bDecIrregular && !bDecDashes )
1418 nMinDecimals = nDecZeros;
1419
1420 switch ( nFmtType )
1421 {
1422 // for type 0 (not recognized as a special type),
1423 // write a "normal" number
1424 case 0:
1425 case NUMBERFORMAT_NUMBER:
1426 case NUMBERFORMAT_CURRENCY:
1427 case NUMBERFORMAT_PERCENT:
1428 {
1429 // decimals
1430 // only some built-in formats have automatic decimals
1431 sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
1432 if ( eBuiltIn == NF_NUMBER_STANDARD ||
1433 eBuiltIn == NF_CURRENCY_1000DEC2 ||
1434 eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1435 eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1436 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1437 nDecimals = -1;
1438
1439 // integer digits
1440 // only one built-in format has automatic integer digits
1441 sal_Int32 nInteger = nLeading;
1442 if ( eBuiltIn == NF_NUMBER_SYSTEM )
1443 nInteger = -1;
1444
1445 // string for decimal replacement
1446 // has to be taken from nPrecision
1447 // (positive number even for automatic decimals)
1448 String sDashStr;
1449 if ( bDecDashes && nPrecision > 0 )
1450 sDashStr.Fill( nPrecision, '-' );
1451
1452 WriteNumberElement_Impl( nDecimals, nInteger, sDashStr, bVarDecimals,
1453 bThousand, nTrailingThousands, aEmbeddedEntries, nMinDecimals );
1454 bAnyContent = sal_True;
1455 }
1456 break;
1457 case NUMBERFORMAT_SCIENTIFIC:
1458 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1459 // as integer digits: use nIntegerSymbols instead of nLeading
1460 // (use of '#' to select multiples in exponent might be added later)
1461 WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits, nMinDecimals );
1462 bAnyContent = sal_True;
1463 break;
1464 case NUMBERFORMAT_FRACTION:
1465 {
1466 sal_Int32 nInteger = nLeading;
1467 if ( pElemStr && pElemStr->GetChar(0) == '?' )
1468 {
1469 // If the first digit character is a question mark,
1470 // the fraction doesn't have an integer part, and no
1471 // min-integer-digits attribute must be written.
1472 nInteger = -1;
1473 }
1474 WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision );
1475 bAnyContent = sal_True;
1476 }
1477 break;
1478 }
1479
1480 bNumWritten = sal_True;
1481 }
1482 break;
1483 case NF_SYMBOLTYPE_DECSEP:
1484 if ( pElemStr && nPrecision == 0 )
1485 {
1486 // A decimal separator after the number, without following decimal digits,
1487 // isn't modelled as part of the number element, so it's written as text
1488 // (the distinction between a quoted and non-quoted, locale-dependent
1489 // character is lost here).
1490
1491 AddToTextElement_Impl( *pElemStr );
1492 }
1493 break;
1494 case NF_SYMBOLTYPE_DEL:
1495 if ( pElemStr && *pElemStr == XubString('@') )
1496 {
1497 WriteTextContentElement_Impl();
1498 bAnyContent = sal_True;
1499 }
1500 break;
1501
1502 case NF_SYMBOLTYPE_CALENDAR:
1503 if ( pElemStr )
1504 aCalendar = *pElemStr;
1505 break;
1506
1507 // date elements:
1508
1509 case NF_KEY_D:
1510 case NF_KEY_DD:
1511 {
1512 sal_Bool bLong = ( nElemType == NF_KEY_DD );
1513 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1514 bAnyContent = sal_True;
1515 }
1516 break;
1517 case NF_KEY_DDD:
1518 case NF_KEY_DDDD:
1519 case NF_KEY_NN:
1520 case NF_KEY_NNN:
1521 case NF_KEY_NNNN:
1522 case NF_KEY_AAA:
1523 case NF_KEY_AAAA:
1524 {
1525 OUString aCalAttr = aCalendar;
1526 if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1527 {
1528 // calendar attribute for AAA and AAAA is switched only for this element
1529 if (!aCalAttr.getLength())
1530 aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
1531 }
1532
1533 sal_Bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1534 nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1535 WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1536 bAnyContent = sal_True;
1537 if ( nElemType == NF_KEY_NNNN )
1538 {
1539 // write additional text element for separator
1540 pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
1541 AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
1542 }
1543 }
1544 break;
1545 case NF_KEY_M:
1546 case NF_KEY_MM:
1547 case NF_KEY_MMM:
1548 case NF_KEY_MMMM:
1549 case NF_KEY_MMMMM: //! first letter of month name, no attribute available
1550 {
1551 sal_Bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
1552 sal_Bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1553 nElemType == NF_KEY_MMMMM );
1554 WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1555 bAnyContent = sal_True;
1556 }
1557 break;
1558 case NF_KEY_YY:
1559 case NF_KEY_YYYY:
1560 case NF_KEY_EC:
1561 case NF_KEY_EEC:
1562 case NF_KEY_R: //! R acts as EE, no attribute available
1563 {
1564 //! distinguish EE and R
1565 // calendar attribute for E and EE and R is set in first loop
1566 sal_Bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1567 nElemType == NF_KEY_R );
1568 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1569 bAnyContent = sal_True;
1570 }
1571 break;
1572 case NF_KEY_G:
1573 case NF_KEY_GG:
1574 case NF_KEY_GGG:
1575 case NF_KEY_RR: //! RR acts as GGGEE, no attribute available
1576 {
1577 //! distinguish GG and GGG and RR
1578 sal_Bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1579 WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1580 bAnyContent = sal_True;
1581 if ( nElemType == NF_KEY_RR )
1582 {
1583 // calendar attribute for RR is set in first loop
1584 WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : sal_True ) );
1585 }
1586 }
1587 break;
1588 case NF_KEY_Q:
1589 case NF_KEY_QQ:
1590 {
1591 sal_Bool bLong = ( nElemType == NF_KEY_QQ );
1592 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1593 bAnyContent = sal_True;
1594 }
1595 break;
1596 case NF_KEY_WW:
1597 WriteWeekElement_Impl( aCalendar );
1598 bAnyContent = sal_True;
1599 break;
1600
1601 // time elements (bSystemDate is not used):
1602
1603 case NF_KEY_H:
1604 case NF_KEY_HH:
1605 WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1606 bAnyContent = sal_True;
1607 break;
1608 case NF_KEY_MI:
1609 case NF_KEY_MMI:
1610 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1611 bAnyContent = sal_True;
1612 break;
1613 case NF_KEY_S:
1614 case NF_KEY_SS:
1615 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1616 bAnyContent = sal_True;
1617 break;
1618 case NF_KEY_AMPM:
1619 case NF_KEY_AP:
1620 WriteAMPMElement_Impl(); // short/long?
1621 bAnyContent = sal_True;
1622 break;
1623 }
1624 nPrevType = nElemType;
1625 ++nPos;
1626 }
1627 }
1628
1629 if ( sTextContent.getLength() )
1630 bAnyContent = sal_True; // element written in FinishTextElement_Impl
1631
1632 FinishTextElement_Impl(); // final text element - before maps
1633
1634 if ( !bAnyContent )
1635 {
1636 // for an empty format, write an empty text element
1637 SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
1638 sal_True, sal_False );
1639 }
1640
1641 //
1642 // mapping (conditions) must be last elements
1643 //
1644
1645 if (bDefPart)
1646 {
1647 SvNumberformatLimitOps eOp1, eOp2;
1648 double fLimit1, fLimit2;
1649 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1650
1651 WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1652 WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1653
1654 if ( rFormat.HasTextFormat() )
1655 {
1656 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1657 // by reversing the 2nd condition
1658
1659 SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO;
1660 double fLimit3 = fLimit2;
1661 switch ( eOp2 )
1662 {
1663 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1664 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1665 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1666 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1667 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1668 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1669 default:
1670 break;
1671 }
1672
1673 if ( fLimit1 == fLimit2 &&
1674 ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1675 ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1676 {
1677 // For <x and >x, add =x as last condition
1678 // (just for readability, <=x would be valid, too)
1679
1680 eOp3 = NUMBERFORMAT_OP_EQ;
1681 }
1682
1683 WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 );
1684 }
1685 }
1686 }
1687
1688 //-------------------------------------------------------------------------
1689
1690 //
1691 // export one format
1692 //
1693
ExportFormat_Impl(const SvNumberformat & rFormat,sal_uInt32 nKey)1694 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
1695 {
1696 sal_uInt16 nUsedParts = 0;
1697 sal_uInt16 nPart;
1698 for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++)
1699 if (rFormat.GetNumForType( nPart, 0, sal_False ) != 0)
1700 nUsedParts = nPart+1;
1701
1702 SvNumberformatLimitOps eOp1, eOp2;
1703 double fLimit1, fLimit2;
1704 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1705
1706 // if conditions are set, even empty formats must be written
1707
1708 if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 )
1709 nUsedParts = 2;
1710 if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
1711 nUsedParts = 3;
1712 if ( rFormat.HasTextFormat() && nUsedParts < 4 )
1713 nUsedParts = 4;
1714
1715 for (nPart=0; nPart<nUsedParts; nPart++)
1716 {
1717 sal_Bool bDefault = ( nPart+1 == nUsedParts ); // last = default
1718 ExportPart_Impl( rFormat, nKey, nPart, bDefault );
1719 }
1720 }
1721
1722 //-------------------------------------------------------------------------
1723
1724 //
1725 // export method called by application
1726 //
1727
Export(sal_Bool bIsAutoStyle)1728 void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle )
1729 {
1730 if ( !pFormatter )
1731 return; // no formatter -> no entries
1732
1733 sal_uInt32 nKey;
1734 const SvNumberformat* pFormat = NULL;
1735 sal_Bool bNext(pUsedList->GetFirstUsed(nKey));
1736 while(bNext)
1737 {
1738 pFormat = pFormatter->GetEntry(nKey);
1739 if(pFormat)
1740 ExportFormat_Impl( *pFormat, nKey );
1741 bNext = pUsedList->GetNextUsed(nKey);
1742 }
1743 if (!bIsAutoStyle)
1744 {
1745 SvUShorts aLanguages;
1746 pFormatter->GetUsedLanguages( aLanguages );
1747 sal_uInt16 nLangCount = aLanguages.Count();
1748 for (sal_uInt16 nLangPos=0; nLangPos<nLangCount; nLangPos++)
1749 {
1750 LanguageType nLang = aLanguages[nLangPos];
1751
1752 sal_uInt32 nDefaultIndex = 0;
1753 SvNumberFormatTable& rTable = pFormatter->GetEntryTable(
1754 NUMBERFORMAT_DEFINED, nDefaultIndex, nLang );
1755 pFormat = rTable.First();
1756 while (pFormat)
1757 {
1758 nKey = rTable.GetCurKey();
1759 if (!pUsedList->IsUsed(nKey))
1760 {
1761 DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found");
1762 // user-defined and used formats are exported
1763 ExportFormat_Impl( *pFormat, nKey );
1764 // if it is a user-defined Format it will be added else nothing will happen
1765 pUsedList->SetUsed(nKey);
1766 }
1767
1768 pFormat = rTable.Next();
1769 }
1770 }
1771 }
1772 pUsedList->Export();
1773 }
1774
GetStyleName(sal_uInt32 nKey)1775 OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1776 {
1777 if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
1778 return lcl_CreateStyleName( nKey, 0, sal_True, sPrefix );
1779 else
1780 {
1781 DBG_ERROR("There is no written Data-Style");
1782 return rtl::OUString();
1783 }
1784 }
1785
SetUsed(sal_uInt32 nKey)1786 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1787 {
1788 DBG_ASSERT( pFormatter != NULL, "missing formatter" );
1789 if( !pFormatter )
1790 return;
1791
1792 if (pFormatter->GetEntry(nKey))
1793 pUsedList->SetUsed( nKey );
1794 else {
1795 DBG_ERROR("no existing Numberformat found with this key");
1796 }
1797 }
1798
GetWasUsed(uno::Sequence<sal_Int32> & rWasUsed)1799 void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
1800 {
1801 if (pUsedList)
1802 pUsedList->GetWasUsed(rWasUsed);
1803 }
1804
SetWasUsed(const uno::Sequence<sal_Int32> & rWasUsed)1805 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1806 {
1807 if (pUsedList)
1808 pUsedList->SetWasUsed(rWasUsed);
1809 }
1810
1811
1812
lcl_GetFormat(SvNumberFormatter * pFormatter,sal_uInt32 nKey)1813 const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
1814 sal_uInt32 nKey )
1815 {
1816 return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL;
1817 }
1818
ForceSystemLanguage(sal_uInt32 nKey)1819 sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
1820 {
1821 sal_uInt32 nRet = nKey;
1822
1823 const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
1824 if( pFormat != NULL )
1825 {
1826 DBG_ASSERT( pFormatter != NULL, "format without formatter?" );
1827
1828 xub_StrLen nErrorPos;
1829 short nType = pFormat->GetType();
1830
1831 sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
1832 nKey, LANGUAGE_SYSTEM );
1833
1834 if( nNewKey != nKey )
1835 {
1836 nRet = nNewKey;
1837 }
1838 else
1839 {
1840 String aFormatString( pFormat->GetFormatstring() );
1841 pFormatter->PutandConvertEntry(
1842 aFormatString,
1843 nErrorPos, nType, nNewKey,
1844 pFormat->GetLanguage(), LANGUAGE_SYSTEM );
1845
1846 // success? Then use new key.
1847 if( nErrorPos == 0 )
1848 nRet = nNewKey;
1849 }
1850 }
1851
1852 return nRet;
1853 }
1854