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