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