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