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