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