1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
25 #include <comphelper/string.hxx>
26 #include <sal/log.hxx>
27 #include <tools/debug.hxx>
28 #include <osl/diagnose.h>
29 #include <i18nlangtag/mslangid.hxx>
30 #include <rtl/math.hxx>
31 #include <unotools/charclass.hxx>
32 #include <unotools/calendarwrapper.hxx>
33 #include <unotools/nativenumberwrapper.hxx>
34 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
36 #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
37 #include <com/sun/star/i18n/AmPmValue.hpp>
39 #include <svl/zformat.hxx>
40 #include "zforscan.hxx"
42 #include "zforfind.hxx"
43 #include <svl/zforlist.hxx>
44 #include <unotools/digitgroupingiterator.hxx>
45 #include <svl/nfsymbol.hxx>
48 #include <boost/scoped_ptr.hpp>
54 char const GREGORIAN
[] = "gregorian";
56 const sal_uInt16 UPPER_PRECISION
= 300; // entirely arbitrary...
57 const double EXP_LOWER_BOUND
= 1.0E-4; // prefer scientific notation below this value.
58 const double EXP_ABS_UPPER_BOUND
= 1.0E15
; // use exponential notation above that absolute value.
59 // Back in time was E16 that lead
60 // to display rounding errors, see
61 // also sal/rtl/math.cxx
66 const double _D_MAX_U_LONG_
= (double) 0xffffffff; // 4294967295.0
67 const sal_uInt16 _MAX_FRACTION_PREC
= 3;
68 const double D_EPS
= 1.0E-2;
70 const double _D_MAX_D_BY_100
= 1.7E306
;
71 const double _D_MIN_M_BY_1000
= 2.3E-305;
73 static const sal_uInt8 cCharWidths
[ 128-32 ] = {
74 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
75 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
76 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
77 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
78 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
79 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
83 sal_Int32
SvNumberformat::InsertBlanks( OUStringBuffer
& r
, sal_Int32 nPos
, sal_Unicode c
)
87 int n
= 2; // Default for chars > 128 (HACK!)
90 n
= (int)cCharWidths
[ c
- 32 ];
94 r
.insert( nPos
++, ' ');
100 static long GetPrecExp( double fAbsVal
)
102 DBG_ASSERT( fAbsVal
> 0.0, "GetPrecExp: fAbsVal <= 0.0" );
103 if ( fAbsVal
< 1e-7 || fAbsVal
> 1e7
)
105 // Shear: whether it's faster or not, falls in between 1e6 and 1e7
106 return (long) floor( log10( fAbsVal
) ) + 1;
116 while( fAbsVal
>= 10 )
129 void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo
& rNumFor
, sal_uInt16 nAnz
)
131 for (sal_uInt16 i
= 0; i
< nAnz
; ++i
)
133 sStrArray
[i
] = rNumFor
.sStrArray
[i
];
134 nTypeArray
[i
] = rNumFor
.nTypeArray
[i
];
136 eScannedType
= rNumFor
.eScannedType
;
137 bThousand
= rNumFor
.bThousand
;
138 nThousand
= rNumFor
.nThousand
;
139 nCntPre
= rNumFor
.nCntPre
;
140 nCntPost
= rNumFor
.nCntPost
;
141 nCntExp
= rNumFor
.nCntExp
;
145 sal_uInt8
SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum
, LanguageType eLang
, bool bDate
)
147 sal_uInt8 nNatNum
= 0;
148 eLang
= MsLangId::getRealLanguage( eLang
); // resolve SYSTEM etc.
149 eLang
&= 0x03FF; // 10 bit primary language
152 if ( nDBNum
== 4 && eLang
== (LANGUAGE_KOREAN
& 0x03FF) )
156 else if ( nDBNum
<= 3 )
158 nNatNum
= nDBNum
; // known to be good for: zh,ja,ko / 1,2,3
168 case (LANGUAGE_CHINESE
& 0x03FF):
171 case (LANGUAGE_JAPANESE
& 0x03FF):
174 case (LANGUAGE_KOREAN
& 0x03FF):
182 case (LANGUAGE_CHINESE
& 0x03FF):
185 case (LANGUAGE_JAPANESE
& 0x03FF):
188 case (LANGUAGE_KOREAN
& 0x03FF):
196 case (LANGUAGE_CHINESE
& 0x03FF):
199 case (LANGUAGE_JAPANESE
& 0x03FF):
202 case (LANGUAGE_KOREAN
& 0x03FF):
210 case (LANGUAGE_JAPANESE
& 0x03FF):
213 case (LANGUAGE_KOREAN
& 0x03FF):
224 /* XXX NOTE: even though the MapNatNumToDBNum method is currently unused please
225 * don't remove it in case we'd have to use it for some obscure exports to
229 sal_uInt8
SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum
, LanguageType eLang
, bool bDate
)
231 sal_uInt8 nDBNum
= 0;
232 eLang
= MsLangId::getRealLanguage( eLang
); // resolve SYSTEM etc.
233 eLang
&= 0x03FF; // 10 bit primary language
236 if ( nNatNum
== 9 && eLang
== (LANGUAGE_KOREAN
& 0x03FF) )
240 else if ( nNatNum
<= 3 )
242 nDBNum
= nNatNum
; // known to be good for: zh,ja,ko / 1,2,3
252 case (LANGUAGE_JAPANESE
& 0x03FF):
255 case (LANGUAGE_KOREAN
& 0x03FF):
263 case (LANGUAGE_KOREAN
& 0x03FF):
271 case (LANGUAGE_KOREAN
& 0x03FF):
279 case (LANGUAGE_CHINESE
& 0x03FF):
282 case (LANGUAGE_JAPANESE
& 0x03FF):
290 case (LANGUAGE_CHINESE
& 0x03FF):
293 case (LANGUAGE_JAPANESE
& 0x03FF):
301 case (LANGUAGE_CHINESE
& 0x03FF):
309 case (LANGUAGE_JAPANESE
& 0x03FF):
319 case (LANGUAGE_KOREAN
& 0x03FF):
338 ImpSvNumFor::ImpSvNumFor()
341 aI
.nTypeArray
= NULL
;
343 aI
.eScannedType
= css::util::NumberFormat::UNDEFINED
;
344 aI
.bThousand
= false;
352 ImpSvNumFor::~ImpSvNumFor()
354 delete [] aI
.sStrArray
;
355 delete [] aI
.nTypeArray
;
358 void ImpSvNumFor::Enlarge(sal_uInt16 nAnz
)
360 if ( nAnzStrings
!= nAnz
)
362 delete [] aI
.nTypeArray
;
363 delete [] aI
.sStrArray
;
367 aI
.nTypeArray
= new short[nAnz
];
368 aI
.sStrArray
= new OUString
[nAnz
];
372 aI
.nTypeArray
= NULL
;
378 void ImpSvNumFor::Copy( const ImpSvNumFor
& rNumFor
, ImpSvNumberformatScan
* pSc
)
380 Enlarge( rNumFor
.nAnzStrings
);
381 aI
.Copy( rNumFor
.aI
, nAnzStrings
);
382 sColorName
= rNumFor
.sColorName
;
385 pColor
= pSc
->GetColor( sColorName
); // #121103# don't copy pointer between documents
389 pColor
= rNumFor
.pColor
;
391 aNatNum
= rNumFor
.aNatNum
;
394 bool ImpSvNumFor::HasNewCurrency() const
396 for ( sal_uInt16 j
=0; j
<nAnzStrings
; j
++ )
398 if ( aI
.nTypeArray
[j
] == NF_SYMBOLTYPE_CURRENCY
)
406 bool ImpSvNumFor::GetNewCurrencySymbol( OUString
& rSymbol
,
407 OUString
& rExtension
) const
409 for ( sal_uInt16 j
=0; j
<nAnzStrings
; j
++ )
411 if ( aI
.nTypeArray
[j
] == NF_SYMBOLTYPE_CURRENCY
)
413 rSymbol
= aI
.sStrArray
[j
];
414 if ( j
< nAnzStrings
-1 && aI
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_CURREXT
)
416 rExtension
= aI
.sStrArray
[j
+1];
425 //! No Erase at rSymbol, rExtension
433 enum BracketFormatSymbolType
435 BRACKET_SYMBOLTYPE_FORMAT
= -1, // subformat string
436 BRACKET_SYMBOLTYPE_COLOR
= -2, // color
437 BRACKET_SYMBOLTYPE_ERROR
= -3, // error
438 BRACKET_SYMBOLTYPE_DBNUM1
= -4, // DoubleByteNumber, represent numbers
439 BRACKET_SYMBOLTYPE_DBNUM2
= -5, // using CJK characters, Excel compatible
440 BRACKET_SYMBOLTYPE_DBNUM3
= -6,
441 BRACKET_SYMBOLTYPE_DBNUM4
= -7,
442 BRACKET_SYMBOLTYPE_DBNUM5
= -8,
443 BRACKET_SYMBOLTYPE_DBNUM6
= -9,
444 BRACKET_SYMBOLTYPE_DBNUM7
= -10,
445 BRACKET_SYMBOLTYPE_DBNUM8
= -11,
446 BRACKET_SYMBOLTYPE_DBNUM9
= -12,
447 BRACKET_SYMBOLTYPE_LOCALE
= -13,
448 BRACKET_SYMBOLTYPE_NATNUM0
= -14, // Our NativeNumber support, ASCII
449 BRACKET_SYMBOLTYPE_NATNUM1
= -15, // Our NativeNumber support, represent
450 BRACKET_SYMBOLTYPE_NATNUM2
= -16, // numbers using CJK, CTL, ...
451 BRACKET_SYMBOLTYPE_NATNUM3
= -17,
452 BRACKET_SYMBOLTYPE_NATNUM4
= -18,
453 BRACKET_SYMBOLTYPE_NATNUM5
= -19,
454 BRACKET_SYMBOLTYPE_NATNUM6
= -20,
455 BRACKET_SYMBOLTYPE_NATNUM7
= -21,
456 BRACKET_SYMBOLTYPE_NATNUM8
= -22,
457 BRACKET_SYMBOLTYPE_NATNUM9
= -23,
458 BRACKET_SYMBOLTYPE_NATNUM10
= -24,
459 BRACKET_SYMBOLTYPE_NATNUM11
= -25,
460 BRACKET_SYMBOLTYPE_NATNUM12
= -26,
461 BRACKET_SYMBOLTYPE_NATNUM13
= -27,
462 BRACKET_SYMBOLTYPE_NATNUM14
= -28,
463 BRACKET_SYMBOLTYPE_NATNUM15
= -29,
464 BRACKET_SYMBOLTYPE_NATNUM16
= -30,
465 BRACKET_SYMBOLTYPE_NATNUM17
= -31,
466 BRACKET_SYMBOLTYPE_NATNUM18
= -32,
467 BRACKET_SYMBOLTYPE_NATNUM19
= -33
470 void SvNumberformat::ImpCopyNumberformat( const SvNumberformat
& rFormat
)
472 sFormatstring
= rFormat
.sFormatstring
;
473 eType
= rFormat
.eType
;
474 maLocale
= rFormat
.maLocale
;
475 fLimit1
= rFormat
.fLimit1
;
476 fLimit2
= rFormat
.fLimit2
;
479 bStandard
= rFormat
.bStandard
;
480 bIsUsed
= rFormat
.bIsUsed
;
481 sComment
= rFormat
.sComment
;
482 bAdditionalBuiltin
= rFormat
.bAdditionalBuiltin
;
484 // #121103# when copying between documents, get color pointers from own scanner
485 ImpSvNumberformatScan
* pColorSc
= ( &rScan
!= &rFormat
.rScan
) ? &rScan
: NULL
;
487 for (sal_uInt16 i
= 0; i
< 4; i
++)
489 NumFor
[i
].Copy(rFormat
.NumFor
[i
], pColorSc
);
493 SvNumberformat::SvNumberformat( SvNumberformat
& rFormat
)
494 : rScan(rFormat
.rScan
), bStarFlag( rFormat
.bStarFlag
)
496 ImpCopyNumberformat( rFormat
);
499 SvNumberformat::SvNumberformat( SvNumberformat
& rFormat
, ImpSvNumberformatScan
& rSc
)
501 , bStarFlag( rFormat
.bStarFlag
)
503 ImpCopyNumberformat( rFormat
);
506 static bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType
)
508 if ( nSymbolType
> 0 )
510 return true; // conditions
512 switch ( nSymbolType
)
514 case BRACKET_SYMBOLTYPE_COLOR
:
515 case BRACKET_SYMBOLTYPE_DBNUM1
:
516 case BRACKET_SYMBOLTYPE_DBNUM2
:
517 case BRACKET_SYMBOLTYPE_DBNUM3
:
518 case BRACKET_SYMBOLTYPE_DBNUM4
:
519 case BRACKET_SYMBOLTYPE_DBNUM5
:
520 case BRACKET_SYMBOLTYPE_DBNUM6
:
521 case BRACKET_SYMBOLTYPE_DBNUM7
:
522 case BRACKET_SYMBOLTYPE_DBNUM8
:
523 case BRACKET_SYMBOLTYPE_DBNUM9
:
524 case BRACKET_SYMBOLTYPE_LOCALE
:
525 case BRACKET_SYMBOLTYPE_NATNUM0
:
526 case BRACKET_SYMBOLTYPE_NATNUM1
:
527 case BRACKET_SYMBOLTYPE_NATNUM2
:
528 case BRACKET_SYMBOLTYPE_NATNUM3
:
529 case BRACKET_SYMBOLTYPE_NATNUM4
:
530 case BRACKET_SYMBOLTYPE_NATNUM5
:
531 case BRACKET_SYMBOLTYPE_NATNUM6
:
532 case BRACKET_SYMBOLTYPE_NATNUM7
:
533 case BRACKET_SYMBOLTYPE_NATNUM8
:
534 case BRACKET_SYMBOLTYPE_NATNUM9
:
535 case BRACKET_SYMBOLTYPE_NATNUM10
:
536 case BRACKET_SYMBOLTYPE_NATNUM11
:
537 case BRACKET_SYMBOLTYPE_NATNUM12
:
538 case BRACKET_SYMBOLTYPE_NATNUM13
:
539 case BRACKET_SYMBOLTYPE_NATNUM14
:
540 case BRACKET_SYMBOLTYPE_NATNUM15
:
541 case BRACKET_SYMBOLTYPE_NATNUM16
:
542 case BRACKET_SYMBOLTYPE_NATNUM17
:
543 case BRACKET_SYMBOLTYPE_NATNUM18
:
544 case BRACKET_SYMBOLTYPE_NATNUM19
:
551 OUString
SvNumberformat::ImpObtainCalendarAndNumerals( OUStringBuffer
& rString
, sal_Int32
& nPos
,
552 LanguageType
& nLang
, const LocaleType
& aTmpLocale
)
555 /* TODO: this could be enhanced to allow other possible locale dependent
556 * calendars and numerals. BUT only if our locale data allows it! For LCID
557 * numerals and calendars see
558 * http://office.microsoft.com/en-us/excel/HA010346351033.aspx */
559 if (MsLangId::getRealLanguage( aTmpLocale
.meLanguage
) == LANGUAGE_THAI
)
561 // Numeral shape code "D" = Thai digits.
562 if (aTmpLocale
.mnNumeralShape
== 0xD)
564 rString
.insert( nPos
, "[NatNum1]");
566 // Calendar type code "07" = Thai Buddhist calendar, insert this after
567 // all prefixes have been consumed as it is actually a format modifier
569 if (aTmpLocale
.mnCalendarType
== 0x07)
571 // Currently calendars are tied to the locale of the entire number
572 // format, e.g. [~buddhist] in en_US doesn't work.
573 // => Having different locales in sub formats does not work!
574 /* TODO: calendars could be tied to a sub format's NatNum info
575 * instead, or even better be available for any locale. Needs a
576 * different implementation of GetCal() and locale data calendars.
578 // If this is not Thai yet, make it so.
579 if (MsLangId::getRealLanguage( maLocale
.meLanguage
) != LANGUAGE_THAI
)
581 maLocale
= aTmpLocale
;
582 nLang
= maLocale
.meLanguage
= LANGUAGE_THAI
;
584 sCalendar
="[~buddhist]";
591 SvNumberformat::SvNumberformat(OUString
& rString
,
592 ImpSvNumberformatScan
* pSc
,
593 ImpSvNumberInputScan
* pISc
,
594 sal_Int32
& nCheckPos
,
598 , bAdditionalBuiltin( false )
601 OUStringBuffer
sBuff(rString
);
603 // If the group (AKA thousand) separator is a No-Break Space (French)
604 // replace all occurrences by a simple space.
605 // The same for Narrow No-Break Space just in case some locale uses it.
606 // The tokens will be changed to the LocaleData separator again later on.
607 const OUString
& rThSep
= GetFormatter().GetNumThousandSep();
608 if ( rThSep
.getLength() == 1)
610 const sal_Unicode cNBSp
= 0xA0;
611 const sal_Unicode cNNBSp
= 0x202F;
612 if (rThSep
[0] == cNBSp
)
613 sBuff
.replace( cNBSp
, ' ');
614 else if (rThSep
[0] == cNNBSp
)
615 sBuff
.replace( cNNBSp
, ' ');
618 if (rScan
.GetConvertMode())
620 maLocale
.meLanguage
= rScan
.GetNewLnge();
621 eLan
= maLocale
.meLanguage
; // Make sure to return switch
625 maLocale
.meLanguage
= eLan
;
631 eOp1
= NUMBERFORMAT_OP_NO
;
632 eOp2
= NUMBERFORMAT_OP_NO
;
633 eType
= css::util::NumberFormat::DEFINED
;
635 bool bCancel
= false;
636 bool bCondition
= false;
642 // Split into 4 sub formats
644 for ( nIndex
= 0; nIndex
< 4 && !bCancel
; nIndex
++ )
646 // Original language/country may have to be reestablished
647 if (rScan
.GetConvertMode())
649 (rScan
.GetNumberformatter())->ChangeIntl(rScan
.GetTmpLnge());
651 OUString sInsertCalendar
; // a calendar resulting from parsing LCID
653 nPosOld
= nPos
; // Start position of substring
654 // first get bracketed prefixes; e.g. conditions, color
657 eSymbolType
= ImpNextSymbol(sBuff
, nPos
, sStr
);
658 if (eSymbolType
> 0) // condition
660 if ( nIndex
== 0 && !bCondition
)
663 eOp1
= (SvNumberformatLimitOps
) eSymbolType
;
665 else if ( nIndex
== 1 && bCondition
)
667 eOp2
= (SvNumberformatLimitOps
) eSymbolType
;
671 bCancel
= true; // break for
677 sal_Int32 nAnzChars
= ImpGetNumber(sBuff
, nPos
, sStr
);
680 short F_Type
= css::util::NumberFormat::UNDEFINED
;
681 if (!pISc
->IsNumberFormat(sStr
,F_Type
,fNumber
) ||
682 ( F_Type
!= css::util::NumberFormat::NUMBER
&&
683 F_Type
!= css::util::NumberFormat::SCIENTIFIC
) )
686 nPos
= nPos
- nAnzChars
;
687 sBuff
.remove(nPos
, nAnzChars
);
688 sBuff
.insert(nPos
, '0');
695 sBuff
.insert(nPos
++, '0');
705 if ( nPos
< sBuff
.getLength() && sBuff
[nPos
] == ']' )
711 bCancel
= true; // break for
715 nPosOld
= nPos
; // position before string
717 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) )
719 OUString
sSymbol( sStr
);
720 switch ( eSymbolType
)
722 case BRACKET_SYMBOLTYPE_COLOR
:
723 if ( NumFor
[nIndex
].GetColor() != NULL
)
724 { // error, more than one color
725 bCancel
= true; // break for
730 Color
* pColor
= pSc
->GetColor( sStr
);
731 NumFor
[nIndex
].SetColor( pColor
, sStr
);
734 bCancel
= true; // break for
739 case BRACKET_SYMBOLTYPE_NATNUM0
:
740 case BRACKET_SYMBOLTYPE_NATNUM1
:
741 case BRACKET_SYMBOLTYPE_NATNUM2
:
742 case BRACKET_SYMBOLTYPE_NATNUM3
:
743 case BRACKET_SYMBOLTYPE_NATNUM4
:
744 case BRACKET_SYMBOLTYPE_NATNUM5
:
745 case BRACKET_SYMBOLTYPE_NATNUM6
:
746 case BRACKET_SYMBOLTYPE_NATNUM7
:
747 case BRACKET_SYMBOLTYPE_NATNUM8
:
748 case BRACKET_SYMBOLTYPE_NATNUM9
:
749 case BRACKET_SYMBOLTYPE_NATNUM10
:
750 case BRACKET_SYMBOLTYPE_NATNUM11
:
751 case BRACKET_SYMBOLTYPE_NATNUM12
:
752 case BRACKET_SYMBOLTYPE_NATNUM13
:
753 case BRACKET_SYMBOLTYPE_NATNUM14
:
754 case BRACKET_SYMBOLTYPE_NATNUM15
:
755 case BRACKET_SYMBOLTYPE_NATNUM16
:
756 case BRACKET_SYMBOLTYPE_NATNUM17
:
757 case BRACKET_SYMBOLTYPE_NATNUM18
:
758 case BRACKET_SYMBOLTYPE_NATNUM19
:
759 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
761 bCancel
= true; // break for
767 //! eSymbolType is negative
768 sal_uInt8 nNum
= (sal_uInt8
)(0 - (eSymbolType
- BRACKET_SYMBOLTYPE_NATNUM0
));
769 sStr
+= OUString::number( nNum
);
770 NumFor
[nIndex
].SetNatNumNum( nNum
, false );
773 case BRACKET_SYMBOLTYPE_DBNUM1
:
774 case BRACKET_SYMBOLTYPE_DBNUM2
:
775 case BRACKET_SYMBOLTYPE_DBNUM3
:
776 case BRACKET_SYMBOLTYPE_DBNUM4
:
777 case BRACKET_SYMBOLTYPE_DBNUM5
:
778 case BRACKET_SYMBOLTYPE_DBNUM6
:
779 case BRACKET_SYMBOLTYPE_DBNUM7
:
780 case BRACKET_SYMBOLTYPE_DBNUM8
:
781 case BRACKET_SYMBOLTYPE_DBNUM9
:
782 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
784 bCancel
= true; // break for
790 //! eSymbolType is negative
791 sal_uInt8 nNum
= (sal_uInt8
)(1 - (eSymbolType
- BRACKET_SYMBOLTYPE_DBNUM1
));
792 sStr
+= OUString((sal_Unicode
)('0' + nNum
));
793 NumFor
[nIndex
].SetNatNumNum( nNum
, true );
796 case BRACKET_SYMBOLTYPE_LOCALE
:
797 if ( NumFor
[nIndex
].GetNatNum().GetLang() != LANGUAGE_DONTKNOW
||
798 sBuff
[nPos
-1] != ']' )
799 // Check also for ']' to avoid pulling in
800 // locale data for the preview string for not
801 // yet completed LCIDs in the dialog.
803 bCancel
= true; // break for
809 LocaleType
aTmpLocale( ImpGetLocaleType( sStr
, nTmp
));
810 if (aTmpLocale
.meLanguage
== LANGUAGE_DONTKNOW
)
812 bCancel
= true; // break for
817 // Only the first sub format's locale will be
818 // used as the format's overall locale.
819 // Sorts this also under the corresponding
820 // locale for the dialog.
821 // If we don't support the locale this would
822 // result in an unknown (empty) language
823 // listbox entry and the user would never see
825 if (nIndex
== 0 && (aTmpLocale
.meLanguage
== 0 ||
826 SvNumberFormatter::IsLocaleInstalled( aTmpLocale
.meLanguage
)))
828 maLocale
= aTmpLocale
;
829 eLan
= aTmpLocale
.meLanguage
; // return to caller
830 /* TODO: fiddle with scanner to make this
831 * known? A change in the locale may affect
832 * separators and keywords. On the other
833 * hand they may have been entered as used
834 * in the originating locale, there's no
835 * way to predict other than analyzing the
836 * format code, we assume here the current
837 * context is used, which is most likely
841 sStr
= "$-" + aTmpLocale
.generateCode();
842 NumFor
[nIndex
].SetNatNumLang( MsLangId::getRealLanguage( aTmpLocale
.meLanguage
));
844 // "$-NNCCLLLL" Numerals and Calendar
845 if (sSymbol
.getLength() > 6)
847 sInsertCalendar
= ImpObtainCalendarAndNumerals( sBuff
, nPos
, eLan
, aTmpLocale
);
849 /* NOTE: there can be only one calendar
850 * inserted so the last one wins, though
851 * our own calendar modifiers support
852 * multiple calendars within one sub format
853 * code if at different positions. */
866 sBuff
.remove(nPosOld
, nPos
- nPosOld
);
869 sBuff
.insert(nPosOld
, sStr
);
870 nPos
= nPosOld
+ sStr
.getLength();
871 sBuff
.insert(nPos
, "]");
872 sBuff
.insert(nPosOld
, "[");
874 nPosOld
= nPos
; // position before string
878 nPos
= nPosOld
; // prefix removed for whatever reason
884 while ( !bCancel
&& lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) );
886 // The remaining format code string
889 if (eSymbolType
== BRACKET_SYMBOLTYPE_FORMAT
)
891 if (nIndex
== 1 && eOp1
== NUMBERFORMAT_OP_NO
)
893 eOp1
= NUMBERFORMAT_OP_GT
; // undefined condition, default: > 0
895 else if (nIndex
== 2 && eOp2
== NUMBERFORMAT_OP_NO
)
897 eOp2
= NUMBERFORMAT_OP_LT
; // undefined condition, default: < 0
905 if (!sInsertCalendar
.isEmpty())
907 sStr
= sInsertCalendar
+ sStr
;
909 sal_Int32 nStrPos
= pSc
->ScanFormat( sStr
);
910 sal_uInt16 nAnz
= pSc
->GetAnzResStrings();
911 if (nAnz
== 0) // error
915 if (nStrPos
== 0) // ok
917 // e.g. Thai T speciality
918 if (pSc
->GetNatNumModifier() && !NumFor
[nIndex
].GetNatNum().IsSet())
920 sStr
= "[NatNum" + OUString::number( pSc
->GetNatNumModifier()) + "]" + sStr
;
921 NumFor
[nIndex
].SetNatNumNum( pSc
->GetNatNumModifier(), false );
923 // #i53826# #i42727# For the Thai T speciality we need
924 // to freeze the locale and immunize it against
925 // conversions during exports, just in case we want to
926 // save to Xcl. This disables the feature of being able
927 // to convert a NatNum to another locale. You can't
929 // FIXME: implement a specialized export conversion
930 // that works on tokens (have to tokenize all first)
931 // and doesn't use the format string and
932 // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
933 // sc/source/filter/excel/xestyle.cxx
934 // XclExpNumFmtBuffer::WriteFormatRecord().
935 LanguageType eLanguage
;
936 if (NumFor
[nIndex
].GetNatNum().GetNatNum() == 1 &&
937 ((eLanguage
= MsLangId::getRealLanguage( eLan
)) == LANGUAGE_THAI
) &&
938 NumFor
[nIndex
].GetNatNum().GetLang() == LANGUAGE_DONTKNOW
)
940 sStr
= "[$-" + OUString::number( eLanguage
, 16 ).toAsciiUpperCase() + "]" + sStr
;
941 NumFor
[nIndex
].SetNatNumLang( eLanguage
);
943 sBuff
.remove(nPosOld
, nPos
- nPosOld
);
944 sBuff
.insert(nPosOld
, sStr
);
945 nPos
= nPosOld
+ sStr
.getLength();
946 if (nPos
< sBuff
.getLength())
948 sBuff
.insert(nPos
, ";");
951 NumFor
[nIndex
].Enlarge(nAnz
);
952 pSc
->CopyInfo(&(NumFor
[nIndex
].Info()), nAnz
);
956 eType
= (short) NumFor
[nIndex
].Info().eScannedType
;
958 else if (nIndex
== 3)
959 { // #77026# Everything recognized IS text
960 NumFor
[nIndex
].Info().eScannedType
= css::util::NumberFormat::TEXT
;
962 else if ( (short) NumFor
[nIndex
].Info().eScannedType
!= eType
)
964 eType
= css::util::NumberFormat::DEFINED
;
969 nCheckPos
= nPosOld
+ nStrPos
; // error in string
970 bCancel
= true; // break for
974 else if (eSymbolType
== BRACKET_SYMBOLTYPE_ERROR
) // error
979 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) )
981 nCheckPos
= nPosOld
+ 1; // error, prefix in string
982 bCancel
= true; // break for
985 if ( bCancel
&& !nCheckPos
)
987 nCheckPos
= 1; // nCheckPos is used as an error condition
991 if ( NumFor
[nIndex
].GetNatNum().IsSet() &&
992 NumFor
[nIndex
].GetNatNum().GetLang() == LANGUAGE_DONTKNOW
)
994 NumFor
[nIndex
].SetNatNumLang( eLan
);
997 if (sBuff
.getLength() == nPos
)
999 if ( nIndex
== 2 && eSymbolType
== BRACKET_SYMBOLTYPE_FORMAT
&&
1000 sBuff
[nPos
- 1] == ';' )
1002 // #83510# A 4th subformat explicitly specified to be empty
1003 // hides any text. Need the type here for HasTextFormat()
1004 NumFor
[3].Info().eScannedType
= css::util::NumberFormat::TEXT
;
1008 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
1010 NumFor
[nIndex
].SetNatNumDate( (NumFor
[nIndex
].Info().eScannedType
& css::util::NumberFormat::DATE
) != 0 );
1014 if ( bCondition
&& !nCheckPos
)
1016 if ( nIndex
== 1 && NumFor
[0].GetCount() == 0 &&
1017 sBuff
[sBuff
.getLength() - 1] != ';' )
1019 // No format code => GENERAL but not if specified empty
1020 OUString
aAdd( pSc
->GetStandardName() );
1021 if ( !pSc
->ScanFormat( aAdd
) )
1023 sal_uInt16 nAnz
= pSc
->GetAnzResStrings();
1026 NumFor
[0].Enlarge(nAnz
);
1027 pSc
->CopyInfo( &(NumFor
[0].Info()), nAnz
);
1032 else if ( nIndex
== 1 && NumFor
[nIndex
].GetCount() == 0 &&
1033 sBuff
[sBuff
.getLength() - 1] != ';' &&
1034 (NumFor
[0].GetCount() > 1 ||
1035 (NumFor
[0].GetCount() == 1 &&
1036 NumFor
[0].Info().nTypeArray
[0] != NF_KEY_GENERAL
)) )
1038 // No trailing second subformat => GENERAL but not if specified empty
1039 // and not if first subformat is GENERAL
1040 OUString
aAdd( pSc
->GetStandardName() );
1041 if ( !pSc
->ScanFormat( aAdd
) )
1043 sal_uInt16 nAnz
= pSc
->GetAnzResStrings();
1046 NumFor
[nIndex
].Enlarge(nAnz
);
1047 pSc
->CopyInfo( &(NumFor
[nIndex
].Info()), nAnz
);
1053 else if ( nIndex
== 2 && NumFor
[nIndex
].GetCount() == 0 &&
1054 sBuff
[sBuff
.getLength() - 1] != ';' &&
1055 eOp2
!= NUMBERFORMAT_OP_NO
)
1057 // No trailing third subformat => GENERAL but not if specified empty
1058 OUString
aAdd( pSc
->GetStandardName() );
1059 if ( !pSc
->ScanFormat( aAdd
) )
1061 sal_uInt16 nAnz
= pSc
->GetAnzResStrings();
1064 NumFor
[nIndex
].Enlarge(nAnz
);
1065 pSc
->CopyInfo( &(NumFor
[nIndex
].Info()), nAnz
);
1072 rString
= sBuff
.makeStringAndClear();
1073 sFormatstring
= rString
;
1075 if (NumFor
[2].GetCount() == 0 && // No third partial string
1076 eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_NO
&&
1077 fLimit1
== 0.0 && fLimit2
== 0.0)
1079 eOp1
= NUMBERFORMAT_OP_GE
; // Add 0 to the first format
1084 SvNumberformat::~SvNumberformat()
1091 * Splits up the symbols for further processing (by the Turing machine)
1093 * Start state = SsStart, * = Special state
1094 * ---------------+-------------------+----------------------------+---------------
1095 * Old State | Symbol read | Event | New state
1096 * ---------------+-------------------+----------------------------+---------------
1097 * SsStart | ; | Pos-- | SsGetString
1098 * | [ | Symbol += Character | SsGetBracketed
1099 * | ] | Error | SsStop
1101 * | Else | Symbol += Character | SsGetString
1102 * ---------------+-------------------+----------------------------+---------------
1103 * SsGetString | ; | | SsStop
1104 * | Else | Symbol += Character |
1105 * ---------------+-------------------+----------------------------+---------------
1106 * SsGetBracketed | <, > = | del [ |
1107 * | | Symbol += Character | SsGetCon
1109 * | h, H, m, M, s, S | Symbol += Character | SsGetTime
1111 * | | Symbol += Character | SsGetPrefix
1112 * ---------------+-------------------+----------------------------+---------------
1113 * SsGetTime | ] | Symbol += Character | SsGetString
1114 * | h, H, m, M, s, S | Symbol += Character, * | SsGetString
1115 * | Else | del [; Symbol += Character | SsGetPrefix
1116 * ---------------+-------------------+----------------------------+---------------
1117 * SsGetPrefix | ] | | SsStop
1118 * | Else | Symbol += Character |
1119 * ---------------+-------------------+----------------------------+---------------
1120 * SsGetCon | >, = | Symbol += Character |
1122 * | Else | Error | SsStop
1123 * ---------------+-------------------+----------------------------+---------------
1130 SsGetCon
, // condition
1131 SsGetString
, // format string
1132 SsGetPrefix
, // color or NatNumN
1133 SsGetTime
, // [HH] for time
1134 SsGetBracketed
// any [...] not decided yet
1137 // read a string until ']' and delete spaces in input
1139 sal_Int32
SvNumberformat::ImpGetNumber(OUStringBuffer
& rString
,
1143 sal_Int32 nStartPos
= nPos
;
1145 sal_Int32 nLen
= rString
.getLength();
1146 OUStringBuffer sBuffSymbol
;
1147 while ( nPos
< nLen
&& ((cToken
= rString
[nPos
]) != ']') )
1151 rString
.remove(nPos
,1);
1157 sBuffSymbol
.append(cToken
);
1160 sSymbol
= sBuffSymbol
.makeStringAndClear();
1161 return nPos
- nStartPos
;
1166 sal_Unicode
toUniChar(sal_uInt8 n
)
1177 return sal_Unicode(c
);
1180 bool IsCombiningSymbol( OUStringBuffer
& rStringBuffer
, sal_Int32 nPos
)
1185 switch (rStringBuffer
[nPos
])
1202 OUString
SvNumberformat::LocaleType::generateCode() const
1204 OUStringBuffer aBuf
;
1206 // TODO: We may re-enable this later. Don't remove it! --Kohei
1209 sal_uInt8 nVal
= mnNumeralShape
;
1210 for (sal_uInt8 i
= 0; i
< 2; ++i
)
1212 sal_uInt8 n
= (nVal
& 0xF0) >> 4;
1213 if (n
|| aBuf
.getLength())
1215 aBuf
.append(toUniChar(n
));
1221 if (mnNumeralShape
|| mnCalendarType
)
1223 sal_uInt8 nVal
= mnCalendarType
;
1224 for (sal_uInt8 i
= 0; i
< 2; ++i
)
1226 sal_uInt8 n
= (nVal
& 0xF0) >> 4;
1227 if (n
|| aBuf
.getLength())
1229 aBuf
.append(toUniChar(n
));
1236 sal_uInt16 n16
= static_cast<sal_uInt16
>(meLanguage
);
1237 for (sal_uInt8 i
= 0; i
< 4; ++i
)
1239 sal_uInt8 n
= static_cast<sal_uInt8
>((n16
& 0xF000) >> 12);
1240 // Omit leading zeros for consistency.
1241 if (n
|| !aBuf
.isEmpty() || i
== 3)
1243 aBuf
.append(toUniChar(n
));
1248 return aBuf
.makeStringAndClear();
1251 SvNumberformat::LocaleType::LocaleType()
1254 , meLanguage(LANGUAGE_DONTKNOW
)
1258 SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum
)
1261 , meLanguage(LANGUAGE_DONTKNOW
)
1263 meLanguage
= static_cast<LanguageType
>(nRawNum
& 0x0000FFFF);
1264 nRawNum
= (nRawNum
>> 16);
1265 mnCalendarType
= static_cast<sal_uInt8
>(nRawNum
& 0xFF);
1266 nRawNum
= (nRawNum
>> 8);
1267 mnNumeralShape
= static_cast<sal_uInt8
>(nRawNum
& 0xFF);
1271 SvNumberformat::LocaleType
SvNumberformat::ImpGetLocaleType(const OUString
& rString
, sal_Int32
& nPos
)
1273 sal_uInt32 nNum
= 0;
1274 sal_Unicode cToken
= 0;
1275 sal_Int32 nStart
= nPos
;
1276 sal_Int32 nLen
= rString
.getLength();
1277 while ( nPos
< nLen
&& (nPos
- nStart
< 8) && ((cToken
= rString
[nPos
]) != ']') )
1279 if ( '0' <= cToken
&& cToken
<= '9' )
1282 nNum
+= cToken
- '0';
1284 else if ( 'a' <= cToken
&& cToken
<= 'f' )
1287 nNum
+= cToken
- 'a' + 10;
1289 else if ( 'A' <= cToken
&& cToken
<= 'F' )
1292 nNum
+= cToken
- 'A' + 10;
1296 return LANGUAGE_DONTKNOW
;
1301 return (cToken
== ']' || nPos
== nLen
) ? LocaleType(nNum
) : LocaleType();
1304 static bool lcl_matchKeywordAndGetNumber( const OUString
& rString
, const sal_Int32 nPos
,
1305 const OUString
& rKeyword
, sal_Int32
& nNumber
)
1307 if (0 <= nPos
&& nPos
+ rKeyword
.getLength() < rString
.getLength() && rString
.matchIgnoreAsciiCase( rKeyword
, nPos
))
1309 nNumber
= rString
.copy( nPos
+ rKeyword
.getLength()).toInt32();
1319 short SvNumberformat::ImpNextSymbol(OUStringBuffer
& rString
,
1323 short eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1325 sal_Unicode cLetter
= ' '; // Preliminary result
1326 sal_Int32 nLen
= rString
.getLength();
1327 ScanState eState
= SsStart
;
1328 OUStringBuffer sBuffSymbol
;
1330 const NfKeywordTable
& rKeywords
= rScan
.GetKeywords();
1331 while (nPos
< nLen
&& eState
!= SsStop
)
1333 cToken
= rString
[nPos
];
1340 eState
= SsGetBracketed
;
1341 sBuffSymbol
.append(cToken
);
1343 else if (cToken
== ';')
1345 eState
= SsGetString
;
1347 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1349 else if (cToken
== ']')
1352 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1354 else if (cToken
== ' ') // Skip Blanks
1357 rString
.remove(nPos
, 1);
1362 sBuffSymbol
.append(cToken
);
1363 eState
= SsGetString
;
1364 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1367 case SsGetBracketed
:
1373 sBuffSymbol
.stripStart('[');
1374 sBuffSymbol
.append(cToken
);
1380 eSymbolType
= NUMBERFORMAT_OP_LT
;
1383 eSymbolType
= NUMBERFORMAT_OP_GT
;
1386 eSymbolType
= NUMBERFORMAT_OP_EQ
;
1392 rString
.remove(nPos
, 1);
1396 if ( rString
[nPos
] == '-' )
1399 sBuffSymbol
.stripStart('[');
1400 eSymbolType
= BRACKET_SYMBOLTYPE_LOCALE
;
1401 eState
= SsGetPrefix
;
1405 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1406 eState
= SsGetString
;
1408 sBuffSymbol
.append(cToken
);
1412 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1413 sBuffSymbol
.append(cToken
);
1414 eState
= SsGetString
;
1418 const OUString
aNatNum("NATNUM");
1419 const OUString
aDBNum("DBNUM");
1420 const OUString
aBufStr( rString
.toString());
1421 sal_Int32 nNatNumNum
;
1423 if ( lcl_matchKeywordAndGetNumber( aBufStr
, nPos
-1, aNatNum
, nNatNumNum
) &&
1424 0 <= nNatNumNum
&& nNatNumNum
<= 19 )
1426 sBuffSymbol
.stripStart('[');
1427 sBuffSymbol
.append( aBufStr
.copy( --nPos
, aNatNum
.getLength()+1 ));
1428 nPos
+= aNatNum
.getLength()+1;
1429 //! SymbolType is negative
1430 eSymbolType
= (short) (BRACKET_SYMBOLTYPE_NATNUM0
- nNatNumNum
);
1431 eState
= SsGetPrefix
;
1433 else if ( lcl_matchKeywordAndGetNumber( aBufStr
, nPos
-1, aDBNum
, nDBNum
) &&
1434 '1' <= nDBNum
&& nDBNum
<= '9' )
1436 sBuffSymbol
.stripStart('[');
1437 sBuffSymbol
.append( aBufStr
.copy( --nPos
, aDBNum
.getLength()+1 ));
1438 nPos
+= aDBNum
.getLength()+1;
1439 //! SymbolType is negative
1440 eSymbolType
= sal::static_int_cast
< short >( BRACKET_SYMBOLTYPE_DBNUM1
- (nDBNum
- '1'));
1441 eState
= SsGetPrefix
;
1445 sal_Unicode cUpper
= rChrCls().uppercase( aBufStr
, nPos
-1, 1)[0];
1446 if ( cUpper
== rKeywords
[NF_KEY_H
][0] || // H
1447 cUpper
== rKeywords
[NF_KEY_MI
][0] || // M
1448 cUpper
== rKeywords
[NF_KEY_S
][0] ) // S
1450 sBuffSymbol
.append(cToken
);
1456 sBuffSymbol
.stripStart('[');
1457 sBuffSymbol
.append(cToken
);
1458 eSymbolType
= BRACKET_SYMBOLTYPE_COLOR
;
1459 eState
= SsGetPrefix
;
1466 if (cToken
== ';' && (nPos
< 2 || !IsCombiningSymbol( rString
, nPos
-2)))
1472 sBuffSymbol
.append(cToken
);
1478 sBuffSymbol
.append(cToken
);
1479 eState
= SsGetString
;
1480 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1484 sal_Unicode cUpper
= rChrCls().uppercase(rString
.toString(), nPos
-1, 1)[0];
1485 if (cUpper
== rKeywords
[NF_KEY_H
][0] || // H
1486 cUpper
== rKeywords
[NF_KEY_MI
][0] || // M
1487 cUpper
== rKeywords
[NF_KEY_S
][0] ) // S
1489 if (cLetter
== cToken
)
1491 sBuffSymbol
.append(cToken
);
1496 sBuffSymbol
.stripStart('[');
1497 sBuffSymbol
.append(cToken
);
1498 eState
= SsGetPrefix
;
1503 sBuffSymbol
.stripStart('[');
1504 sBuffSymbol
.append(cToken
);
1505 eSymbolType
= BRACKET_SYMBOLTYPE_COLOR
;
1506 eState
= SsGetPrefix
;
1515 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1520 sBuffSymbol
.append(cToken
);
1523 eSymbolType
= NUMBERFORMAT_OP_NE
;
1528 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1534 sBuffSymbol
.append(cToken
);
1536 eSymbolType
= NUMBERFORMAT_OP_LE
;
1538 else if (cLetter
== '>')
1540 sBuffSymbol
.append(cToken
);
1542 eSymbolType
= NUMBERFORMAT_OP_GE
;
1547 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1552 rString
.remove(nPos
,1);
1568 sBuffSymbol
.append(cToken
);
1575 sSymbol
= sBuffSymbol
.makeStringAndClear();
1579 void SvNumberformat::ConvertLanguage( SvNumberFormatter
& rConverter
,
1580 LanguageType eConvertFrom
,
1581 LanguageType eConvertTo
, bool bSystem
)
1583 sal_Int32 nCheckPos
;
1585 short nType
= eType
;
1586 OUString
aFormatString( sFormatstring
);
1589 rConverter
.PutandConvertEntrySystem( aFormatString
, nCheckPos
, nType
,
1590 nKey
, eConvertFrom
, eConvertTo
);
1594 rConverter
.PutandConvertEntry( aFormatString
, nCheckPos
, nType
,
1595 nKey
, eConvertFrom
, eConvertTo
);
1597 const SvNumberformat
* pFormat
= rConverter
.GetEntry( nKey
);
1598 DBG_ASSERT( pFormat
, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
1601 ImpCopyNumberformat( *pFormat
);
1602 // Reset values taken over from Formatter/Scanner
1605 maLocale
.meLanguage
= LANGUAGE_SYSTEM
;
1607 // pColor still points to table in temporary Formatter/Scanner
1608 for ( sal_uInt16 i
= 0; i
< 4; i
++ )
1610 OUString aColorName
= NumFor
[i
].GetColorName();
1611 Color
* pColor
= rScan
.GetColor( aColorName
);
1612 NumFor
[i
].SetColor( pColor
, aColorName
);
1617 bool SvNumberformat::HasNewCurrency() const
1619 for ( sal_uInt16 j
=0; j
<4; j
++ )
1621 if ( NumFor
[j
].HasNewCurrency() )
1629 bool SvNumberformat::GetNewCurrencySymbol( OUString
& rSymbol
,
1630 OUString
& rExtension
) const
1632 for ( sal_uInt16 j
=0; j
<4; j
++ )
1634 if ( NumFor
[j
].GetNewCurrencySymbol( rSymbol
, rExtension
) )
1645 OUString
SvNumberformat::StripNewCurrencyDelimiters( const OUString
& rStr
,
1649 OUString
aSource(rStr
);
1650 sal_Int32 nStartPos
, nPos
, nLen
;
1651 nLen
= aSource
.getLength();
1653 while ( (nPos
= aSource
.indexOf( "[$", nStartPos
)) >= 0 )
1656 if ( (nEnd
= GetQuoteEnd( aSource
, nPos
)) >= 0 )
1658 aTmp
+= aSource
.copy( nStartPos
, ++nEnd
- nStartPos
);
1663 aTmp
+= aSource
.copy( nStartPos
, nPos
- nStartPos
);
1664 nStartPos
= nPos
+ 2;
1666 nEnd
= nStartPos
- 1;
1669 nDash
= aSource
.indexOf( '-', ++nEnd
);
1671 while ( (nEnd
= GetQuoteEnd( aSource
, nDash
)) >= 0 );
1673 nEnd
= nStartPos
- 1;
1676 nClose
= aSource
.indexOf( ']', ++nEnd
);
1678 while ( (nEnd
= GetQuoteEnd( aSource
, nClose
)) >= 0 );
1682 /* there should always be a closing ]
1683 * but the old String class would have hidden
1684 * that. so be conservative too
1690 if(nDash
>= 0 && nDash
< nClose
)
1694 if ( !bQuoteSymbol
|| aSource
[ nStartPos
] == '"' )
1696 aTmp
+= aSource
.copy( nStartPos
, nPos
- nStartPos
);
1701 aTmp
+= aSource
.copy( nStartPos
, nPos
- nStartPos
);
1704 nStartPos
= nClose
+ 1;
1707 if ( nLen
> nStartPos
)
1709 aTmp
+= aSource
.copy( nStartPos
, nLen
- nStartPos
);
1714 void SvNumberformat::ImpGetOutputStandard(double& fNumber
, OUStringBuffer
& rOutString
)
1717 ImpGetOutputStandard(fNumber
, sTemp
);
1721 void SvNumberformat::ImpGetOutputStandard(double& fNumber
, OUString
& rOutString
)
1723 sal_uInt16 nStandardPrec
= rScan
.GetStandardPrec();
1725 if ( fabs(fNumber
) > EXP_ABS_UPPER_BOUND
)
1727 nStandardPrec
= ::std::min(nStandardPrec
, static_cast<sal_uInt16
>(14)); // limits to 14 decimals
1728 rOutString
= ::rtl::math::doubleToUString( fNumber
,
1729 rtl_math_StringFormat_E2
, nStandardPrec
/*2*/,
1730 GetFormatter().GetNumDecimalSep()[0]);
1734 ImpGetOutputStdToPrecision(fNumber
, rOutString
, nStandardPrec
);
1738 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber
, OUString
& rOutString
, sal_uInt16 nPrecision
) const
1740 // Make sure the precision doesn't go over the maximum allowable precision.
1741 nPrecision
= ::std::min(UPPER_PRECISION
, nPrecision
);
1745 // debugger test case for ANSI standard correctness
1747 // expect 0.00123 OK
1748 aTest
= ::rtl::math::doubleToUString( 0.001234567,
1749 rtl_math_StringFormat_G
, 3, '.', true );
1751 aTest
= ::rtl::math::doubleToUString( 123.4567,
1752 rtl_math_StringFormat_G
, 3, '.', true );
1754 aTest
= ::rtl::math::doubleToUString( 123.4567,
1755 rtl_math_StringFormat_G
, 4, '.', true );
1756 // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
1757 // 1000 with an exponent equal to significant digits)
1758 // Currently (24-Jan-2003) we do fail in this case and output 1000
1759 // instead, negligible.
1760 aTest
= ::rtl::math::doubleToUString( 999.6,
1761 rtl_math_StringFormat_G
, 3, '.', true );
1762 // expect what? result is 1.2e+004
1763 aTest
= ::rtl::math::doubleToUString( 12345.6789,
1764 rtl_math_StringFormat_G
, -3, '.', true );
1768 // We decided to strip trailing zeros unconditionally, since binary
1769 // double-precision rounding error makes it impossible to determine e.g.
1770 // whether 844.10000000000002273737 is what the user has typed, or the
1771 // user has typed 844.1 but IEEE 754 represents it that way internally.
1773 rOutString
= ::rtl::math::doubleToUString( rNumber
,
1774 rtl_math_StringFormat_F
, nPrecision
/*2*/,
1775 GetFormatter().GetNumDecimalSep()[0], true );
1776 if (rOutString
[0] == '-' &&
1777 comphelper::string::getTokenCount(rOutString
, '0') == rOutString
.getLength())
1779 rOutString
= comphelper::string::stripStart(rOutString
, '-'); // not -0
1781 rOutString
= impTransliterate(rOutString
, NumFor
[0].GetNatNum());
1784 void SvNumberformat::ImpGetOutputInputLine(double fNumber
, OUString
& OutString
)
1786 bool bModified
= false;
1787 if ( (eType
& css::util::NumberFormat::PERCENT
) && (fabs(fNumber
) < _D_MAX_D_BY_100
))
1804 OutString
= ::rtl::math::doubleToUString( fNumber
,
1805 rtl_math_StringFormat_Automatic
,
1806 rtl_math_DecimalPlaces_Max
,
1807 GetFormatter().GetNumDecimalSep()[0], true );
1809 if ( eType
& css::util::NumberFormat::PERCENT
&& bModified
)
1816 short SvNumberformat::ImpCheckCondition(double& fNumber
,
1818 SvNumberformatLimitOps eOp
)
1822 case NUMBERFORMAT_OP_NO
:
1824 case NUMBERFORMAT_OP_EQ
:
1825 return (short) (fNumber
== fLimit
);
1826 case NUMBERFORMAT_OP_NE
:
1827 return (short) (fNumber
!= fLimit
);
1828 case NUMBERFORMAT_OP_LT
:
1829 return (short) (fNumber
< fLimit
);
1830 case NUMBERFORMAT_OP_LE
:
1831 return (short) (fNumber
<= fLimit
);
1832 case NUMBERFORMAT_OP_GT
:
1833 return (short) (fNumber
> fLimit
);
1834 case NUMBERFORMAT_OP_GE
:
1835 return (short) (fNumber
>= fLimit
);
1841 static bool lcl_appendStarFillChar( OUStringBuffer
& rBuf
, const OUString
& rStr
)
1843 // Right during user input the star symbol is the very
1844 // last character before the user enters another one.
1845 if (rStr
.getLength() > 1)
1847 rBuf
.append((sal_Unicode
) 0x1B);
1848 rBuf
.append(rStr
[1]);
1854 static bool lcl_insertStarFillChar( OUStringBuffer
& rBuf
, sal_Int32 nPos
, const OUString
& rStr
)
1856 if (rStr
.getLength() > 1)
1858 rBuf
.insert( nPos
, rStr
[1]);
1859 rBuf
.insert( nPos
, (sal_Unicode
) 0x1B);
1865 bool SvNumberformat::GetOutputString(const OUString
& sString
,
1866 OUString
& OutString
,
1869 OUStringBuffer sOutBuff
;
1871 if (eType
& css::util::NumberFormat::TEXT
)
1875 else if (NumFor
[3].GetCount() > 0)
1881 *ppColor
= NULL
; // no change of color
1884 *ppColor
= NumFor
[nIx
].GetColor();
1885 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
1887 if (rInfo
.eScannedType
== css::util::NumberFormat::TEXT
)
1889 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
1890 for (sal_uInt16 i
= 0; i
< nAnz
; i
++)
1892 switch (rInfo
.nTypeArray
[i
])
1894 case NF_SYMBOLTYPE_STAR
:
1897 bRes
= lcl_appendStarFillChar( sOutBuff
, rInfo
.sStrArray
[i
]);
1900 case NF_SYMBOLTYPE_BLANK
:
1901 InsertBlanks( sOutBuff
, sOutBuff
.getLength(),
1902 rInfo
.sStrArray
[i
][1] );
1904 case NF_KEY_GENERAL
: // #77026# "General" is the same as "@"
1905 case NF_SYMBOLTYPE_DEL
:
1906 sOutBuff
.append(sString
);
1909 sOutBuff
.append(rInfo
.sStrArray
[i
]);
1913 OutString
= sOutBuff
.makeStringAndClear();
1917 sal_uLong
SvNumberformat::ImpGGT(sal_uLong x
, sal_uLong y
)
1936 sal_uLong
SvNumberformat::ImpGGTRound(sal_uLong x
, sal_uLong y
)
1945 while ((double)z
/(double)y
> D_EPS
)
1957 void lcl_GetOutputStringScientific(double fNumber
, sal_uInt16 nCharCount
,
1958 const SvNumberFormatter
& rFormatter
, OUString
& rOutString
)
1960 bool bSign
= ::rtl::math::isSignBitSet(fNumber
);
1962 // 1.000E+015 (one digit and the decimal point, and the two chars +
1963 // nExpDigit for the exponential part, totalling 6 or 7).
1964 double fExp
= log10( fabs(fNumber
) );
1967 sal_uInt16 nCharFormat
= 6 + (fExp
>= 100.0 ? 1 : 0);
1968 sal_uInt16 nPrec
= nCharCount
> nCharFormat
? nCharCount
- nCharFormat
: 0;
1971 // Make room for the negative sign.
1974 nPrec
= ::std::min(nPrec
, static_cast<sal_uInt16
>(14)); // limit to 14 decimals.
1976 rOutString
= ::rtl::math::doubleToUString(fNumber
, rtl_math_StringFormat_E2
,
1977 nPrec
, rFormatter
.GetNumDecimalSep()[0], true );
1980 sal_Int32
lcl_GetForcedDenominator(const ImpSvNumberformatInfo
&rInfo
, sal_uInt16 nAnz
)
1984 for( i
= 0; i
< nAnz
; i
++ )
1986 if( rInfo
.nTypeArray
[i
] == NF_SYMBOLTYPE_FRAC_FDIV
)
1988 aDiv
+= rInfo
.sStrArray
[i
];
1991 return aDiv
.toInt32();
1994 // TODO: More optimizations?
1995 void lcl_ForcedDenominator(sal_uLong
&nFrac
, sal_uLong
&nDiv
, sal_uLong nForcedDiv
)
1997 double fFrac
= (double)nFrac
/ (double)nDiv
;
1998 double fMultiplier
= (double)nForcedDiv
/ (double)nDiv
;
1999 nFrac
= (sal_uLong
)( (double)nFrac
* fMultiplier
);
2001 double fFracNew
= (double)nFrac
/ (double)nForcedDiv
;
2002 double fFracNew1
= (double)(nFrac
+ 1) / (double)nForcedDiv
;
2003 double fDiff
= fFrac
- fFracNew
;
2004 if( fDiff
> ( fFracNew1
- fFrac
) )
2013 sal_Int32
SvNumberformat::GetForcedDenominatorForType( sal_uInt16 nNumFor
) const
2015 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nNumFor
].Info();
2016 sal_uInt16 nAnz
= NumFor
[nNumFor
].GetCount();
2017 return lcl_GetForcedDenominator( rInfo
, nAnz
);
2020 bool SvNumberformat::GetOutputString(double fNumber
, sal_uInt16 nCharCount
, OUString
& rOutString
) const
2022 using namespace std
;
2024 if (eType
!= css::util::NumberFormat::NUMBER
)
2028 double fTestNum
= fNumber
;
2029 bool bSign
= ::rtl::math::isSignBitSet(fTestNum
);
2032 fTestNum
= -fTestNum
;
2034 if (fTestNum
< EXP_LOWER_BOUND
)
2036 lcl_GetOutputStringScientific(fNumber
, nCharCount
, GetFormatter(), rOutString
);
2040 double fExp
= log10(fTestNum
);
2041 // Values < 1.0 always have one digit before the decimal point.
2042 sal_uInt16 nDigitPre
= fExp
>= 0.0 ? static_cast<sal_uInt16
>(ceil(fExp
)) : 1;
2046 lcl_GetOutputStringScientific(fNumber
, nCharCount
, GetFormatter(), rOutString
);
2050 sal_uInt16 nPrec
= nCharCount
>= nDigitPre
? nCharCount
- nDigitPre
: 0;
2053 // Subtract the negative sign.
2058 // Subtract the decimal point.
2061 ImpGetOutputStdToPrecision(fNumber
, rOutString
, nPrec
);
2062 if (rOutString
.getLength() > nCharCount
)
2064 // String still wider than desired. Switch to scientific notation.
2065 lcl_GetOutputStringScientific(fNumber
, nCharCount
, GetFormatter(), rOutString
);
2070 bool SvNumberformat::GetOutputString(double fNumber
,
2071 OUString
& OutString
,
2075 OUStringBuffer sBuff
;
2077 *ppColor
= NULL
; // No color change
2078 if (eType
& css::util::NumberFormat::LOGICAL
)
2082 OutString
= rScan
.GetTrueString();
2086 OutString
= rScan
.GetFalseString();
2090 if (eType
& css::util::NumberFormat::TEXT
)
2092 ImpGetOutputStandard(fNumber
, sBuff
);
2093 OutString
= sBuff
.makeStringAndClear();
2096 bool bHadStandard
= false;
2097 if (bStandard
) // Individual standard formats
2099 if (rScan
.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION
) // All number format InputLine
2101 ImpGetOutputInputLine(fNumber
, OutString
);
2106 case css::util::NumberFormat::NUMBER
: // Standard number format
2107 if (rScan
.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION
)
2109 bool bSign
= ::rtl::math::isSignBitSet(fNumber
);
2112 if (!(fNumber
< 0.0))
2118 /* TODO: why did we insist on 10 decimals for the non-exponent
2119 * case? doubleToUString() handles rtl_math_DecimalPlaces_Max
2120 * gracefully when used with rtl_math_StringFormat_Automatic,
2121 * so all that special casing and mumbo-jumbo in the else
2122 * branch below might not be needed at all. */
2123 if (fNumber
> EXP_ABS_UPPER_BOUND
)
2125 sBuff
.append( ::rtl::math::doubleToUString( fNumber
,
2126 rtl_math_StringFormat_Automatic
,
2127 rtl_math_DecimalPlaces_Max
,
2128 GetFormatter().GetNumDecimalSep()[0], true));
2133 ImpGetOutputStdToPrecision(fNumber
, sTemp
, 10); // Use 10 decimals for general 'unlimited' format.
2134 sBuff
.append(sTemp
);
2135 if (fNumber
< EXP_LOWER_BOUND
)
2137 sal_Int32 nLen
= sBuff
.getLength();
2142 // #i112250# With the 10-decimal limit, small numbers are formatted as "0".
2143 // Switch to scientific in that case, too:
2144 if (nLen
> 11 || ((nLen
== 1 && sBuff
[0] == '0') && fNumber
!= 0.0))
2146 sal_uInt16 nStandardPrec
= rScan
.GetStandardPrec();
2147 nStandardPrec
= ::std::min(nStandardPrec
, static_cast<sal_uInt16
>(14)); // limits to 14 decimals
2148 sBuff
= ::rtl::math::doubleToUString( fNumber
,
2149 rtl_math_StringFormat_E2
, nStandardPrec
/*2*/,
2150 GetFormatter().GetNumDecimalSep()[0], true);
2156 sBuff
.insert(0, '-');
2158 OutString
= sBuff
.makeStringAndClear();
2161 ImpGetOutputStandard(fNumber
, sBuff
);
2162 bHadStandard
= true;
2164 case css::util::NumberFormat::DATE
:
2165 bRes
|= ImpGetDateOutput(fNumber
, 0, sBuff
);
2166 bHadStandard
= true;
2168 case css::util::NumberFormat::TIME
:
2169 bRes
|= ImpGetTimeOutput(fNumber
, 0, sBuff
);
2170 bHadStandard
= true;
2172 case css::util::NumberFormat::DATETIME
:
2173 bRes
|= ImpGetDateTimeOutput(fNumber
, 0, sBuff
);
2174 bHadStandard
= true;
2178 if ( !bHadStandard
)
2180 sal_uInt16 nIx
; // Index of the partial format
2181 short nCheck
= ImpCheckCondition(fNumber
, fLimit1
, eOp1
);
2182 if (nCheck
== -1 || nCheck
== 1) // Only 1 String or True
2188 nCheck
= ImpCheckCondition(fNumber
, fLimit2
, eOp2
);
2189 if (nCheck
== -1 || nCheck
== 1)
2198 if (fNumber
< 0.0 &&
2199 ((nIx
== 0 && IsFirstSubformatRealNegative()) || // 1st, usually positive subformat
2200 (nIx
== 1 && IsSecondSubformatRealNegative()))) // 2nd, usually negative subformat
2202 fNumber
= -fNumber
; // eliminate sign
2204 *ppColor
= NumFor
[nIx
].GetColor();
2205 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2206 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
2207 if (nAnz
== 0 && rInfo
.eScannedType
== css::util::NumberFormat::UNDEFINED
)
2209 return false; // Empty => nothing
2211 else if (nAnz
== 0) // Else Standard Format
2213 ImpGetOutputStandard(fNumber
, sBuff
);
2214 OutString
= sBuff
.makeStringAndClear();
2217 switch (rInfo
.eScannedType
)
2219 case css::util::NumberFormat::TEXT
:
2220 case css::util::NumberFormat::DEFINED
:
2221 for (sal_uInt16 i
= 0; i
< nAnz
; i
++)
2223 switch (rInfo
.nTypeArray
[i
])
2225 case NF_SYMBOLTYPE_STAR
:
2228 bRes
= lcl_appendStarFillChar( sBuff
, rInfo
.sStrArray
[i
]);
2231 case NF_SYMBOLTYPE_BLANK
:
2232 InsertBlanks(sBuff
, sBuff
.getLength(),
2233 rInfo
.sStrArray
[i
][1] );
2235 case NF_SYMBOLTYPE_STRING
:
2236 case NF_SYMBOLTYPE_CURRENCY
:
2237 sBuff
.append(rInfo
.sStrArray
[i
]);
2239 case NF_SYMBOLTYPE_THSEP
:
2240 if (rInfo
.nThousand
== 0)
2242 sBuff
.append(rInfo
.sStrArray
[i
]);
2250 case css::util::NumberFormat::DATE
:
2251 bRes
|= ImpGetDateOutput(fNumber
, nIx
, sBuff
);
2253 case css::util::NumberFormat::TIME
:
2254 bRes
|= ImpGetTimeOutput(fNumber
, nIx
, sBuff
);
2256 case css::util::NumberFormat::DATETIME
:
2257 bRes
|= ImpGetDateTimeOutput(fNumber
, nIx
, sBuff
);
2259 case css::util::NumberFormat::NUMBER
:
2260 case css::util::NumberFormat::PERCENT
:
2261 case css::util::NumberFormat::CURRENCY
:
2262 bRes
|= ImpGetNumberOutput(fNumber
, nIx
, sBuff
);
2264 case css::util::NumberFormat::FRACTION
:
2265 bRes
|= ImpGetFractionOutput(fNumber
, nIx
, sBuff
);
2267 case css::util::NumberFormat::SCIENTIFIC
:
2268 bRes
|= ImpGetScientificOutput(fNumber
, nIx
, sBuff
);
2272 OutString
= sBuff
.makeStringAndClear();
2276 bool SvNumberformat::ImpGetScientificOutput(double fNumber
,
2278 OUStringBuffer
& sStr
)
2283 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2284 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
2288 if (nIx
== 0) // Not in the ones at the end
2290 bSign
= true; // Formats
2295 sStr
= ::rtl::math::doubleToUString( fNumber
,
2296 rtl_math_StringFormat_E
,
2297 rInfo
.nCntPre
+ rInfo
.nCntPost
- 1, '.' );
2298 OUStringBuffer ExpStr
;
2300 sal_Int32 nExPos
= sStr
.indexOf('E');
2304 // split into mantisse and exponent and get rid of "E+" or "E-"
2305 sal_Int32 nExpStart
= nExPos
+ 1;
2307 switch ( sStr
[ nExpStart
] )
2316 ExpStr
= sStr
.toString().copy( nExpStart
); // part following the "E+"
2317 sStr
.truncate( nExPos
);
2319 if ( rInfo
.nCntPre
!= 1 ) // rescale Exp
2321 sal_Int32 nExp
= ExpStr
.toString().toInt32() * nExpSign
;
2322 sal_Int32 nRescale
= (rInfo
.nCntPre
!= 0) ? nExp
% (sal_Int32
)rInfo
.nCntPre
: -1;
2323 if( nRescale
< 0 && rInfo
.nCntPre
!= 0 )
2324 nRescale
+= (sal_Int32
)rInfo
.nCntPre
;
2335 ExpStr
= OUString::number( nExp
);
2337 sStr
= ::rtl::math::doubleToUString( fNumber
,
2338 rtl_math_StringFormat_E
,
2339 nRescale
+ rInfo
.nCntPost
, '.' );
2340 sStr
.truncate( sStr
.indexOf('E') );
2343 // cut any decimal delimiter
2344 sal_Int32 index
= 0;
2346 while((index
= sStr
.indexOf('.', index
)) >= 0)
2348 sStr
.remove(index
, 1);
2352 sal_uInt16 j
= nAnz
-1; // Last symbol
2353 sal_Int32 k
; // Position in ExpStr
2354 sal_Int32 nZeros
= 0; // Erase leading zeros
2356 bRes
|= ImpNumberFill(ExpStr
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_EXP
);
2358 while (nZeros
< k
&& ExpStr
[nZeros
] == '0')
2364 ExpStr
.remove( 0, nZeros
);
2369 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_EXP
)
2371 const OUString
& rStr
= rInfo
.sStrArray
[j
];
2374 ExpStr
.insert(0, '-');
2376 else if (rStr
.getLength() > 1 && rStr
[1] == '+')
2378 ExpStr
.insert(0, '+');
2380 ExpStr
.insert(0, rStr
[0]);
2390 // Continure main number:
2397 bRes
|= ImpDecimalFill(sStr
, fNumber
, j
, nIx
, false);
2402 sStr
.insert(0, '-');
2404 sStr
.append(ExpStr
);
2409 bool SvNumberformat::ImpGetFractionOutput(double fNumber
,
2411 OUStringBuffer
& sBuff
)
2414 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2415 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
2416 OUStringBuffer sStr
, sFrac
, sDiv
; // Strings, value for
2417 sal_uLong nFrac
, nDiv
; // Integral part
2418 bool bSign
= false; // Numerator and denominator
2422 if (nIx
== 0) // Not in the ones at the end
2423 bSign
= true; // Formats
2427 double fNum
= floor(fNumber
); // Integral part
2429 fNumber
-= fNum
; // Fractional part
2430 if (fNum
> _D_MAX_U_LONG_
|| rInfo
.nCntExp
> 9) // Too large
2432 sBuff
= rScan
.GetErrorString();
2435 if (rInfo
.nCntExp
== 0)
2437 SAL_WARN( "svl.numbers", "SvNumberformat:: Fraction, nCntExp == 0");
2442 sal_uLong nBasis
= ((sal_uLong
)floor( pow(10.0,rInfo
.nCntExp
))) - 1; // 9, 99, 999 ,...
2443 sal_uLong x0
, y0
, x1
, y1
;
2445 if (rInfo
.nCntExp
<= _MAX_FRACTION_PREC
)
2452 fNumber
-= (fNumber
- 0.5) * 2.0;
2458 // Find entry to Farey sequence:
2459 x0
= (sal_uLong
) floor(fNumber
*nBasis
); // e.g.: 2/9 <= x < 3/9
2460 if (x0
== 0) // => x0 = 2
2466 else if (x0
== (nBasis
-1)/2) // (b-1)/2, 1/2
2467 { // is ok (nBasis is odd)
2474 y0
= nBasis
; // 1/n; 1/(n-1)
2480 y0
= nBasis
; // e.g.: 2/9 2/8
2483 double fUg
= (double) x0
/ (double) y0
;
2484 double fOg
= (double) x1
/ (double) y1
;
2485 sal_uLong nGgt
= ImpGGT(y0
, x0
); // x0/y0 kuerzen
2487 y0
/= nGgt
; // Nest:
2494 // #i21648# GCC over-optimizes something resulting
2495 // in wrong fTest values throughout the loops.
2498 double fTest
= (double)x1
/(double)y1
;
2504 fTest
= (double)x1
/(double)y1
;
2506 while (fTest
< fUg
&& y1
> 1)
2509 fTest
= (double)x1
/(double)y1
;
2521 nGgt
= ImpGGT(y1
, x1
); // Shorten x1/y1
2524 if (x2
*y0
- x0
*y2
== 1 || y1
<= 1) // Test for x2/y2
2525 bStop
= true; // Next Farey number
2538 flow
= (double)x0
/(double)y0
;
2539 fup
= (double)x1
/(double)y1
;
2540 while (fNumber
> fup
)
2542 sal_uLong x2
= ((y0
+nBasis
)/y1
)*x1
- x0
; // Next Farey number
2543 sal_uLong y2
= ((y0
+nBasis
)/y1
)*y1
- y0
;
2550 fup
= (double)x1
/(double)y1
;
2552 if (fNumber
- flow
< fup
- fNumber
)
2562 if (bUpperHalf
) // Recover original
2564 if (nFrac
== 0 && nDiv
== 1) // 1/1
2570 nFrac
= nDiv
- nFrac
;
2574 else // Large denominator
2575 { // 0,1234->123/1000
2579 nFrac
= ((sal_uLong
)floor(0.5 + fNumber
* 10000000.0));
2580 nGgt
= ImpGGT(nDiv
, nFrac
);
2588 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2598 nFrac
= ((sal_uLong
)floor(0.5 + fNumber
*
2599 pow(10.0,rInfo
.nCntExp
)));
2600 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2609 if( sal_Int32 nForcedDiv
= lcl_GetForcedDenominator(NumFor
[nIx
].Info(), nAnz
) )
2611 lcl_ForcedDenominator(nFrac
, nDiv
, nForcedDiv
);
2619 if (rInfo
.nCntPre
== 0) // Improper fraction
2621 double fNum1
= fNum
* (double)nDiv
+ (double)nFrac
;
2623 if (fNum1
> _D_MAX_U_LONG_
)
2625 sBuff
= rScan
.GetErrorString();
2628 nFrac
= (sal_uLong
) floor(fNum1
);
2630 else if (fNum
== 0.0 && nFrac
!= 0)
2636 sprintf( aBuf
, "%.f", fNum
); // simple rounded integer (#100211# - checked)
2637 sStr
.appendAscii( aBuf
);
2638 impTransliterate(sStr
, NumFor
[nIx
].GetNatNum());
2640 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2646 sFrac
= ImpIntToString( nIx
, nFrac
);
2647 sDiv
= ImpIntToString( nIx
, nDiv
);
2650 sal_uInt16 j
= nAnz
-1; // Last symbol -> backwards
2651 sal_Int32 k
; // Denominator
2653 bRes
|= ImpNumberFill(sDiv
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRAC
);
2656 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRAC
)
2658 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2660 sDiv
.insert(0, ' ');
2664 sDiv
.insert(0, rInfo
.sStrArray
[j
][0]);
2675 // Further numerators:
2682 bRes
|= ImpNumberFill(sFrac
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRACBLANK
);
2683 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRACBLANK
)
2685 sFrac
.insert(0, rInfo
.sStrArray
[j
]);
2696 // Continue main number
2703 k
= sStr
.getLength(); // After last figure
2704 bRes
|= ImpNumberFillWithThousands(sStr
, fNumber
, k
, j
, nIx
,
2707 if (bSign
&& !(nFrac
== 0 && fNum
== 0.0))
2709 sBuff
.insert(0, '-'); // Not -0
2712 sBuff
.append(sFrac
);
2717 bool SvNumberformat::ImpGetTimeOutput(double fNumber
,
2719 OUStringBuffer
& sBuff
)
2721 using namespace ::com::sun::star::i18n
;
2722 bool bCalendarSet
= false;
2723 double fNumberOrig
= fNumber
;
2734 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2735 if (rInfo
.bThousand
) // [] format
2737 if (fNumber
> 1.0E10
) // Too large
2739 sBuff
= rScan
.GetErrorString();
2745 fNumber
-= floor(fNumber
); // Else truncate date
2749 if ( rScan
.GetStandardPrec() == 300 &&
2750 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
2751 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2758 nCntPost
= rInfo
.nCntPost
;
2760 if (bSign
&& !rInfo
.bThousand
) // No [] format
2762 fNumber
= 1.0 - fNumber
; // "Inverse"
2764 double fTime
= fNumber
* 86400.0;
2765 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
2766 if (bSign
&& fTime
== 0.0)
2768 bSign
= false; // Not -00:00:00
2770 if( floor( fTime
) > _D_MAX_U_LONG_
)
2772 sBuff
= rScan
.GetErrorString();
2775 sal_uLong nSeconds
= (sal_uLong
)floor( fTime
);
2777 OUStringBuffer
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
2778 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
2779 sSecStr
.stripStart('0');
2780 sSecStr
.stripStart('.');
2783 sSecStr
.stripEnd('0');
2784 for(sal_Int32 index
= sSecStr
.getLength(); index
< rInfo
.nCntPost
; ++index
)
2786 sSecStr
.append('0');
2788 impTransliterate(sSecStr
, NumFor
[nIx
].GetNatNum());
2789 nCntPost
= sSecStr
.getLength();
2793 impTransliterate(sSecStr
, NumFor
[nIx
].GetNatNum());
2796 sal_Int32 nSecPos
= 0; // For figure by figure processing
2797 sal_uLong nHour
, nMin
, nSec
;
2798 if (!rInfo
.bThousand
) // No [] format
2800 nHour
= (nSeconds
/3600) % 24;
2801 nMin
= (nSeconds
%3600) / 60;
2804 else if (rInfo
.nThousand
== 3) // [ss]
2810 else if (rInfo
.nThousand
== 2) // [mm]:ss
2813 nMin
= nSeconds
/ 60;
2814 nSec
= nSeconds
% 60;
2816 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
2818 nHour
= nSeconds
/ 3600;
2819 nMin
= (nSeconds
%3600) / 60;
2824 // TODO What should these be set to?
2830 sal_Unicode cAmPm
= ' '; // a or p
2831 if (rInfo
.nCntExp
) // AM/PM
2838 else if (nHour
< 12)
2851 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
2852 for (sal_uInt16 i
= 0; i
< nAnz
; i
++)
2855 switch (rInfo
.nTypeArray
[i
])
2857 case NF_SYMBOLTYPE_STAR
:
2860 bRes
= lcl_appendStarFillChar( sBuff
, rInfo
.sStrArray
[i
]);
2863 case NF_SYMBOLTYPE_BLANK
:
2864 InsertBlanks(sBuff
, sBuff
.getLength(),
2865 rInfo
.sStrArray
[i
][1] );
2867 case NF_SYMBOLTYPE_STRING
:
2868 case NF_SYMBOLTYPE_CURRENCY
:
2869 case NF_SYMBOLTYPE_DATESEP
:
2870 case NF_SYMBOLTYPE_TIMESEP
:
2871 case NF_SYMBOLTYPE_TIME100SECSEP
:
2872 sBuff
.append(rInfo
.sStrArray
[i
]);
2874 case NF_SYMBOLTYPE_DIGIT
:
2875 nLen
= ( bInputLine
&& i
> 0 &&
2876 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
2877 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
2878 nCntPost
: rInfo
.sStrArray
[i
].getLength() );
2879 for (sal_Int32 j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
2881 sBuff
.append(sSecStr
[nSecPos
]);
2885 case NF_KEY_AMPM
: // AM/PM
2886 if ( !bCalendarSet
)
2888 double fDiff
= DateTime(*(rScan
.GetNullDate())) - GetCal().getEpochStart();
2889 fDiff
+= fNumberOrig
;
2890 GetCal().setLocalDateTime( fDiff
);
2891 bCalendarSet
= true;
2895 sBuff
.append(GetCal().getDisplayName(
2896 CalendarDisplayIndex::AM_PM
, AmPmValue::AM
, 0 ));
2900 sBuff
.append(GetCal().getDisplayName(
2901 CalendarDisplayIndex::AM_PM
, AmPmValue::PM
, 0 ));
2904 case NF_KEY_AP
: // A/P
2914 case NF_KEY_MI
: // M
2915 sBuff
.append(ImpIntToString( nIx
, nMin
));
2917 case NF_KEY_MMI
: // MM
2918 sBuff
.append(ImpIntToString( nIx
, nMin
, 2 ));
2921 sBuff
.append(ImpIntToString( nIx
, nHour
));
2923 case NF_KEY_HH
: // HH
2924 sBuff
.append(ImpIntToString( nIx
, nHour
, 2 ));
2927 sBuff
.append(ImpIntToString( nIx
, nSec
));
2929 case NF_KEY_SS
: // SS
2930 sBuff
.append(ImpIntToString( nIx
, nSec
, 2 ));
2936 if (bSign
&& rInfo
.bThousand
)
2938 sBuff
.insert(0, '-');
2944 /** If a day of month occurs within the format, the month name is in possessive
2945 genitive case if the day follows the month, and partitive case if the day
2946 precedes the month. If there is no day of month the nominative case (noun)
2947 is returned. Also if the month is immediately preceded or followed by a
2948 literal string other than space the nominative name is used, this prevents
2949 duplicated casing for MMMM\t\a and such in documents imported from (e.g.
2950 Finnish) Excel or older LibO/OOo releases.
2953 // IDEA: instead of eCodeType pass the index to nTypeArray and restrict
2954 // inspection of month name around that one, that would enable different month
2955 // cases in one format. Though probably the most rare use case ever..
2957 sal_Int32
SvNumberformat::ImpUseMonthCase( int & io_nState
, const ImpSvNumFor
& rNumFor
, NfKeywordIndex eCodeType
) const
2959 using namespace ::com::sun::star::i18n
;
2962 bool bMonthSeen
= false;
2963 bool bDaySeen
= false;
2964 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
2965 const sal_uInt16 nCount
= rNumFor
.GetCount();
2966 for (sal_uInt16 i
= 0; i
< nCount
&& io_nState
== 0; ++i
)
2969 switch (rInfo
.nTypeArray
[i
])
2985 if ((i
< nCount
-1 &&
2986 rInfo
.nTypeArray
[i
+1] == NF_SYMBOLTYPE_STRING
&&
2987 rInfo
.sStrArray
[i
+1][0] != ' ') ||
2988 (i
> 0 && rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
&&
2989 ((nLen
= rInfo
.sStrArray
[i
-1].getLength()) > 0) &&
2990 rInfo
.sStrArray
[i
-1][nLen
-1] != ' '))
3007 io_nState
= 1; // No day of month
3013 // No day of month or forced nominative
3017 return CalendarDisplayCode::SHORT_MONTH_NAME
;
3019 return CalendarDisplayCode::LONG_MONTH_NAME
;
3021 return CalendarDisplayCode::NARROW_MONTH_NAME
;
3026 // Day of month follows month (the month's 17th)
3030 return CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME
;
3032 return CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME
;
3034 return CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME
;
3039 // Day of month precedes month (17 of month)
3043 return CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME
;
3045 return CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME
;
3047 return CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME
;
3052 SAL_WARN( "svl.numbers", "ImpUseMonthCase: unhandled keyword index eCodeType");
3053 return CalendarDisplayCode::LONG_MONTH_NAME
;
3057 bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor
& rNumFor
) const
3059 if ( GetCal().getUniqueID() != GREGORIAN
)
3063 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
3064 const sal_uInt16 nAnz
= rNumFor
.GetCount();
3066 for ( i
= 0; i
< nAnz
; i
++ )
3068 switch ( rInfo
.nTypeArray
[i
] )
3070 case NF_SYMBOLTYPE_CALENDAR
:
3084 void SvNumberformat::SwitchToOtherCalendar( OUString
& rOrgCalendar
,
3085 double& fOrgDateTime
) const
3087 CalendarWrapper
& rCal
= GetCal();
3088 if ( rCal
.getUniqueID() == GREGORIAN
)
3090 using namespace ::com::sun::star::i18n
;
3091 ::com::sun::star::uno::Sequence
< OUString
> xCals
= rCal
.getAllCalendars(
3092 rLoc().getLanguageTag().getLocale() );
3093 sal_Int32 nCnt
= xCals
.getLength();
3096 for ( sal_Int32 j
=0; j
< nCnt
; j
++ )
3098 if ( xCals
[j
] != GREGORIAN
)
3100 if ( !rOrgCalendar
.getLength() )
3102 rOrgCalendar
= rCal
.getUniqueID();
3103 fOrgDateTime
= rCal
.getDateTime();
3105 rCal
.loadCalendar( xCals
[j
], rLoc().getLanguageTag().getLocale() );
3106 rCal
.setDateTime( fOrgDateTime
);
3114 void SvNumberformat::SwitchToGregorianCalendar( const OUString
& rOrgCalendar
,
3115 double fOrgDateTime
) const
3117 CalendarWrapper
& rCal
= GetCal();
3118 if ( rOrgCalendar
.getLength() && rCal
.getUniqueID() != GREGORIAN
)
3120 rCal
.loadCalendar( GREGORIAN
, rLoc().getLanguageTag().getLocale() );
3121 rCal
.setDateTime( fOrgDateTime
);
3125 bool SvNumberformat::ImpFallBackToGregorianCalendar( OUString
& rOrgCalendar
, double& fOrgDateTime
)
3127 using namespace ::com::sun::star::i18n
;
3128 CalendarWrapper
& rCal
= GetCal();
3129 if ( rCal
.getUniqueID() != GREGORIAN
)
3131 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
3132 if ( nVal
== 0 && rCal
.getLoadedCalendar().Eras
[0].ID
== "Dummy" )
3134 if ( !rOrgCalendar
.getLength() )
3136 rOrgCalendar
= rCal
.getUniqueID();
3137 fOrgDateTime
= rCal
.getDateTime();
3139 else if ( rOrgCalendar
== GREGORIAN
)
3141 rOrgCalendar
.clear();
3143 rCal
.loadCalendar( GREGORIAN
, rLoc().getLanguageTag().getLocale() );
3144 rCal
.setDateTime( fOrgDateTime
);
3153 /* XXX NOTE: even if the ImpSwitchToSpecifiedCalendar method is currently
3154 * unused please don't remove it, it would be needed by
3155 * SwitchToSpecifiedCalendar(), see comment in
3156 * ImpSvNumberInputScan::GetDateRef() */
3158 bool SvNumberformat::ImpSwitchToSpecifiedCalendar( OUString
& rOrgCalendar
,
3159 double& fOrgDateTime
,
3160 const ImpSvNumFor
& rNumFor
) const
3162 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
3163 const sal_uInt16 nAnz
= rNumFor
.GetCount();
3164 for ( sal_uInt16 i
= 0; i
< nAnz
; i
++ )
3166 if ( rInfo
.nTypeArray
[i
] == NF_SYMBOLTYPE_CALENDAR
)
3168 CalendarWrapper
& rCal
= GetCal();
3169 if ( !rOrgCalendar
.getLength() )
3171 rOrgCalendar
= rCal
.getUniqueID();
3172 fOrgDateTime
= rCal
.getDateTime();
3174 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
3175 rCal
.setDateTime( fOrgDateTime
);
3184 void SvNumberformat::ImpAppendEraG( OUStringBuffer
& OutString
,
3185 const CalendarWrapper
& rCal
,
3188 using namespace ::com::sun::star::i18n
;
3189 if ( rCal
.getUniqueID() == "gengou" )
3192 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
3211 OutString
.append(cEra
);
3215 OutString
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_ERA
, nNatNum
));
3219 bool SvNumberformat::ImpIsIso8601( const ImpSvNumFor
& rNumFor
)
3221 bool bIsIso
= false;
3222 if ((eType
& css::util::NumberFormat::DATE
) == css::util::NumberFormat::DATE
)
3233 State eState
= eNone
;
3234 short const * const pType
= rNumFor
.Info().nTypeArray
;
3235 sal_uInt16 nAnz
= rNumFor
.GetCount();
3236 for (sal_uInt16 i
=0; i
< nAnz
&& !bIsIso
&& eState
!= eNotIso
; ++i
)
3240 case NF_KEY_YY
: // two digits not strictly ISO 8601
3242 if (eState
!= eNone
)
3251 case NF_KEY_M
: // single digit not strictly ISO 8601
3253 if (eState
!= eAtSep1
)
3262 case NF_KEY_D
: // single digit not strictly ISO 8601
3264 if (eState
!= eAtSep2
)
3273 case NF_SYMBOLTYPE_STRING
:
3274 case NF_SYMBOLTYPE_DATESEP
:
3275 if (comphelper::string::equals(rNumFor
.Info().sStrArray
[i
], '-'))
3277 if (eState
== eAtYear
)
3281 else if (eState
== eAtMonth
)
3302 SAL_WARN( "svl.numbers", "SvNumberformat::ImpIsIso8601: no date" );
3307 bool SvNumberformat::ImpGetDateOutput(double fNumber
,
3309 OUStringBuffer
& sBuff
)
3311 using namespace ::com::sun::star::i18n
;
3314 CalendarWrapper
& rCal
= GetCal();
3315 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
3317 rCal
.setLocalDateTime( fNumber
);
3318 int nUseMonthCase
= 0; // Not decided yet
3319 OUString aOrgCalendar
; // empty => not changed yet
3321 double fOrgDateTime(0.0);
3322 bool bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
3323 if ( bOtherCalendar
)
3325 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3327 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
3329 bOtherCalendar
= false;
3331 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3332 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
3333 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
3336 for (sal_uInt16 i
= 0; i
< nAnz
; i
++)
3338 switch (rInfo
.nTypeArray
[i
])
3340 case NF_SYMBOLTYPE_CALENDAR
:
3341 if ( !aOrgCalendar
.getLength() )
3343 aOrgCalendar
= rCal
.getUniqueID();
3344 fOrgDateTime
= rCal
.getDateTime();
3346 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLanguageTag().getLocale() );
3347 rCal
.setDateTime( fOrgDateTime
);
3348 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3350 case NF_SYMBOLTYPE_STAR
:
3353 bRes
= lcl_appendStarFillChar( sBuff
, rInfo
.sStrArray
[i
]);
3356 case NF_SYMBOLTYPE_BLANK
:
3357 InsertBlanks( sBuff
, sBuff
.getLength(), rInfo
.sStrArray
[i
][1] );
3359 case NF_SYMBOLTYPE_STRING
:
3360 case NF_SYMBOLTYPE_CURRENCY
:
3361 case NF_SYMBOLTYPE_DATESEP
:
3362 case NF_SYMBOLTYPE_TIMESEP
:
3363 case NF_SYMBOLTYPE_TIME100SECSEP
:
3364 sBuff
.append(rInfo
.sStrArray
[i
]);
3367 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_MONTH
, nNatNum
));
3369 case NF_KEY_MM
: // MM
3370 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_MONTH
, nNatNum
));
3372 case NF_KEY_MMM
: // MMM
3373 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3374 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3377 case NF_KEY_MMMM
: // MMMM
3378 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3379 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3382 case NF_KEY_MMMMM
: // MMMMM
3383 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3384 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3388 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_QUARTER
, nNatNum
));
3390 case NF_KEY_QQ
: // QQ
3391 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_QUARTER
, nNatNum
));
3394 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY
, nNatNum
));
3396 case NF_KEY_DD
: // DD
3397 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY
, nNatNum
));
3399 case NF_KEY_DDD
: // DDD
3400 if ( bOtherCalendar
)
3402 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3404 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
));
3405 if ( bOtherCalendar
)
3407 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3410 case NF_KEY_DDDD
: // DDDD
3411 if ( bOtherCalendar
)
3413 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3415 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3416 if ( bOtherCalendar
)
3418 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3421 case NF_KEY_YY
: // YY
3422 if ( bOtherCalendar
)
3424 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3426 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_YEAR
, nNatNum
));
3427 if ( bOtherCalendar
)
3429 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3432 case NF_KEY_YYYY
: // YYYY
3433 if ( bOtherCalendar
)
3435 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3437 aYear
= rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3438 if (aYear
.getLength() < 4)
3440 using namespace comphelper::string
;
3441 // Ensure that year consists of at least 4 digits, so it
3442 // can be distinguished from 2 digits display and edited
3443 // without suddenly being hit by the 2-digit year magic.
3444 OUStringBuffer aBuf
;
3445 padToLength(aBuf
, 4 - aYear
.getLength(), '0');
3446 impTransliterate(aBuf
, NumFor
[nIx
].GetNatNum());
3452 sBuff
.append(aYear
);
3454 if ( bOtherCalendar
)
3456 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3459 case NF_KEY_EC
: // E
3460 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_YEAR
, nNatNum
));
3462 case NF_KEY_EEC
: // EE
3464 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR
, nNatNum
));
3466 case NF_KEY_NN
: // NN
3467 case NF_KEY_AAA
: // AAA
3468 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
));
3470 case NF_KEY_NNN
: // NNN
3471 case NF_KEY_AAAA
: // AAAA
3472 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3474 case NF_KEY_NNNN
: // NNNN
3475 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3476 sBuff
.append(rLoc().getLongDateDayOfWeekSep());
3478 case NF_KEY_WW
: // WW
3479 sBuff
.append(ImpIntToString( nIx
,
3480 rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
)));
3483 ImpAppendEraG(sBuff
, rCal
, nNatNum
);
3485 case NF_KEY_GG
: // GG
3486 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_ERA
, nNatNum
));
3488 case NF_KEY_GGG
: // GGG
3489 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_ERA
, nNatNum
));
3491 case NF_KEY_RR
: // RR => GGGEE
3492 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
));
3496 if ( aOrgCalendar
.getLength() )
3498 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLanguageTag().getLocale() ); // restore calendar
3503 bool SvNumberformat::ImpGetDateTimeOutput(double fNumber
,
3505 OUStringBuffer
& sBuff
)
3507 using namespace ::com::sun::star::i18n
;
3510 CalendarWrapper
& rCal
= GetCal();
3511 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
3514 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3517 if ( rScan
.GetStandardPrec() == 300 &&
3518 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
3520 // round at 7 decimals (+5 of 86400 == 12 significant digits)
3527 nCntPost
= rInfo
.nCntPost
;
3529 double fTime
= (fNumber
- floor( fNumber
)) * 86400.0;
3530 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
3531 if (fTime
>= 86400.0)
3533 // result of fNumber==x.999999999... rounded up, use correct date/time
3535 fNumber
= floor( fNumber
+ 0.5) + fTime
;
3537 rCal
.setLocalDateTime( fNumber
);
3539 int nUseMonthCase
= 0; // Not decided yet
3540 OUString aOrgCalendar
; // empty => not changed yet
3541 double fOrgDateTime(0.0);
3542 bool bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
3543 if ( bOtherCalendar
)
3545 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3547 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
3549 bOtherCalendar
= false;
3551 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
3553 sal_uLong nSeconds
= (sal_uLong
)floor( fTime
);
3554 OUStringBuffer
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
3555 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
3556 sSecStr
.stripStart('0');
3557 sSecStr
.stripStart('.');
3560 sSecStr
.stripEnd('0');
3561 for(sal_Int32 index
= sSecStr
.getLength(); index
< rInfo
.nCntPost
; ++index
)
3563 sSecStr
.append('0');
3565 impTransliterate(sSecStr
, NumFor
[nIx
].GetNatNum());
3566 nCntPost
= sSecStr
.getLength();
3570 impTransliterate(sSecStr
, NumFor
[nIx
].GetNatNum());
3573 sal_Int32 nSecPos
= 0; // For figure by figure processing
3574 sal_uLong nHour
, nMin
, nSec
;
3575 if (!rInfo
.bThousand
) // [] format
3577 nHour
= (nSeconds
/3600) % 24;
3578 nMin
= (nSeconds
%3600) / 60;
3581 else if (rInfo
.nThousand
== 3) // [ss]
3587 else if (rInfo
.nThousand
== 2) // [mm]:ss
3590 nMin
= nSeconds
/ 60;
3591 nSec
= nSeconds
% 60;
3593 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
3595 nHour
= nSeconds
/ 3600;
3596 nMin
= (nSeconds
%3600) / 60;
3601 nHour
= 0; // TODO What should these values be?
3605 sal_Unicode cAmPm
= ' '; // a or p
3606 if (rInfo
.nCntExp
) // AM/PM
3613 else if (nHour
< 12)
3626 const sal_uInt16 nAnz
= NumFor
[nIx
].GetCount();
3629 for (sal_uInt16 i
= 0; i
< nAnz
; i
++)
3631 switch (rInfo
.nTypeArray
[i
])
3633 case NF_SYMBOLTYPE_CALENDAR
:
3634 if ( !aOrgCalendar
.getLength() )
3636 aOrgCalendar
= rCal
.getUniqueID();
3637 fOrgDateTime
= rCal
.getDateTime();
3639 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLanguageTag().getLocale() );
3640 rCal
.setDateTime( fOrgDateTime
);
3641 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3643 case NF_SYMBOLTYPE_STAR
:
3646 bRes
= lcl_appendStarFillChar( sBuff
, rInfo
.sStrArray
[i
]);
3649 case NF_SYMBOLTYPE_BLANK
:
3650 InsertBlanks( sBuff
, sBuff
.getLength(),
3651 rInfo
.sStrArray
[i
][1] );
3653 case NF_SYMBOLTYPE_STRING
:
3654 case NF_SYMBOLTYPE_CURRENCY
:
3655 case NF_SYMBOLTYPE_DATESEP
:
3656 case NF_SYMBOLTYPE_TIMESEP
:
3657 case NF_SYMBOLTYPE_TIME100SECSEP
:
3658 sBuff
.append(rInfo
.sStrArray
[i
]);
3660 case NF_SYMBOLTYPE_DIGIT
:
3661 nLen
= ( bInputLine
&& i
> 0 &&
3662 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
3663 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
3664 nCntPost
: rInfo
.sStrArray
[i
].getLength() );
3665 for (sal_Int32 j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
3667 sBuff
.append(sSecStr
[ nSecPos
]);
3671 case NF_KEY_AMPM
: // AM/PM
3674 sBuff
.append(rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3675 AmPmValue::AM
, 0 ));
3679 sBuff
.append(rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3680 AmPmValue::PM
, 0 ));
3683 case NF_KEY_AP
: // A/P
3693 case NF_KEY_MI
: // M
3694 sBuff
.append(ImpIntToString( nIx
, nMin
));
3696 case NF_KEY_MMI
: // MM
3697 sBuff
.append(ImpIntToString( nIx
, nMin
, 2 ));
3700 sBuff
.append(ImpIntToString( nIx
, nHour
));
3702 case NF_KEY_HH
: // HH
3703 sBuff
.append(ImpIntToString( nIx
, nHour
, 2 ));
3706 sBuff
.append(ImpIntToString( nIx
, nSec
));
3708 case NF_KEY_SS
: // SS
3709 sBuff
.append(ImpIntToString( nIx
, nSec
, 2 ));
3712 sBuff
.append(rCal
.getDisplayString(
3713 CalendarDisplayCode::SHORT_MONTH
, nNatNum
));
3715 case NF_KEY_MM
: // MM
3716 sBuff
.append(rCal
.getDisplayString(
3717 CalendarDisplayCode::LONG_MONTH
, nNatNum
));
3719 case NF_KEY_MMM
: // MMM
3720 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3721 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3724 case NF_KEY_MMMM
: // MMMM
3725 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3726 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3729 case NF_KEY_MMMMM
: // MMMMM
3730 sBuff
.append(rCal
.getDisplayString( ImpUseMonthCase( nUseMonthCase
, NumFor
[nIx
],
3731 static_cast<NfKeywordIndex
>(rInfo
.nTypeArray
[i
])),
3735 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_QUARTER
, nNatNum
));
3737 case NF_KEY_QQ
: // QQ
3738 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_QUARTER
, nNatNum
));
3741 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY
, nNatNum
));
3743 case NF_KEY_DD
: // DD
3744 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY
, nNatNum
));
3746 case NF_KEY_DDD
: // DDD
3747 if ( bOtherCalendar
)
3749 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3751 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
));
3752 if ( bOtherCalendar
)
3754 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3757 case NF_KEY_DDDD
: // DDDD
3758 if ( bOtherCalendar
)
3760 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3762 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3763 if ( bOtherCalendar
)
3765 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3768 case NF_KEY_YY
: // YY
3769 if ( bOtherCalendar
)
3771 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3773 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_YEAR
, nNatNum
));
3774 if ( bOtherCalendar
)
3776 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3779 case NF_KEY_YYYY
: // YYYY
3780 if ( bOtherCalendar
)
3782 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3784 aYear
= rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3785 if (aYear
.getLength() < 4)
3787 using namespace comphelper::string
;
3788 // Ensure that year consists of at least 4 digits, so it
3789 // can be distinguished from 2 digits display and edited
3790 // without suddenly being hit by the 2-digit year magic.
3791 OUStringBuffer aBuf
;
3792 padToLength(aBuf
, 4 - aYear
.getLength(), '0');
3793 impTransliterate(aBuf
, NumFor
[nIx
].GetNatNum());
3799 sBuff
.append(aYear
);
3801 if ( bOtherCalendar
)
3803 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3806 case NF_KEY_EC
: // E
3807 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_YEAR
, nNatNum
));
3809 case NF_KEY_EEC
: // EE
3811 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR
, nNatNum
));
3813 case NF_KEY_NN
: // NN
3814 case NF_KEY_AAA
: // AAA
3815 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
));
3817 case NF_KEY_NNN
: // NNN
3818 case NF_KEY_AAAA
: // AAAA
3819 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3821 case NF_KEY_NNNN
: // NNNN
3822 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
));
3823 sBuff
.append(rLoc().getLongDateDayOfWeekSep());
3825 case NF_KEY_WW
: // WW
3826 sBuff
.append(ImpIntToString( nIx
, rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
)));
3829 ImpAppendEraG( sBuff
, rCal
, nNatNum
);
3831 case NF_KEY_GG
: // GG
3832 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::SHORT_ERA
, nNatNum
));
3834 case NF_KEY_GGG
: // GGG
3835 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_ERA
, nNatNum
));
3837 case NF_KEY_RR
: // RR => GGGEE
3838 sBuff
.append(rCal
.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
));
3842 if ( aOrgCalendar
.getLength() )
3844 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLanguageTag().getLocale() ); // restore calendar
3849 bool SvNumberformat::ImpGetNumberOutput(double fNumber
,
3851 OUStringBuffer
& sStr
)
3857 if (nIx
== 0) // Not in the ones at the back
3859 bSign
= true; // Formats
3870 if ( ::rtl::math::isSignBitSet( fNumber
) )
3872 fNumber
= -fNumber
; // yes, -0.0 is possible, eliminate '-'
3875 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3876 if (rInfo
.eScannedType
== css::util::NumberFormat::PERCENT
)
3878 if (fNumber
< _D_MAX_D_BY_100
)
3884 sStr
= rScan
.GetErrorString();
3889 bool bInteger
= false;
3890 if ( rInfo
.nThousand
!= FLAG_STANDARD_IN_FORMAT
)
3892 // Special formatting only if no GENERAL keyword in format code
3893 const sal_uInt16 nThousand
= rInfo
.nThousand
;
3895 for (i
= 0; i
< nThousand
; i
++)
3897 if (fNumber
> _D_MIN_M_BY_1000
)
3908 nPrecExp
= GetPrecExp( fNumber
);
3914 if (rInfo
.nCntPost
) // Decimal places
3916 if ((rInfo
.nCntPost
+ nPrecExp
) > 15 && nPrecExp
< 15)
3918 sStr
= ::rtl::math::doubleToUString( fNumber
, rtl_math_StringFormat_F
, 15-nPrecExp
, '.');
3919 for (long l
= 15-nPrecExp
; l
< (long) rInfo
.nCntPost
; l
++)
3926 sStr
= ::rtl::math::doubleToUString( fNumber
, rtl_math_StringFormat_F
, rInfo
.nCntPost
, '.' );
3928 sStr
.stripStart('0'); // Strip leading zeros
3930 else if (fNumber
== 0.0) // Null
3932 // Nothing to be done here, keep empty string sStr,
3933 // ImpNumberFillWithThousands does the rest
3937 sStr
= ::rtl::math::doubleToUString( fNumber
, rtl_math_StringFormat_F
, 0, '.');
3938 sStr
.stripStart('0'); // Strip leading zeros
3940 sal_Int32 nPoint
= sStr
.indexOf('.' );
3943 const sal_Unicode
* p
= sStr
.getStr() + nPoint
;
3944 while ( *++p
== '0' )
3950 sStr
.remove( nPoint
, 1 ); // Remove .
3952 if (bSign
&& (sStr
.isEmpty() ||
3953 comphelper::string::getTokenCount(sStr
.toString(), '0') == sStr
.getLength()+1)) // Only 00000
3955 bSign
= false; // Not -0.00
3957 } // End of != FLAG_STANDARD_IN_FORMAT
3960 j
= NumFor
[nIx
].GetCount()-1; // Last symbol
3962 bRes
|= ImpDecimalFill( sStr
, fNumber
, j
, nIx
, bInteger
);
3965 sStr
.insert(0, '-');
3967 impTransliterate(sStr
, NumFor
[nIx
].GetNatNum());
3971 bool SvNumberformat::ImpDecimalFill( OUStringBuffer
& sStr
, // number string
3972 double& rNumber
, // number
3973 sal_uInt16 j
, // symbol index within format code
3974 sal_uInt16 nIx
, // subformat index
3975 bool bInteger
) // is integer
3978 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3979 sal_Int32 k
= sStr
.getLength(); // After last figure
3981 if (rInfo
.nCntPost
> 0)
3983 bool bTrailing
= true; // Trailing zeros?
3984 bool bFilled
= false; // Was filled?
3986 while (j
> 0 && // Backwards
3987 (nType
= rInfo
.nTypeArray
[j
]) != NF_SYMBOLTYPE_DECSEP
)
3991 case NF_SYMBOLTYPE_STAR
:
3994 bRes
= lcl_insertStarFillChar( sStr
, k
, rInfo
.sStrArray
[j
]);
3997 case NF_SYMBOLTYPE_BLANK
:
3998 if (rInfo
.sStrArray
[j
].getLength() >= 2)
3999 /*k = */ InsertBlanks(sStr
, k
, rInfo
.sStrArray
[j
][1] );
4001 case NF_SYMBOLTYPE_STRING
:
4002 case NF_SYMBOLTYPE_CURRENCY
:
4003 case NF_SYMBOLTYPE_PERCENT
:
4004 sStr
.insert(k
, rInfo
.sStrArray
[j
]);
4006 case NF_SYMBOLTYPE_THSEP
:
4007 if (rInfo
.nThousand
== 0)
4009 sStr
.insert(k
, rInfo
.sStrArray
[j
]);
4012 case NF_SYMBOLTYPE_DIGIT
:
4014 const OUString
& rStr
= rInfo
.sStrArray
[j
];
4015 const sal_Unicode
* p1
= rStr
.getStr();
4016 const sal_Unicode
* p
= p1
+ rStr
.getLength();
4017 while (k
&& p1
< p
--)
4019 const sal_Unicode c
= *p
;
4021 if ( sStr
[k
] != '0' )
4031 else if ( c
== '-' )
4039 else if ( c
== '?' )
4044 else if ( !bFilled
) // #
4052 case NF_KEY_CCC
: // CCC currency
4053 sStr
.insert(k
, rScan
.GetCurAbbrev());
4055 case NF_KEY_GENERAL
: // Standard in the String
4057 OUStringBuffer sNum
;
4058 ImpGetOutputStandard(rNumber
, sNum
);
4059 sNum
.stripStart('-');
4060 sStr
.insert(k
, sNum
.makeStringAndClear());
4068 } // of decimal places
4070 bRes
|= ImpNumberFillWithThousands(sStr
, rNumber
, k
, j
, nIx
, // Fill with . if needed
4072 if ( rInfo
.nCntPost
> 0 )
4074 const OUString
& rDecSep
= GetFormatter().GetNumDecimalSep();
4075 sal_Int32 nLen
= rDecSep
.getLength();
4076 if ( sStr
.getLength() > nLen
&& ( sStr
.indexOf( rDecSep
, sStr
.getLength() - nLen
) == sStr
.getLength() - nLen
) )
4078 sStr
.truncate( sStr
.getLength() - nLen
); // no decimals => strip DecSep
4085 bool SvNumberformat::ImpNumberFillWithThousands( OUStringBuffer
& sBuff
, // number string
4086 double& rNumber
, // number
4087 sal_Int32 k
, // position within string
4088 sal_uInt16 j
, // symbol index within format code
4089 sal_uInt16 nIx
, // subformat index
4090 sal_Int32 nDigCnt
) // count of integer digits in format
4093 sal_Int32 nLeadingStringChars
= 0; // inserted StringChars before number
4094 sal_Int32 nDigitCount
= 0; // count of integer digits from the right
4096 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
4097 // no normal thousands separators if number divided by thousands
4098 bool bDoThousands
= (rInfo
.nThousand
== 0);
4099 utl::DigitGroupingIterator
aGrouping( GetFormatter().GetLocaleData()->getDigitGrouping());
4101 while (!bStop
) // backwards
4107 switch (rInfo
.nTypeArray
[j
])
4109 case NF_SYMBOLTYPE_DECSEP
:
4112 case NF_SYMBOLTYPE_STRING
:
4113 case NF_SYMBOLTYPE_CURRENCY
:
4114 case NF_SYMBOLTYPE_PERCENT
:
4115 sBuff
.insert(k
, rInfo
.sStrArray
[j
]);
4118 nLeadingStringChars
= nLeadingStringChars
+ rInfo
.sStrArray
[j
].getLength();
4121 case NF_SYMBOLTYPE_STAR
:
4124 bRes
= lcl_insertStarFillChar( sBuff
, k
, rInfo
.sStrArray
[j
]);
4127 case NF_SYMBOLTYPE_BLANK
:
4128 if (rInfo
.sStrArray
[j
].getLength() >= 2)
4129 /*k = */ InsertBlanks(sBuff
, k
, rInfo
.sStrArray
[j
][1] );
4131 case NF_SYMBOLTYPE_THSEP
:
4132 // #i7284# #102685# Insert separator also if number is divided
4133 // by thousands and the separator is specified somewhere in
4134 // between and not only at the end.
4135 // #i12596# But do not insert if it's a parenthesized negative
4137 // In fact, do not insert if divided and regex [0#,],[^0#] and
4138 // no other digit symbol follows (which was already detected
4139 // during scan of format code, otherwise there would be no
4140 // division), else do insert. Same in ImpNumberFill() below.
4141 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetCount()-1 )
4143 bDoThousands
= ((j
== 0) ||
4144 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
4145 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
4146 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
4152 sBuff
.insert(k
, rInfo
.sStrArray
[j
]);
4154 else if (nDigitCount
< nDigCnt
)
4156 // Leading '#' displays nothing (e.g. no leading
4157 // separator for numbers <1000 with #,##0 format).
4158 // Leading '?' displays blank.
4159 // Everything else, including nothing, displays the
4161 sal_Unicode cLeader
= 0;
4162 if (j
> 0 && rInfo
.nTypeArray
[j
-1] == NF_SYMBOLTYPE_DIGIT
)
4164 const OUString
& rStr
= rInfo
.sStrArray
[j
-1];
4165 sal_Int32 nLen
= rStr
.getLength();
4168 cLeader
= rStr
[ nLen
- 1 ];
4177 // erAck: 2008-04-03T16:24+0200
4178 // Actually this currently isn't executed
4179 // because the format scanner in the context of
4180 // "?," doesn't generate a group separator but
4181 // a literal ',' character instead that is
4182 // inserted unconditionally. Should be changed
4183 // on some occasion.
4184 sBuff
.insert(k
, ' ');
4187 sBuff
.insert(k
, rInfo
.sStrArray
[j
]);
4190 aGrouping
.advance();
4193 case NF_SYMBOLTYPE_DIGIT
:
4195 const OUString
& rStr
= rInfo
.sStrArray
[j
];
4196 const sal_Unicode
* p1
= rStr
.getStr();
4197 const sal_Unicode
* p
= p1
+ rStr
.getLength();
4210 sBuff
.insert(0, '0');
4213 sBuff
.insert(0, ' ');
4217 if (nDigitCount
== nDigCnt
&& k
> 0)
4219 // more digits than specified
4220 ImpDigitFill(sBuff
, 0, k
, nIx
, nDigitCount
, aGrouping
);
4225 case NF_KEY_CCC
: // CCC currency
4226 sBuff
.insert(k
, rScan
.GetCurAbbrev());
4228 case NF_KEY_GENERAL
: // "General" in string
4230 OUStringBuffer sNum
;
4231 ImpGetOutputStandard(rNumber
, sNum
);
4232 sNum
.stripStart('-');
4233 sBuff
.insert(k
, sNum
.makeStringAndClear());
4239 j
--; // next format code string
4242 k
= k
+ nLeadingStringChars
; // MSC converts += to int and then warns, so ...
4243 if (k
> nLeadingStringChars
)
4245 ImpDigitFill(sBuff
, nLeadingStringChars
, k
, nIx
, nDigitCount
, aGrouping
);
4250 void SvNumberformat::ImpDigitFill(OUStringBuffer
& sStr
, // number string
4251 sal_Int32 nStart
, // start of digits
4252 sal_Int32
& k
, // position within string
4253 sal_uInt16 nIx
, // subformat index
4254 sal_Int32
& nDigitCount
, // count of integer digits from the right so far
4255 utl::DigitGroupingIterator
& rGrouping
) // current grouping
4257 if (NumFor
[nIx
].Info().bThousand
) // Only if grouping fill in separators
4259 const OUString
& rThousandSep
= GetFormatter().GetNumThousandSep();
4262 if (nDigitCount
== rGrouping
.getPos())
4264 sStr
.insert( k
, rThousandSep
);
4265 rGrouping
.advance();
4277 bool SvNumberformat::ImpNumberFill( OUStringBuffer
& sBuff
, // number string
4278 double& rNumber
, // number for "General" format
4279 sal_Int32
& k
, // position within string
4280 sal_uInt16
& j
, // symbol index within format code
4281 sal_uInt16 nIx
, // subformat index
4282 short eSymbolType
) // type of stop condition
4285 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
4286 // no normal thousands separators if number divided by thousands
4287 bool bDoThousands
= (rInfo
.nThousand
== 0);
4290 k
= sBuff
.getLength(); // behind last digit
4292 while (j
> 0 && (nType
= rInfo
.nTypeArray
[j
]) != eSymbolType
) // Backwards
4296 case NF_SYMBOLTYPE_STAR
:
4299 bRes
= lcl_insertStarFillChar( sBuff
, k
, rInfo
.sStrArray
[j
]);
4302 case NF_SYMBOLTYPE_BLANK
:
4303 k
= InsertBlanks(sBuff
, k
, rInfo
.sStrArray
[j
][1] );
4305 case NF_SYMBOLTYPE_THSEP
:
4306 // Same as in ImpNumberFillWithThousands() above, do not insert
4307 // if divided and regex [0#,],[^0#] and no other digit symbol
4308 // follows (which was already detected during scan of format
4309 // code, otherwise there would be no division), else do insert.
4310 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetCount()-1 )
4312 bDoThousands
= ((j
== 0) ||
4313 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
4314 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
4315 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
4317 if ( bDoThousands
&& k
> 0 )
4319 sBuff
.insert(k
, rInfo
.sStrArray
[j
]);
4322 case NF_SYMBOLTYPE_DIGIT
:
4324 const OUString
& rStr
= rInfo
.sStrArray
[j
];
4325 const sal_Unicode
* p1
= rStr
.getStr();
4326 const sal_Unicode
* p
= p1
+ rStr
.getLength();
4338 sBuff
.insert(0, '0');
4341 sBuff
.insert(0, ' ');
4348 case NF_KEY_CCC
: // CCC currency
4349 sBuff
.insert(k
, rScan
.GetCurAbbrev());
4351 case NF_KEY_GENERAL
: // Standard in the String
4353 OUStringBuffer sNum
;
4354 ImpGetOutputStandard(rNumber
, sNum
);
4355 sNum
.stripStart('-');
4356 sBuff
.insert(k
, sNum
.makeStringAndClear());
4359 case NF_SYMBOLTYPE_FRAC_FDIV
: // Do Nothing
4363 sBuff
.insert(k
, rInfo
.sStrArray
[j
]);
4371 void SvNumberformat::GetFormatSpecialInfo(bool& bThousand
,
4373 sal_uInt16
& nPrecision
,
4374 sal_uInt16
& nAnzLeading
) const
4376 // as before: take info from nNumFor=0 for whole format (for dialog etc.)
4379 GetNumForInfo( 0, nDummyType
, bThousand
, nPrecision
, nAnzLeading
);
4381 // "negative in red" is only useful for the whole format
4383 const Color
* pColor
= NumFor
[1].GetColor();
4384 if (fLimit1
== 0.0 && fLimit2
== 0.0 && pColor
4385 && (*pColor
== rScan
.GetRedColor()))
4395 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor
, short& rScannedType
,
4396 bool& bThousand
, sal_uInt16
& nPrecision
, sal_uInt16
& nAnzLeading
) const
4398 // take info from a specified sub-format (for XML export)
4405 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nNumFor
].Info();
4406 rScannedType
= rInfo
.eScannedType
;
4407 bThousand
= rInfo
.bThousand
;
4408 nPrecision
= rInfo
.nCntPost
;
4409 if (bStandard
&& rInfo
.eScannedType
== css::util::NumberFormat::NUMBER
)
4419 const sal_uInt16 nAnz
= NumFor
[nNumFor
].GetCount();
4420 while (!bStop
&& i
< nAnz
)
4422 short nType
= rInfo
.nTypeArray
[i
];
4423 if ( nType
== NF_SYMBOLTYPE_DIGIT
)
4425 const sal_Unicode
* p
= rInfo
.sStrArray
[i
].getStr();
4430 while ( *p
++ == '0' )
4435 else if (nType
== NF_SYMBOLTYPE_DECSEP
|| nType
== NF_SYMBOLTYPE_EXP
)
4444 const OUString
* SvNumberformat::GetNumForString( sal_uInt16 nNumFor
, sal_uInt16 nPos
,
4445 bool bString
/* = false */ ) const
4451 sal_uInt16 nAnz
= NumFor
[nNumFor
].GetCount();
4456 if ( nPos
== 0xFFFF )
4461 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
4462 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
4463 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4468 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4474 else if ( nPos
> nAnz
- 1 )
4481 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
4482 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
4483 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4488 if ( nPos
>= nAnz
|| ((*pType
!= NF_SYMBOLTYPE_STRING
) &&
4489 (*pType
!= NF_SYMBOLTYPE_CURRENCY
)) )
4494 return &NumFor
[nNumFor
].Info().sStrArray
[nPos
];
4497 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor
, sal_uInt16 nPos
,
4498 bool bString
/* = false */ ) const
4504 sal_uInt16 nAnz
= NumFor
[nNumFor
].GetCount();
4509 if ( nPos
== 0xFFFF )
4515 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
4516 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
4517 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4522 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4528 else if ( nPos
> nAnz
- 1 )
4535 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
4536 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
4537 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4542 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
4547 return NumFor
[nNumFor
].Info().nTypeArray
[nPos
];
4550 bool SvNumberformat::IsNegativeWithoutSign() const
4552 if ( IsSecondSubformatRealNegative() )
4554 const OUString
* pStr
= GetNumForString( 1, 0, true );
4557 return !HasStringNegativeSign( *pStr
);
4563 bool SvNumberformat::IsNegativeInBracket() const
4565 sal_uInt16 nAnz
= NumFor
[1].GetCount();
4570 OUString
*tmpStr
= NumFor
[1].Info().sStrArray
;
4571 using comphelper::string::equals
;
4572 return (equals(tmpStr
[0], '(') && equals(tmpStr
[nAnz
-1], ')'));
4575 bool SvNumberformat::HasPositiveBracketPlaceholder() const
4577 sal_uInt16 nAnz
= NumFor
[0].GetCount();
4578 OUString
*tmpStr
= NumFor
[0].Info().sStrArray
;
4579 return tmpStr
[nAnz
-1] == "_)";
4582 DateFormat
SvNumberformat::GetDateOrder() const
4584 if ( (eType
& css::util::NumberFormat::DATE
) == css::util::NumberFormat::DATE
)
4586 short const * const pType
= NumFor
[0].Info().nTypeArray
;
4587 sal_uInt16 nAnz
= NumFor
[0].GetCount();
4588 for ( sal_uInt16 j
=0; j
<nAnz
; j
++ )
4613 SAL_WARN( "svl.numbers", "SvNumberformat::GetDateOrder: no date" );
4615 return rLoc().getDateFormat();
4618 sal_uInt32
SvNumberformat::GetExactDateOrder() const
4620 sal_uInt32 nRet
= 0;
4621 if ( (eType
& css::util::NumberFormat::DATE
) != css::util::NumberFormat::DATE
)
4623 SAL_WARN( "svl.numbers", "SvNumberformat::GetExactDateOrder: no date" );
4626 short const * const pType
= NumFor
[0].Info().nTypeArray
;
4627 sal_uInt16 nAnz
= NumFor
[0].GetCount();
4629 for ( sal_uInt16 j
=0; j
<nAnz
&& nShift
< 3; j
++ )
4635 nRet
= (nRet
<< 8) | 'D';
4643 nRet
= (nRet
<< 8) | 'M';
4652 nRet
= (nRet
<< 8) | 'Y';
4660 void SvNumberformat::GetConditions( SvNumberformatLimitOps
& rOper1
, double& rVal1
,
4661 SvNumberformatLimitOps
& rOper2
, double& rVal2
) const
4669 Color
* SvNumberformat::GetColor( sal_uInt16 nNumFor
) const
4675 return NumFor
[nNumFor
].GetColor();
4678 static void lcl_SvNumberformat_AddLimitStringImpl( OUString
& rStr
,
4679 SvNumberformatLimitOps eOp
,
4680 double fLimit
, const OUString
& rDecSep
)
4682 if ( eOp
!= NUMBERFORMAT_OP_NO
)
4686 case NUMBERFORMAT_OP_EQ
:
4689 case NUMBERFORMAT_OP_NE
:
4692 case NUMBERFORMAT_OP_LT
:
4695 case NUMBERFORMAT_OP_LE
:
4698 case NUMBERFORMAT_OP_GT
:
4701 case NUMBERFORMAT_OP_GE
:
4705 SAL_WARN( "svl.numbers", "unsupported number format" );
4708 rStr
+= ::rtl::math::doubleToUString( fLimit
,
4709 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
4715 OUString
SvNumberformat::GetMappedFormatstring( const NfKeywordTable
& rKeywords
,
4716 const LocaleDataWrapper
& rLocWrp
,
4717 bool bDontQuote
) const
4719 OUStringBuffer aStr
;
4721 // 1 subformat matches all if no condition specified,
4722 bDefault
[0] = ( NumFor
[1].GetCount() == 0 && eOp1
== NUMBERFORMAT_OP_NO
);
4723 // with 2 subformats [>=0];[<0] is implied if no condition specified
4724 bDefault
[1] = ( !bDefault
[0] && NumFor
[2].GetCount() == 0 &&
4725 eOp1
== NUMBERFORMAT_OP_GE
&& fLimit1
== 0.0 &&
4726 eOp2
== NUMBERFORMAT_OP_NO
&& fLimit2
== 0.0 );
4727 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4728 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4729 bDefault
[2] = ( !bDefault
[0] && !bDefault
[1] &&
4730 eOp1
== NUMBERFORMAT_OP_GT
&& fLimit1
== 0.0 &&
4731 eOp2
== NUMBERFORMAT_OP_LT
&& fLimit2
== 0.0 );
4732 bool bDefaults
= bDefault
[0] || bDefault
[1] || bDefault
[2];
4733 // from now on bDefault[] values are used to append empty subformats at the end
4734 bDefault
[3] = false;
4737 // conditions specified
4738 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
== NUMBERFORMAT_OP_NO
)
4740 bDefault
[0] = bDefault
[1] = true; // [];x
4742 else if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
!= NUMBERFORMAT_OP_NO
&&
4743 NumFor
[2].GetCount() == 0 )
4745 bDefault
[0] = bDefault
[1] = bDefault
[2] = bDefault
[3] = true; // [];[];;
4747 // nothing to do if conditions specified for every subformat
4749 else if ( bDefault
[0] )
4751 bDefault
[0] = false; // a single unconditional subformat is never delimited
4755 if ( bDefault
[2] && NumFor
[2].GetCount() == 0 && NumFor
[1].GetCount() > 0 )
4757 bDefault
[3] = true; // special cases x;x;; and ;x;;
4759 for ( int i
=0; i
<3 && !bDefault
[i
]; ++i
)
4764 int nSem
= 0; // needed ';' delimiters
4765 int nSub
= 0; // subformats delimited so far
4766 for ( int n
=0; n
<4; n
++ )
4773 bool LCIDInserted
= false;
4780 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp1
,
4781 fLimit1
, rLocWrp
.getNumDecimalSep() );
4784 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp2
,
4785 fLimit2
, rLocWrp
.getNumDecimalSep() );
4790 const OUString
& rColorName
= NumFor
[n
].GetColorName();
4791 if ( !rColorName
.isEmpty() )
4793 const NfKeywordTable
& rKey
= rScan
.GetKeywords();
4794 for ( int j
= NF_KEY_FIRSTCOLOR
; j
<= NF_KEY_LASTCOLOR
; j
++ )
4796 if ( rKey
[j
] == rColorName
)
4799 aPrefix
+= rKeywords
[j
];
4806 const SvNumberNatNum
& rNum
= NumFor
[n
].GetNatNum();
4808 sal_uInt16 nAnz
= NumFor
[n
].GetCount();
4809 if ( nSem
&& (nAnz
|| !aPrefix
.isEmpty()) )
4811 for ( ; nSem
; --nSem
)
4815 for ( ; nSub
<= n
; ++nSub
)
4817 bDefault
[nSub
] = false;
4821 if ( !aPrefix
.isEmpty() )
4823 aStr
.append( aPrefix
);
4827 const short* pType
= NumFor
[n
].Info().nTypeArray
;
4828 const OUString
* pStr
= NumFor
[n
].Info().sStrArray
;
4829 for ( sal_uInt16 j
=0; j
<nAnz
; j
++ )
4831 if ( 0 <= pType
[j
] && pType
[j
] < NF_KEYWORD_ENTRIES_COUNT
)
4833 aStr
.append( rKeywords
[pType
[j
]] );
4834 if( NF_KEY_NNNN
== pType
[j
] )
4836 aStr
.append( rLocWrp
.getLongDateDayOfWeekSep() );
4843 case NF_SYMBOLTYPE_DECSEP
:
4844 aStr
.append( rLocWrp
.getNumDecimalSep() );
4846 case NF_SYMBOLTYPE_THSEP
:
4847 aStr
.append( rLocWrp
.getNumThousandSep() );
4849 case NF_SYMBOLTYPE_EXP
:
4850 // tdf#95677: Excel does not support exponent without sign
4851 aStr
.append( rKeywords
[NF_KEY_E
] );
4854 case NF_SYMBOLTYPE_DATESEP
:
4855 aStr
.append( rLocWrp
.getDateSep() );
4857 case NF_SYMBOLTYPE_TIMESEP
:
4858 aStr
.append( rLocWrp
.getTimeSep() );
4860 case NF_SYMBOLTYPE_TIME100SECSEP
:
4861 aStr
.append( rLocWrp
.getTime100SecSep() );
4863 case NF_SYMBOLTYPE_STRING
:
4866 aStr
.append( pStr
[j
] );
4868 else if ( pStr
[j
].getLength() == 1 )
4870 aStr
.append( '\\' );
4871 aStr
.append( pStr
[j
] );
4876 aStr
.append( pStr
[j
] );
4880 case NF_SYMBOLTYPE_CALDEL
:
4881 if ( pStr
[j
+1] == "buddhist" )
4883 aStr
.insert( 0, "[$-" );
4884 if ( rNum
.IsSet() && rNum
.GetNatNum() == 1 &&
4885 MsLangId::getRealLanguage( rNum
.GetLang() ) ==
4888 aStr
.insert( 3, "D07041E]" ); // date in Thai digit, Buddhist era
4892 aStr
.insert( 3, "107041E]" ); // date in Arabic digit, Buddhist era
4896 LCIDInserted
= true;
4899 aStr
.append( pStr
[j
] );
4904 // The Thai T NatNum modifier during Xcl export.
4905 if (rNum
.IsSet() && rNum
.GetNatNum() == 1 &&
4906 rKeywords
[NF_KEY_THAI_T
] == "T" &&
4907 MsLangId::getRealLanguage( rNum
.GetLang()) ==
4908 LANGUAGE_THAI
&& !LCIDInserted
)
4911 aStr
.insert( 0, "[$-D00041E]" ); // number in Thai digit
4914 for ( ; nSub
<4 && bDefault
[nSub
]; ++nSub
)
4915 { // append empty subformats
4918 return aStr
.makeStringAndClear();
4921 OUString
SvNumberformat::ImpGetNatNumString( const SvNumberNatNum
& rNum
,
4922 sal_Int32 nVal
, sal_uInt16 nMinDigits
) const
4927 if ( nMinDigits
== 2 )
4929 // speed up the most common case
4930 if ( 0 <= nVal
&& nVal
< 10 )
4932 sal_Unicode aBuf
[2];
4934 aBuf
[1] = '0' + nVal
;
4935 aStr
= OUString(aBuf
, SAL_N_ELEMENTS(aBuf
));
4939 aStr
= OUString::number( nVal
);
4944 OUString
aValStr( OUString::number( nVal
) );
4945 if ( aValStr
.getLength() >= nMinDigits
)
4951 OUStringBuffer aBuf
;
4952 for(sal_Int32 index
= 0; index
< nMinDigits
- aValStr
.getLength(); ++index
)
4956 aBuf
.append(aValStr
);
4957 aStr
= aBuf
.makeStringAndClear();
4963 aStr
= OUString::number( nVal
);
4965 return impTransliterate(aStr
, rNum
);
4968 OUString
SvNumberformat::impTransliterateImpl(const OUString
& rStr
,
4969 const SvNumberNatNum
& rNum
) const
4971 com::sun::star::lang::Locale
aLocale( LanguageTag( rNum
.GetLang() ).getLocale() );
4972 return GetFormatter().GetNatNum()->getNativeNumberString( rStr
,
4973 aLocale
, rNum
.GetNatNum() );
4976 void SvNumberformat::impTransliterateImpl(OUStringBuffer
& rStr
,
4977 const SvNumberNatNum
& rNum
) const
4979 com::sun::star::lang::Locale
aLocale( LanguageTag( rNum
.GetLang() ).getLocale() );
4981 OUString
sTemp(rStr
.makeStringAndClear());
4982 sTemp
= GetFormatter().GetNatNum()->getNativeNumberString( sTemp
, aLocale
, rNum
.GetNatNum() );
4986 void SvNumberformat::GetNatNumXml( com::sun::star::i18n::NativeNumberXmlAttributes
& rAttr
,
4987 sal_uInt16 nNumFor
) const
4991 const SvNumberNatNum
& rNum
= NumFor
[nNumFor
].GetNatNum();
4994 com::sun::star::lang::Locale
aLocale(
4995 LanguageTag( rNum
.GetLang() ).getLocale() );
4996 rAttr
= GetFormatter().GetNatNum()->convertToXmlAttributes(
4997 aLocale
, rNum
.GetNatNum() );
5001 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
5006 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
5011 bool SvNumberformat::HasStringNegativeSign( const OUString
& rStr
)
5013 // For Sign '-' needs to be at the start or at the end of the string (blanks ignored)
5014 sal_Int32 nLen
= rStr
.getLength();
5019 const sal_Unicode
* const pBeg
= rStr
.getStr();
5020 const sal_Unicode
* const pEnd
= pBeg
+ nLen
;
5021 const sal_Unicode
* p
= pBeg
;
5029 while ( *p
== ' ' && ++p
< pEnd
);
5040 while ( *p
== ' ' && pBeg
< --p
);
5045 bool SvNumberformat::IsInQuote( const OUString
& rStr
, sal_Int32 nPos
,
5046 sal_Unicode cQuote
, sal_Unicode cEscIn
, sal_Unicode cEscOut
)
5048 sal_Int32 nLen
= rStr
.getLength();
5053 const sal_Unicode
* p0
= rStr
.getStr();
5054 const sal_Unicode
* p
= p0
;
5055 const sal_Unicode
* p1
= p0
+ nPos
;
5056 bool bQuoted
= false;
5067 if ( *(p
-1) != cEscIn
)
5074 if ( *(p
-1) != cEscOut
)
5086 sal_Int32
SvNumberformat::GetQuoteEnd( const OUString
& rStr
, sal_Int32 nPos
,
5087 sal_Unicode cQuote
, sal_Unicode cEscIn
,
5088 sal_Unicode cEscOut
)
5094 sal_Int32 nLen
= rStr
.getLength();
5099 if ( !IsInQuote( rStr
, nPos
, cQuote
, cEscIn
, cEscOut
) )
5101 if ( rStr
[ nPos
] == cQuote
)
5103 return nPos
; // Closing cQuote
5107 const sal_Unicode
* p0
= rStr
.getStr();
5108 const sal_Unicode
* p
= p0
+ nPos
;
5109 const sal_Unicode
* p1
= p0
+ nLen
;
5112 if ( *p
== cQuote
&& p
> p0
&& *(p
-1) != cEscIn
)
5114 return sal::static_int_cast
< sal_Int32
>(p
- p0
);
5118 return nLen
; // End of String
5121 sal_uInt16
SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor
) const
5123 sal_uInt16 nCnt
= 0;
5124 sal_uInt16 nAnz
= NumFor
[nNumFor
].GetCount();
5125 short const * const pType
= NumFor
[nNumFor
].Info().nTypeArray
;
5126 for ( sal_uInt16 j
=0; j
<nAnz
; ++j
)
5130 case NF_SYMBOLTYPE_STRING
:
5131 case NF_SYMBOLTYPE_CURRENCY
:
5132 case NF_SYMBOLTYPE_DATESEP
:
5133 case NF_SYMBOLTYPE_TIMESEP
:
5134 case NF_SYMBOLTYPE_TIME100SECSEP
:
5135 case NF_SYMBOLTYPE_PERCENT
:
5143 const CharClass
& SvNumberformat::rChrCls() const
5145 return rScan
.GetChrCls();
5148 const LocaleDataWrapper
& SvNumberformat::rLoc() const
5150 return rScan
.GetLoc();
5153 CalendarWrapper
& SvNumberformat::GetCal() const
5155 return rScan
.GetCal();
5158 const SvNumberFormatter
& SvNumberformat::GetFormatter() const
5160 return *rScan
.GetNumberformatter();
5163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */