1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: zformat.cxx,v $
10 * $Revision: 1.78.138.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
39 #include <tools/debug.hxx>
40 #include <i18npool/mslangid.hxx>
41 #include <rtl/math.hxx>
42 #include <rtl/instance.hxx>
43 #include <unotools/charclass.hxx>
44 #include <unotools/calendarwrapper.hxx>
45 #include <unotools/nativenumberwrapper.hxx>
46 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
47 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
48 #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
49 #include <com/sun/star/i18n/AmPmValue.hpp>
52 #include <svtools/zformat.hxx>
53 #include "zforscan.hxx"
55 #include "zforfind.hxx"
56 #include <svtools/zforlist.hxx>
57 #include "numhead.hxx"
58 #include <unotools/digitgroupingiterator.hxx>
59 #include "nfsymbol.hxx"
64 : public rtl::StaticWithInit
<const ::rtl::OUString
, Gregorian
> {
65 const ::rtl::OUString
operator () () {
66 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
71 const double _D_MAX_U_LONG_
= (double) 0xffffffff; // 4294967295.0
72 const double _D_MAX_LONG_
= (double) 0x7fffffff; // 2147483647.0
73 const USHORT _MAX_FRACTION_PREC
= 3;
74 const double D_EPS
= 1.0E-2;
76 const double _D_MAX_D_BY_100
= 1.7E306
;
77 const double _D_MIN_M_BY_1000
= 2.3E-305;
79 static BYTE cCharWidths
[ 128-32 ] = {
80 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
81 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
82 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
83 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
84 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
85 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
89 xub_StrLen
SvNumberformat::InsertBlanks( String
& r
, xub_StrLen nPos
, sal_Unicode c
)
93 USHORT n
= 2; // Default fuer Zeichen > 128 (HACK!)
95 n
= cCharWidths
[ c
- 32 ];
97 r
.Insert( ' ', nPos
++ );
102 static long GetPrecExp( double fAbsVal
)
104 DBG_ASSERT( fAbsVal
> 0.0, "GetPrecExp: fAbsVal <= 0.0" );
105 if ( fAbsVal
< 1e-7 || fAbsVal
> 1e7
)
106 { // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7
107 return (long) floor( log10( fAbsVal
) ) + 1;
117 while( fAbsVal
>= 10 )
126 const USHORT nNewCurrencyVersionId
= 0x434E; // "NC"
127 const sal_Unicode cNewCurrencyMagic
= 0x01; // Magic for format code in comment
128 const USHORT nNewStandardFlagVersionId
= 0x4653; // "SF"
130 /***********************Funktion SvNumberformatInfo******************************/
132 void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo
& rNumFor
, USHORT nAnz
)
134 for (USHORT i
= 0; i
< nAnz
; i
++)
136 sStrArray
[i
] = rNumFor
.sStrArray
[i
];
137 nTypeArray
[i
] = rNumFor
.nTypeArray
[i
];
139 eScannedType
= rNumFor
.eScannedType
;
140 bThousand
= rNumFor
.bThousand
;
141 nThousand
= rNumFor
.nThousand
;
142 nCntPre
= rNumFor
.nCntPre
;
143 nCntPost
= rNumFor
.nCntPost
;
144 nCntExp
= rNumFor
.nCntExp
;
147 void ImpSvNumberformatInfo::Save(SvStream
& rStream
, USHORT nAnz
) const
149 for (USHORT i
= 0; i
< nAnz
; i
++)
151 rStream
.WriteByteString( sStrArray
[i
], rStream
.GetStreamCharSet() );
152 short nType
= nTypeArray
[i
];
154 { // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR
155 case NF_SYMBOLTYPE_CURRENCY
:
156 rStream
<< short( NF_SYMBOLTYPE_STRING
);
158 case NF_SYMBOLTYPE_CURRDEL
:
159 case NF_SYMBOLTYPE_CURREXT
:
160 rStream
<< short(0); // werden ignoriert (hoffentlich..)
163 if ( nType
> NF_KEY_LASTKEYWORD_SO5
)
164 rStream
<< short( NF_SYMBOLTYPE_STRING
); // all new keywords are string
170 rStream
<< eScannedType
<< bThousand
<< nThousand
171 << nCntPre
<< nCntPost
<< nCntExp
;
174 void ImpSvNumberformatInfo::Load(SvStream
& rStream
, USHORT nAnz
)
176 for (USHORT i
= 0; i
< nAnz
; i
++)
178 SvNumberformat::LoadString( rStream
, sStrArray
[i
] );
179 rStream
>> nTypeArray
[i
];
181 rStream
>> eScannedType
>> bThousand
>> nThousand
182 >> nCntPre
>> nCntPost
>> nCntExp
;
186 //============================================================================
189 BYTE
SvNumberNatNum::MapDBNumToNatNum( BYTE nDBNum
, LanguageType eLang
, BOOL bDate
)
192 eLang
= MsLangId::getRealLanguage( eLang
); // resolve SYSTEM etc.
193 eLang
&= 0x03FF; // 10 bit primary language
196 if ( nDBNum
== 4 && eLang
== LANGUAGE_KOREAN
)
198 else if ( nDBNum
<= 3 )
199 nNatNum
= nDBNum
; // known to be good for: zh,ja,ko / 1,2,3
208 case (LANGUAGE_CHINESE
& 0x03FF) : nNatNum
= 4; break;
209 case (LANGUAGE_JAPANESE
& 0x03FF) : nNatNum
= 1; break;
210 case (LANGUAGE_KOREAN
& 0x03FF) : nNatNum
= 1; break;
216 case (LANGUAGE_CHINESE
& 0x03FF) : nNatNum
= 5; break;
217 case (LANGUAGE_JAPANESE
& 0x03FF) : nNatNum
= 4; break;
218 case (LANGUAGE_KOREAN
& 0x03FF) : nNatNum
= 2; break;
224 case (LANGUAGE_CHINESE
& 0x03FF) : nNatNum
= 6; break;
225 case (LANGUAGE_JAPANESE
& 0x03FF) : nNatNum
= 5; break;
226 case (LANGUAGE_KOREAN
& 0x03FF) : nNatNum
= 3; break;
232 case (LANGUAGE_JAPANESE
& 0x03FF) : nNatNum
= 7; break;
233 case (LANGUAGE_KOREAN
& 0x03FF) : nNatNum
= 9; break;
243 BYTE
SvNumberNatNum::MapNatNumToDBNum( BYTE nNatNum
, LanguageType eLang
, BOOL bDate
)
246 eLang
= MsLangId::getRealLanguage( eLang
); // resolve SYSTEM etc.
247 eLang
&= 0x03FF; // 10 bit primary language
250 if ( nNatNum
== 9 && eLang
== LANGUAGE_KOREAN
)
252 else if ( nNatNum
<= 3 )
253 nDBNum
= nNatNum
; // known to be good for: zh,ja,ko / 1,2,3
262 case (LANGUAGE_JAPANESE
& 0x03FF) : nDBNum
= 1; break;
263 case (LANGUAGE_KOREAN
& 0x03FF) : nDBNum
= 1; break;
269 case (LANGUAGE_KOREAN
& 0x03FF) : nDBNum
= 2; break;
275 case (LANGUAGE_KOREAN
& 0x03FF) : nDBNum
= 3; break;
281 case (LANGUAGE_CHINESE
& 0x03FF) : nDBNum
= 1; break;
282 case (LANGUAGE_JAPANESE
& 0x03FF) : nDBNum
= 2; break;
288 case (LANGUAGE_CHINESE
& 0x03FF) : nDBNum
= 2; break;
289 case (LANGUAGE_JAPANESE
& 0x03FF) : nDBNum
= 3; break;
295 case (LANGUAGE_CHINESE
& 0x03FF) : nDBNum
= 3; break;
301 case (LANGUAGE_JAPANESE
& 0x03FF) : nDBNum
= 4; break;
309 case (LANGUAGE_KOREAN
& 0x03FF) : nDBNum
= 4; break;
321 /***********************Funktionen SvNumFor******************************/
323 ImpSvNumFor::ImpSvNumFor()
326 aI
.nTypeArray
= NULL
;
328 aI
.eScannedType
= NUMBERFORMAT_UNDEFINED
;
329 aI
.bThousand
= FALSE
;
337 ImpSvNumFor::~ImpSvNumFor()
339 for (USHORT i
= 0; i
< nAnzStrings
; i
++)
340 aI
.sStrArray
[i
].Erase();
341 delete [] aI
.sStrArray
;
342 delete [] aI
.nTypeArray
;
345 void ImpSvNumFor::Enlarge(USHORT nAnz
)
347 if ( nAnzStrings
!= nAnz
)
350 delete [] aI
.nTypeArray
;
352 delete [] aI
.sStrArray
;
356 aI
.nTypeArray
= new short[nAnz
];
357 aI
.sStrArray
= new String
[nAnz
];
361 aI
.nTypeArray
= NULL
;
367 void ImpSvNumFor::Copy( const ImpSvNumFor
& rNumFor
, ImpSvNumberformatScan
* pSc
)
369 Enlarge( rNumFor
.nAnzStrings
);
370 aI
.Copy( rNumFor
.aI
, nAnzStrings
);
371 sColorName
= rNumFor
.sColorName
;
373 pColor
= pSc
->GetColor( sColorName
); // #121103# don't copy pointer between documents
375 pColor
= rNumFor
.pColor
;
376 aNatNum
= rNumFor
.aNatNum
;
379 void ImpSvNumFor::Save(SvStream
& rStream
) const
381 rStream
<< nAnzStrings
;
382 aI
.Save(rStream
, nAnzStrings
);
383 rStream
.WriteByteString( sColorName
, rStream
.GetStreamCharSet() );
386 void ImpSvNumFor::Load(SvStream
& rStream
, ImpSvNumberformatScan
& rSc
,
387 String
& rLoadedColorName
)
390 rStream
>> nAnz
; //! noch nicht direkt nAnzStrings wg. Enlarge
392 aI
.Load( rStream
, nAnz
);
393 rStream
.ReadByteString( sColorName
, rStream
.GetStreamCharSet() );
394 rLoadedColorName
= sColorName
;
395 pColor
= rSc
.GetColor(sColorName
);
399 BOOL
ImpSvNumFor::HasNewCurrency() const
401 for ( USHORT j
=0; j
<nAnzStrings
; j
++ )
403 if ( aI
.nTypeArray
[j
] == NF_SYMBOLTYPE_CURRENCY
)
410 BOOL
ImpSvNumFor::GetNewCurrencySymbol( String
& rSymbol
,
411 String
& rExtension
) const
413 for ( USHORT j
=0; j
<nAnzStrings
; j
++ )
415 if ( aI
.nTypeArray
[j
] == NF_SYMBOLTYPE_CURRENCY
)
417 rSymbol
= aI
.sStrArray
[j
];
418 if ( j
< nAnzStrings
-1 && aI
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_CURREXT
)
419 rExtension
= aI
.sStrArray
[j
+1];
425 //! kein Erase an rSymbol, rExtension
430 void ImpSvNumFor::SaveNewCurrencyMap( SvStream
& rStream
) const
434 for ( j
=0; j
<nAnzStrings
; j
++ )
436 switch ( aI
.nTypeArray
[j
] )
438 case NF_SYMBOLTYPE_CURRENCY
:
439 case NF_SYMBOLTYPE_CURRDEL
:
440 case NF_SYMBOLTYPE_CURREXT
:
446 for ( j
=0; j
<nAnzStrings
; j
++ )
448 switch ( aI
.nTypeArray
[j
] )
450 case NF_SYMBOLTYPE_CURRENCY
:
451 case NF_SYMBOLTYPE_CURRDEL
:
452 case NF_SYMBOLTYPE_CURREXT
:
453 rStream
<< j
<< aI
.nTypeArray
[j
];
460 void ImpSvNumFor::LoadNewCurrencyMap( SvStream
& rStream
)
464 for ( USHORT j
=0; j
<nCnt
; j
++ )
468 rStream
>> nPos
>> nType
;
469 if ( nPos
< nAnzStrings
)
470 aI
.nTypeArray
[nPos
] = nType
;
475 /***********************Funktionen SvNumberformat************************/
477 enum BracketFormatSymbolType
479 BRACKET_SYMBOLTYPE_FORMAT
= -1, // subformat string
480 BRACKET_SYMBOLTYPE_COLOR
= -2, // color
481 BRACKET_SYMBOLTYPE_ERROR
= -3, // error
482 BRACKET_SYMBOLTYPE_DBNUM1
= -4, // DoubleByteNumber, represent numbers
483 BRACKET_SYMBOLTYPE_DBNUM2
= -5, // using CJK characters, Excel compatible.
484 BRACKET_SYMBOLTYPE_DBNUM3
= -6,
485 BRACKET_SYMBOLTYPE_DBNUM4
= -7,
486 BRACKET_SYMBOLTYPE_DBNUM5
= -8,
487 BRACKET_SYMBOLTYPE_DBNUM6
= -9,
488 BRACKET_SYMBOLTYPE_DBNUM7
= -10,
489 BRACKET_SYMBOLTYPE_DBNUM8
= -11,
490 BRACKET_SYMBOLTYPE_DBNUM9
= -12,
491 BRACKET_SYMBOLTYPE_LOCALE
= -13,
492 BRACKET_SYMBOLTYPE_NATNUM0
= -14, // Our NativeNumber support, ASCII
493 BRACKET_SYMBOLTYPE_NATNUM1
= -15, // Our NativeNumber support, represent
494 BRACKET_SYMBOLTYPE_NATNUM2
= -16, // numbers using CJK, CTL, ...
495 BRACKET_SYMBOLTYPE_NATNUM3
= -17,
496 BRACKET_SYMBOLTYPE_NATNUM4
= -18,
497 BRACKET_SYMBOLTYPE_NATNUM5
= -19,
498 BRACKET_SYMBOLTYPE_NATNUM6
= -20,
499 BRACKET_SYMBOLTYPE_NATNUM7
= -21,
500 BRACKET_SYMBOLTYPE_NATNUM8
= -22,
501 BRACKET_SYMBOLTYPE_NATNUM9
= -23,
502 BRACKET_SYMBOLTYPE_NATNUM10
= -24,
503 BRACKET_SYMBOLTYPE_NATNUM11
= -25,
504 BRACKET_SYMBOLTYPE_NATNUM12
= -26,
505 BRACKET_SYMBOLTYPE_NATNUM13
= -27,
506 BRACKET_SYMBOLTYPE_NATNUM14
= -28,
507 BRACKET_SYMBOLTYPE_NATNUM15
= -29,
508 BRACKET_SYMBOLTYPE_NATNUM16
= -30,
509 BRACKET_SYMBOLTYPE_NATNUM17
= -31,
510 BRACKET_SYMBOLTYPE_NATNUM18
= -32,
511 BRACKET_SYMBOLTYPE_NATNUM19
= -33
514 SvNumberformat::SvNumberformat( ImpSvNumberformatScan
& rSc
, LanguageType eLge
)
518 nNewStandardDefined(0),
523 void SvNumberformat::ImpCopyNumberformat( const SvNumberformat
& rFormat
)
525 sFormatstring
= rFormat
.sFormatstring
;
526 eType
= rFormat
.eType
;
527 eLnge
= rFormat
.eLnge
;
528 fLimit1
= rFormat
.fLimit1
;
529 fLimit2
= rFormat
.fLimit2
;
532 bStandard
= rFormat
.bStandard
;
533 bIsUsed
= rFormat
.bIsUsed
;
534 sComment
= rFormat
.sComment
;
535 nNewStandardDefined
= rFormat
.nNewStandardDefined
;
537 // #121103# when copying between documents, get color pointers from own scanner
538 ImpSvNumberformatScan
* pColorSc
= ( &rScan
!= &rFormat
.rScan
) ? &rScan
: NULL
;
540 for (USHORT i
= 0; i
< 4; i
++)
541 NumFor
[i
].Copy(rFormat
.NumFor
[i
], pColorSc
);
544 SvNumberformat::SvNumberformat( SvNumberformat
& rFormat
)
545 : rScan(rFormat
.rScan
), bStarFlag( rFormat
.bStarFlag
)
547 ImpCopyNumberformat( rFormat
);
550 SvNumberformat::SvNumberformat( SvNumberformat
& rFormat
, ImpSvNumberformatScan
& rSc
)
551 : rScan(rSc
), bStarFlag( rFormat
.bStarFlag
)
553 ImpCopyNumberformat( rFormat
);
557 BOOL
lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType
)
559 if ( nSymbolType
> 0 )
560 return TRUE
; // conditions
561 switch ( nSymbolType
)
563 case BRACKET_SYMBOLTYPE_COLOR
:
564 case BRACKET_SYMBOLTYPE_DBNUM1
:
565 case BRACKET_SYMBOLTYPE_DBNUM2
:
566 case BRACKET_SYMBOLTYPE_DBNUM3
:
567 case BRACKET_SYMBOLTYPE_DBNUM4
:
568 case BRACKET_SYMBOLTYPE_DBNUM5
:
569 case BRACKET_SYMBOLTYPE_DBNUM6
:
570 case BRACKET_SYMBOLTYPE_DBNUM7
:
571 case BRACKET_SYMBOLTYPE_DBNUM8
:
572 case BRACKET_SYMBOLTYPE_DBNUM9
:
573 case BRACKET_SYMBOLTYPE_LOCALE
:
574 case BRACKET_SYMBOLTYPE_NATNUM0
:
575 case BRACKET_SYMBOLTYPE_NATNUM1
:
576 case BRACKET_SYMBOLTYPE_NATNUM2
:
577 case BRACKET_SYMBOLTYPE_NATNUM3
:
578 case BRACKET_SYMBOLTYPE_NATNUM4
:
579 case BRACKET_SYMBOLTYPE_NATNUM5
:
580 case BRACKET_SYMBOLTYPE_NATNUM6
:
581 case BRACKET_SYMBOLTYPE_NATNUM7
:
582 case BRACKET_SYMBOLTYPE_NATNUM8
:
583 case BRACKET_SYMBOLTYPE_NATNUM9
:
584 case BRACKET_SYMBOLTYPE_NATNUM10
:
585 case BRACKET_SYMBOLTYPE_NATNUM11
:
586 case BRACKET_SYMBOLTYPE_NATNUM12
:
587 case BRACKET_SYMBOLTYPE_NATNUM13
:
588 case BRACKET_SYMBOLTYPE_NATNUM14
:
589 case BRACKET_SYMBOLTYPE_NATNUM15
:
590 case BRACKET_SYMBOLTYPE_NATNUM16
:
591 case BRACKET_SYMBOLTYPE_NATNUM17
:
592 case BRACKET_SYMBOLTYPE_NATNUM18
:
593 case BRACKET_SYMBOLTYPE_NATNUM19
:
600 SvNumberformat::SvNumberformat(String
& rString
,
601 ImpSvNumberformatScan
* pSc
,
602 ImpSvNumberInputScan
* pISc
,
603 xub_StrLen
& nCheckPos
,
608 nNewStandardDefined(0),
611 // If the group (AKA thousand) separator is a Non-Breaking Space (French)
612 // replace all occurences by a simple space.
613 // The tokens will be changed to the LocaleData separator again later on.
614 const sal_Unicode cNBSp
= 0xA0;
615 const String
& rThSep
= GetFormatter().GetNumThousandSep();
616 if ( rThSep
.GetChar(0) == cNBSp
&& rThSep
.Len() == 1 )
618 xub_StrLen nIndex
= 0;
620 nIndex
= rString
.SearchAndReplace( cNBSp
, ' ', nIndex
);
621 while ( nIndex
!= STRING_NOTFOUND
);
624 if (rScan
.GetConvertMode())
626 eLnge
= rScan
.GetNewLnge();
627 eLan
= eLnge
; // Wechsel auch zurueckgeben
635 eOp1
= NUMBERFORMAT_OP_NO
;
636 eOp2
= NUMBERFORMAT_OP_NO
;
637 eType
= NUMBERFORMAT_DEFINED
;
639 BOOL bCancel
= FALSE
;
640 BOOL bCondition
= FALSE
;
647 // Split into 4 sub formats
649 for ( nIndex
= 0; nIndex
< 4 && !bCancel
; nIndex
++ )
651 // Original language/country may have to be reestablished
652 if (rScan
.GetConvertMode())
653 (rScan
.GetNumberformatter())->ChangeIntl(rScan
.GetTmpLnge());
656 nPosOld
= nPos
; // Start position of substring
657 // first get bracketed prefixes; e.g. conditions, color
660 eSymbolType
= ImpNextSymbol(rString
, nPos
, sStr
);
661 if (eSymbolType
> 0) // condition
663 if ( nIndex
== 0 && !bCondition
)
666 eOp1
= (SvNumberformatLimitOps
) eSymbolType
;
668 else if ( nIndex
== 1 && bCondition
)
669 eOp2
= (SvNumberformatLimitOps
) eSymbolType
;
672 bCancel
= TRUE
; // break for
678 xub_StrLen nAnzChars
= ImpGetNumber(rString
, nPos
, sStr
);
682 if (!pISc
->IsNumberFormat(sStr
,F_Type
,fNumber
) ||
683 ( F_Type
!= NUMBERFORMAT_NUMBER
&&
684 F_Type
!= NUMBERFORMAT_SCIENTIFIC
) )
687 nPos
= nPos
- nAnzChars
;
688 rString
.Erase(nPos
, nAnzChars
);
689 rString
.Insert('0',nPos
);
696 rString
.Insert('0',nPos
++);
702 if ( rString
.GetChar(nPos
) == ']' )
706 bCancel
= TRUE
; // break for
710 nPosOld
= nPos
; // position before string
712 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) )
714 switch ( eSymbolType
)
716 case BRACKET_SYMBOLTYPE_COLOR
:
718 if ( NumFor
[nIndex
].GetColor() != NULL
)
719 { // error, more than one color
720 bCancel
= TRUE
; // break for
725 Color
* pColor
= pSc
->GetColor( sStr
);
726 NumFor
[nIndex
].SetColor( pColor
, sStr
);
729 bCancel
= TRUE
; // break for
735 case BRACKET_SYMBOLTYPE_NATNUM0
:
736 case BRACKET_SYMBOLTYPE_NATNUM1
:
737 case BRACKET_SYMBOLTYPE_NATNUM2
:
738 case BRACKET_SYMBOLTYPE_NATNUM3
:
739 case BRACKET_SYMBOLTYPE_NATNUM4
:
740 case BRACKET_SYMBOLTYPE_NATNUM5
:
741 case BRACKET_SYMBOLTYPE_NATNUM6
:
742 case BRACKET_SYMBOLTYPE_NATNUM7
:
743 case BRACKET_SYMBOLTYPE_NATNUM8
:
744 case BRACKET_SYMBOLTYPE_NATNUM9
:
745 case BRACKET_SYMBOLTYPE_NATNUM10
:
746 case BRACKET_SYMBOLTYPE_NATNUM11
:
747 case BRACKET_SYMBOLTYPE_NATNUM12
:
748 case BRACKET_SYMBOLTYPE_NATNUM13
:
749 case BRACKET_SYMBOLTYPE_NATNUM14
:
750 case BRACKET_SYMBOLTYPE_NATNUM15
:
751 case BRACKET_SYMBOLTYPE_NATNUM16
:
752 case BRACKET_SYMBOLTYPE_NATNUM17
:
753 case BRACKET_SYMBOLTYPE_NATNUM18
:
754 case BRACKET_SYMBOLTYPE_NATNUM19
:
756 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
758 bCancel
= TRUE
; // break for
763 sStr
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) );
764 //! eSymbolType is negative
765 BYTE nNum
= sal::static_int_cast
< BYTE
>(0 - (eSymbolType
- BRACKET_SYMBOLTYPE_NATNUM0
));
766 sStr
+= String::CreateFromInt32( nNum
);
767 NumFor
[nIndex
].SetNatNumNum( nNum
, FALSE
);
771 case BRACKET_SYMBOLTYPE_DBNUM1
:
772 case BRACKET_SYMBOLTYPE_DBNUM2
:
773 case BRACKET_SYMBOLTYPE_DBNUM3
:
774 case BRACKET_SYMBOLTYPE_DBNUM4
:
775 case BRACKET_SYMBOLTYPE_DBNUM5
:
776 case BRACKET_SYMBOLTYPE_DBNUM6
:
777 case BRACKET_SYMBOLTYPE_DBNUM7
:
778 case BRACKET_SYMBOLTYPE_DBNUM8
:
779 case BRACKET_SYMBOLTYPE_DBNUM9
:
781 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
783 bCancel
= TRUE
; // break for
788 sStr
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) );
789 //! eSymbolType is negative
790 BYTE nNum
= sal::static_int_cast
< BYTE
>(1 - (eSymbolType
- BRACKET_SYMBOLTYPE_DBNUM1
));
791 sStr
+= static_cast< sal_Unicode
>('0' + nNum
);
792 NumFor
[nIndex
].SetNatNumNum( nNum
, TRUE
);
796 case BRACKET_SYMBOLTYPE_LOCALE
:
798 if ( NumFor
[nIndex
].GetNatNum().GetLang() != LANGUAGE_DONTKNOW
)
800 bCancel
= TRUE
; // break for
806 LanguageType eLang
= ImpGetLanguageType( sStr
, nTmp
);
807 if ( eLang
== LANGUAGE_DONTKNOW
)
809 bCancel
= TRUE
; // break for
814 sStr
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) );
815 sStr
+= String::CreateFromInt32( sal_Int32( eLang
), 16 ).ToUpperAscii();
816 NumFor
[nIndex
].SetNatNumLang( eLang
);
824 rString
.Erase(nPosOld
,nPos
-nPosOld
);
825 rString
.Insert(sStr
,nPosOld
);
826 nPos
= nPosOld
+ sStr
.Len();
827 rString
.Insert(']', nPos
);
828 rString
.Insert('[', nPosOld
);
830 nPosOld
= nPos
; // position before string
833 } while ( !bCancel
&& lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) );
835 // The remaining format code string
838 if (eSymbolType
== BRACKET_SYMBOLTYPE_FORMAT
)
840 if (nIndex
== 1 && eOp1
== NUMBERFORMAT_OP_NO
)
841 eOp1
= NUMBERFORMAT_OP_GT
; // undefined condition, default: > 0
842 else if (nIndex
== 2 && eOp2
== NUMBERFORMAT_OP_NO
)
843 eOp2
= NUMBERFORMAT_OP_LT
; // undefined condition, default: < 0
845 { // empty sub format
849 xub_StrLen nStrPos
= pSc
->ScanFormat( sStr
, aComment
);
850 USHORT nAnz
= pSc
->GetAnzResStrings();
851 if (nAnz
== 0) // error
853 if (nStrPos
== 0) // ok
855 // e.g. Thai T speciality
856 if (pSc
->GetNatNumModifier() && !NumFor
[nIndex
].GetNatNum().IsSet())
858 String
aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum"));
859 aNat
+= String::CreateFromInt32( pSc
->GetNatNumModifier());
861 sStr
.Insert( aNat
, 0);
862 NumFor
[nIndex
].SetNatNumNum( pSc
->GetNatNumModifier(), FALSE
);
864 // #i53826# #i42727# For the Thai T speciality we need
865 // to freeze the locale and immunize it against
866 // conversions during exports, just in case we want to
867 // save to Xcl. This disables the feature of being able
868 // to convert a NatNum to another locale. You can't
870 // FIXME: implement a specialized export conversion
871 // that works on tokens (have to tokenize all first)
872 // and doesn't use the format string and
873 // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
874 // sc/source/filter/excel/xestyle.cxx
875 // XclExpNumFmtBuffer::WriteFormatRecord().
876 LanguageType eLanguage
;
877 if (NumFor
[nIndex
].GetNatNum().GetNatNum() == 1 &&
879 MsLangId::getRealLanguage( eLan
))
881 NumFor
[nIndex
].GetNatNum().GetLang() ==
884 String
aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-"));
885 aLID
+= String::CreateFromInt32( sal_Int32(
886 eLanguage
), 16 ).ToUpperAscii();
888 sStr
.Insert( aLID
, 0);
889 NumFor
[nIndex
].SetNatNumLang( eLanguage
);
891 rString
.Erase(nPosOld
,nPos
-nPosOld
);
892 rString
.Insert(sStr
,nPosOld
);
893 nPos
= nPosOld
+ sStr
.Len();
894 if (nPos
< rString
.Len())
896 rString
.Insert(';',nPos
);
899 NumFor
[nIndex
].Enlarge(nAnz
);
900 pSc
->CopyInfo(&(NumFor
[nIndex
].Info()), nAnz
);
903 eType
= (short) NumFor
[nIndex
].Info().eScannedType
;
904 else if (nIndex
== 3)
905 { // #77026# Everything recognized IS text
906 NumFor
[nIndex
].Info().eScannedType
= NUMBERFORMAT_TEXT
;
908 else if ( (short) NumFor
[nIndex
].Info().eScannedType
!=
910 eType
= NUMBERFORMAT_DEFINED
;
914 nCheckPos
= nPosOld
+ nStrPos
; // error in string
915 bCancel
= TRUE
; // break for
919 else if (eSymbolType
== BRACKET_SYMBOLTYPE_ERROR
) // error
924 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType
) )
926 nCheckPos
= nPosOld
+1; // error, prefix in string
927 bCancel
= TRUE
; // break for
930 if ( bCancel
&& !nCheckPos
)
931 nCheckPos
= 1; // nCheckPos is used as an error condition
934 if ( NumFor
[nIndex
].GetNatNum().IsSet() &&
935 NumFor
[nIndex
].GetNatNum().GetLang() == LANGUAGE_DONTKNOW
)
936 NumFor
[nIndex
].SetNatNumLang( eLan
);
938 if (rString
.Len() == nPos
)
940 if ( nIndex
== 2 && eSymbolType
== BRACKET_SYMBOLTYPE_FORMAT
&&
941 rString
.GetChar(nPos
-1) == ';' )
942 { // #83510# A 4th subformat explicitly specified to be empty
943 // hides any text. Need the type here for HasTextFormat()
944 NumFor
[3].Info().eScannedType
= NUMBERFORMAT_TEXT
;
948 if ( NumFor
[nIndex
].GetNatNum().IsSet() )
949 NumFor
[nIndex
].SetNatNumDate(
950 (NumFor
[nIndex
].Info().eScannedType
& NUMBERFORMAT_DATE
) != 0 );
953 if ( bCondition
&& !nCheckPos
)
955 if ( nIndex
== 1 && NumFor
[0].GetnAnz() == 0 &&
956 rString
.GetChar(rString
.Len()-1) != ';' )
957 { // No format code => GENERAL but not if specified empty
958 String
aAdd( pSc
->GetStandardName() );
960 if ( !pSc
->ScanFormat( aAdd
, aTmp
) )
962 USHORT nAnz
= pSc
->GetAnzResStrings();
965 NumFor
[0].Enlarge(nAnz
);
966 pSc
->CopyInfo( &(NumFor
[0].Info()), nAnz
);
971 else if ( nIndex
== 1 && NumFor
[nIndex
].GetnAnz() == 0 &&
972 rString
.GetChar(rString
.Len()-1) != ';' &&
973 (NumFor
[0].GetnAnz() > 1 || (NumFor
[0].GetnAnz() == 1 &&
974 NumFor
[0].Info().nTypeArray
[0] != NF_KEY_GENERAL
)) )
975 { // No trailing second subformat => GENERAL but not if specified empty
976 // and not if first subformat is GENERAL
977 String
aAdd( pSc
->GetStandardName() );
979 if ( !pSc
->ScanFormat( aAdd
, aTmp
) )
981 USHORT nAnz
= pSc
->GetAnzResStrings();
984 NumFor
[nIndex
].Enlarge(nAnz
);
985 pSc
->CopyInfo( &(NumFor
[nIndex
].Info()), nAnz
);
991 else if ( nIndex
== 2 && NumFor
[nIndex
].GetnAnz() == 0 &&
992 rString
.GetChar(rString
.Len()-1) != ';' &&
993 eOp2
!= NUMBERFORMAT_OP_NO
)
994 { // No trailing third subformat => GENERAL but not if specified empty
995 String
aAdd( pSc
->GetStandardName() );
997 if ( !pSc
->ScanFormat( aAdd
, aTmp
) )
999 USHORT nAnz
= pSc
->GetAnzResStrings();
1002 NumFor
[nIndex
].Enlarge(nAnz
);
1003 pSc
->CopyInfo( &(NumFor
[nIndex
].Info()), nAnz
);
1010 sFormatstring
= rString
;
1011 if ( aComment
.Len() )
1013 SetComment( aComment
); // setzt sComment und sFormatstring
1014 rString
= sFormatstring
; // geaenderten sFormatstring uebernehmen
1016 if (NumFor
[2].GetnAnz() == 0 && // kein 3. Teilstring
1017 eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_NO
&&
1018 fLimit1
== 0.0 && fLimit2
== 0.0)
1019 eOp1
= NUMBERFORMAT_OP_GE
; // 0 zum ersten Format dazu
1023 SvNumberformat::~SvNumberformat()
1027 //---------------------------------------------------------------------------
1029 //---------------------------------------------------------------------------
1030 // Zerlegt die Eingabe in Symbole fuer die weitere
1031 // Verarbeitung (Turing-Maschine).
1032 //---------------------------------------------------------------------------
1033 // Ausgangs Zustand = SsStart
1034 //---------------+-------------------+-----------------------+---------------
1035 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
1036 //---------------+-------------------+-----------------------+---------------
1037 // SsStart | ; | Pos-- | SsGetString
1038 // | [ | Symbol += Zeichen | SsGetBracketed
1039 // | ] | Fehler | SsStop
1041 // | Sonst | Symbol += Zeichen | SsGetString
1042 //---------------+-------------------+-----------------------+---------------
1043 // SsGetString | ; | | SsStop
1044 // | Sonst | Symbol+=Zeichen |
1045 //---------------+-------------------+-----------------------+---------------
1046 // SsGetBracketed| <, > = | del [ |
1047 // | | Symbol += Zeichen | SsGetCon
1049 // | h, H, m, M, s, S | Symbol += Zeichen | SsGetTime
1050 // | sonst | del [ |
1051 // | | Symbol += Zeichen | SsGetPrefix
1052 //---------------+-------------------+-----------------------+---------------
1053 // SsGetTime | ] | Symbol += Zeichen | SsGetString
1054 // | h, H, m, M, s, S | Symbol += Zeichen, * | SsGetString
1055 // | sonst | del [; Symbol+=Zeichen| SsGetPrefix
1056 //---------------+-------------------+-----------------------+---------------
1057 // SsGetPrefix | ] | | SsStop
1058 // | sonst | Symbol += Zeichen |
1059 //---------------+-------------------+-----------------------+---------------
1060 // SsGetCon | >, = | Symbol+=Zeichen |
1062 // | sonst | Fehler | SsStop
1063 //---------------+-------------------+-----------------------+---------------
1064 // * : Sonderbedingung
1070 SsGetCon
, // condition
1071 SsGetString
, // format string
1072 SsGetPrefix
, // color or NatNumN
1073 SsGetTime
, // [HH] for time
1074 SsGetBracketed
// any [...] not decided yet
1078 // read a string until ']' and delete spaces in input
1080 xub_StrLen
SvNumberformat::ImpGetNumber(String
& rString
,
1084 xub_StrLen nStartPos
= nPos
;
1086 xub_StrLen nLen
= rString
.Len();
1088 while ( nPos
< nLen
&& ((cToken
= rString
.GetChar(nPos
)) != ']') )
1092 rString
.Erase(nPos
,1);
1101 return nPos
- nStartPos
;
1106 LanguageType
SvNumberformat::ImpGetLanguageType( const String
& rString
,
1110 sal_Unicode cToken
= 0;
1111 xub_StrLen nLen
= rString
.Len();
1112 while ( nPos
< nLen
&& ((cToken
= rString
.GetChar(nPos
)) != ']') )
1114 if ( '0' <= cToken
&& cToken
<= '9' )
1117 nNum
+= cToken
- '0';
1119 else if ( 'a' <= cToken
&& cToken
<= 'f' )
1122 nNum
+= cToken
- 'a' + 10;
1124 else if ( 'A' <= cToken
&& cToken
<= 'F' )
1127 nNum
+= cToken
- 'A' + 10;
1130 return LANGUAGE_DONTKNOW
;
1133 return (nNum
&& (cToken
== ']' || nPos
== nLen
)) ? (LanguageType
)nNum
:
1138 short SvNumberformat::ImpNextSymbol(String
& rString
,
1142 short eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1144 sal_Unicode cLetter
= ' '; // Zwischenergebnis
1145 xub_StrLen nLen
= rString
.Len();
1146 ScanState eState
= SsStart
;
1148 const String
* pKeywords
= rScan
.GetKeywords();
1149 while (nPos
< nLen
&& eState
!= SsStop
)
1151 cToken
= rString
.GetChar(nPos
);
1159 eState
= SsGetBracketed
;
1162 else if (cToken
== ';')
1164 eState
= SsGetString
;
1166 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1168 else if (cToken
== ']')
1171 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1173 else if (cToken
== ' ') // Skip Blanks
1175 rString
.Erase(nPos
-1,1);
1182 eState
= SsGetString
;
1183 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1187 case SsGetBracketed
:
1195 sSymbol
.EraseAllChars('[');
1201 case '<': eSymbolType
= NUMBERFORMAT_OP_LT
; break;
1202 case '>': eSymbolType
= NUMBERFORMAT_OP_GT
; break;
1203 case '=': eSymbolType
= NUMBERFORMAT_OP_EQ
; break;
1210 rString
.Erase(nPos
-1,1);
1217 if ( rString
.GetChar(nPos
) == '-' )
1219 sSymbol
.EraseAllChars('[');
1220 eSymbolType
= BRACKET_SYMBOLTYPE_LOCALE
;
1221 eState
= SsGetPrefix
;
1224 { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1225 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1226 eState
= SsGetString
;
1232 { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1233 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1235 eState
= SsGetString
;
1240 static const String
aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) );
1241 static const String
aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) );
1242 String
aUpperNatNum( rChrCls().toUpper( rString
, nPos
-1, aNatNum
.Len() ) );
1243 String
aUpperDBNum( rChrCls().toUpper( rString
, nPos
-1, aDBNum
.Len() ) );
1244 sal_Unicode cUpper
= aUpperNatNum
.GetChar(0);
1245 sal_Int32 nNatNumNum
= rString
.Copy( nPos
-1+aNatNum
.Len() ).ToInt32();
1246 sal_Unicode cDBNum
= rString
.GetChar( nPos
-1+aDBNum
.Len() );
1247 if ( aUpperNatNum
== aNatNum
&& 0 <= nNatNumNum
&& nNatNumNum
<= 19 )
1249 sSymbol
.EraseAllChars('[');
1250 sSymbol
+= rString
.Copy( --nPos
, aNatNum
.Len()+1 );
1251 nPos
+= aNatNum
.Len()+1;
1252 //! SymbolType is negative
1253 eSymbolType
= (short) (BRACKET_SYMBOLTYPE_NATNUM0
- nNatNumNum
);
1254 eState
= SsGetPrefix
;
1256 else if ( aUpperDBNum
== aDBNum
&& '1' <= cDBNum
&& cDBNum
<= '9' )
1258 sSymbol
.EraseAllChars('[');
1259 sSymbol
+= rString
.Copy( --nPos
, aDBNum
.Len()+1 );
1260 nPos
+= aDBNum
.Len()+1;
1261 //! SymbolType is negative
1262 eSymbolType
= sal::static_int_cast
< short >(
1263 BRACKET_SYMBOLTYPE_DBNUM1
- (cDBNum
- '1'));
1264 eState
= SsGetPrefix
;
1266 else if (cUpper
== pKeywords
[NF_KEY_H
].GetChar(0) || // H
1267 cUpper
== pKeywords
[NF_KEY_MI
].GetChar(0) || // M
1268 cUpper
== pKeywords
[NF_KEY_S
].GetChar(0) ) // S
1276 sSymbol
.EraseAllChars('[');
1278 eSymbolType
= BRACKET_SYMBOLTYPE_COLOR
;
1279 eState
= SsGetPrefix
;
1299 eState
= SsGetString
;
1300 eSymbolType
= BRACKET_SYMBOLTYPE_FORMAT
;
1304 sal_Unicode cUpper
= rChrCls().toUpper( rString
, nPos
-1, 1 ).GetChar(0);
1305 if (cUpper
== pKeywords
[NF_KEY_H
].GetChar(0) || // H
1306 cUpper
== pKeywords
[NF_KEY_MI
].GetChar(0) || // M
1307 cUpper
== pKeywords
[NF_KEY_S
].GetChar(0) ) // S
1309 if (cLetter
== cToken
)
1316 sSymbol
.EraseAllChars('[');
1318 eState
= SsGetPrefix
;
1323 sSymbol
.EraseAllChars('[');
1325 eSymbolType
= BRACKET_SYMBOLTYPE_COLOR
;
1326 eState
= SsGetPrefix
;
1338 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1348 eSymbolType
= NUMBERFORMAT_OP_NE
;
1353 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1363 eSymbolType
= NUMBERFORMAT_OP_LE
;
1365 else if (cLetter
== '>')
1369 eSymbolType
= NUMBERFORMAT_OP_GE
;
1374 eSymbolType
= BRACKET_SYMBOLTYPE_ERROR
;
1380 rString
.Erase(nPos
-1,1);
1410 NfHackConversion
SvNumberformat::Load( SvStream
& rStream
,
1411 ImpSvNumMultipleReadHeader
& rHdr
, SvNumberFormatter
* pHackConverter
,
1412 ImpSvNumberInputScan
& rISc
)
1416 SvNumberformat::LoadString( rStream
, sFormatstring
);
1417 rStream
>> eType
>> fLimit1
>> fLimit2
1418 >> nOp1
>> nOp2
>> bStandard
>> bIsUsed
;
1419 NfHackConversion eHackConversion
= NF_CONVERT_NONE
;
1420 BOOL bOldConvert
= FALSE
;
1421 LanguageType eOldTmpLang
= 0;
1422 LanguageType eOldNewLang
= 0;
1423 if ( pHackConverter
)
1424 { // werden nur hierbei gebraucht
1425 bOldConvert
= rScan
.GetConvertMode();
1426 eOldTmpLang
= rScan
.GetTmpLnge();
1427 eOldNewLang
= rScan
.GetNewLnge();
1429 String aLoadedColorName
;
1430 for (USHORT i
= 0; i
< 4; i
++)
1432 NumFor
[i
].Load( rStream
, rScan
, aLoadedColorName
);
1433 if ( pHackConverter
&& eHackConversion
== NF_CONVERT_NONE
)
1435 //! HACK! ER 29.07.97 13:52
1436 // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/
1437 // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert..
1438 // System-German FARBE nach System-xxx COLOR umsetzen und vice versa,
1439 //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in
1440 //! ImpSvNumberformatScan existierten
1441 if ( aLoadedColorName
.Len() && !NumFor
[i
].GetColor()
1442 && aLoadedColorName
!= rScan
.GetColorString() )
1444 if ( rScan
.GetColorString().EqualsAscii( "FARBE" ) )
1445 { // English -> German
1446 eHackConversion
= NF_CONVERT_ENGLISH_GERMAN
;
1447 rScan
.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US
);
1448 rScan
.SetConvertMode( LANGUAGE_ENGLISH_US
, LANGUAGE_GERMAN
);
1451 { // German -> English
1452 eHackConversion
= NF_CONVERT_GERMAN_ENGLISH
;
1453 rScan
.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN
);
1454 rScan
.SetConvertMode( LANGUAGE_GERMAN
, LANGUAGE_ENGLISH_US
);
1456 String aColorName
= NumFor
[i
].GetColorName();
1457 const Color
* pColor
= rScan
.GetColor( aColorName
);
1458 if ( !pColor
&& aLoadedColorName
== aColorName
)
1459 eHackConversion
= NF_CONVERT_NONE
;
1460 rScan
.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM
);
1461 rScan
.SetConvertMode( eOldTmpLang
, eOldNewLang
);
1462 rScan
.SetConvertMode( bOldConvert
);
1466 eOp1
= (SvNumberformatLimitOps
) nOp1
;
1467 eOp2
= (SvNumberformatLimitOps
) nOp2
;
1468 String aComment
; // wird nach dem NewCurrency-Geraffel richtig gesetzt
1469 if ( rHdr
.BytesLeft() )
1470 { // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1471 SvNumberformat::LoadString( rStream
, aComment
);
1472 rStream
>> nNewStandardDefined
;
1475 xub_StrLen nNewCurrencyEnd
= STRING_NOTFOUND
;
1476 BOOL bNewCurrencyComment
= ( aComment
.GetChar(0) == cNewCurrencyMagic
&&
1477 (nNewCurrencyEnd
= aComment
.Search( cNewCurrencyMagic
, 1 )) != STRING_NOTFOUND
);
1478 BOOL bNewCurrencyLoaded
= FALSE
;
1479 BOOL bNewCurrency
= FALSE
;
1482 while ( rHdr
.BytesLeft() && bGoOn
)
1483 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1488 case nNewCurrencyVersionId
:
1490 bNewCurrencyLoaded
= TRUE
;
1491 rStream
>> bNewCurrency
;
1494 for ( USHORT j
=0; j
<4; j
++ )
1496 NumFor
[j
].LoadNewCurrencyMap( rStream
);
1501 case nNewStandardFlagVersionId
:
1502 rStream
>> bStandard
; // the real standard flag
1505 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" );
1506 bGoOn
= FALSE
; // stop reading unknown stream left over of newer versions
1507 // Would be nice to have multiple read/write headers instead
1508 // but old versions wouldn't know it, TLOT.
1513 if ( bNewCurrencyLoaded
)
1515 if ( bNewCurrency
&& bNewCurrencyComment
)
1516 { // original Formatstring und Kommentar wiederherstellen
1517 sFormatstring
= aComment
.Copy( 1, nNewCurrencyEnd
-1 );
1518 aComment
.Erase( 0, nNewCurrencyEnd
+1 );
1521 else if ( bNewCurrencyComment
)
1522 { // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert
1523 // original Formatstring und Kommentar wiederherstellen
1524 sFormatstring
= aComment
.Copy( 1, nNewCurrencyEnd
-1 );
1525 aComment
.Erase( 0, nNewCurrencyEnd
+1 );
1527 short nDefined
= ( eType
& NUMBERFORMAT_DEFINED
);
1528 USHORT nNewStandard
= nNewStandardDefined
;
1530 String
aStr( sFormatstring
);
1531 xub_StrLen nCheckPos
= 0;
1532 SvNumberformat
* pFormat
= new SvNumberformat( aStr
, &rScan
, &rISc
,
1533 nCheckPos
, eLnge
, bStandard
);
1534 DBG_ASSERT( !nCheckPos
, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
1535 ImpCopyNumberformat( *pFormat
);
1537 // Zustaende wiederherstellen
1540 SetNewStandardDefined( nNewStandard
);
1542 SetComment( aComment
);
1544 if ( eHackConversion
!= NF_CONVERT_NONE
)
1545 { //! und weiter mit dem HACK!
1546 switch ( eHackConversion
)
1548 case NF_CONVERT_ENGLISH_GERMAN
:
1549 ConvertLanguage( *pHackConverter
,
1550 LANGUAGE_ENGLISH_US
, LANGUAGE_GERMAN
, TRUE
);
1552 case NF_CONVERT_GERMAN_ENGLISH
:
1553 ConvertLanguage( *pHackConverter
,
1554 LANGUAGE_GERMAN
, LANGUAGE_ENGLISH_US
, TRUE
);
1557 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
1560 return eHackConversion
;
1563 void SvNumberformat::ConvertLanguage( SvNumberFormatter
& rConverter
,
1564 LanguageType eConvertFrom
, LanguageType eConvertTo
, BOOL bSystem
)
1566 xub_StrLen nCheckPos
;
1568 short nType
= eType
;
1569 String
aFormatString( sFormatstring
);
1571 rConverter
.PutandConvertEntrySystem( aFormatString
, nCheckPos
, nType
,
1572 nKey
, eConvertFrom
, eConvertTo
);
1574 rConverter
.PutandConvertEntry( aFormatString
, nCheckPos
, nType
,
1575 nKey
, eConvertFrom
, eConvertTo
);
1576 const SvNumberformat
* pFormat
= rConverter
.GetEntry( nKey
);
1577 DBG_ASSERT( pFormat
, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
1580 ImpCopyNumberformat( *pFormat
);
1581 // aus Formatter/Scanner uebernommene Werte zuruecksetzen
1583 eLnge
= LANGUAGE_SYSTEM
;
1584 // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner
1585 for ( USHORT i
= 0; i
< 4; i
++ )
1587 String aColorName
= NumFor
[i
].GetColorName();
1588 Color
* pColor
= rScan
.GetColor( aColorName
);
1589 NumFor
[i
].SetColor( pColor
, aColorName
);
1596 void SvNumberformat::LoadString( SvStream
& rStream
, String
& rStr
)
1598 CharSet eStream
= rStream
.GetStreamCharSet();
1600 rStream
.ReadByteString( aStr
);
1601 sal_Char cStream
= NfCurrencyEntry::GetEuroSymbol( eStream
);
1602 if ( aStr
.Search( cStream
) == STRING_NOTFOUND
)
1603 { // simple conversion to unicode
1604 rStr
= UniString( aStr
, eStream
);
1608 sal_Unicode cTarget
= NfCurrencyEntry::GetEuroSymbol();
1609 register const sal_Char
* p
= aStr
.GetBuffer();
1610 register const sal_Char
* const pEnd
= p
+ aStr
.Len();
1611 register sal_Unicode
* pUni
= rStr
.AllocBuffer( aStr
.Len() );
1614 if ( *p
== cStream
)
1617 *pUni
= ByteString::ConvertToUnicode( *p
, eStream
);
1626 void SvNumberformat::Save( SvStream
& rStream
, ImpSvNumMultipleWriteHeader
& rHdr
) const
1628 String
aFormatstring( sFormatstring
);
1629 String
aComment( sComment
);
1630 #if NF_COMMENT_IN_FORMATSTRING
1631 // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen
1632 // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung
1633 // (z.B. im Dialog) zu ermoeglichen
1634 SetComment( "", aFormatstring
, aComment
);
1637 BOOL bNewCurrency
= HasNewCurrency();
1639 { // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern
1640 aComment
.Insert( cNewCurrencyMagic
, 0 );
1641 aComment
.Insert( cNewCurrencyMagic
, 0 );
1642 aComment
.Insert( aFormatstring
, 1 );
1643 Build50Formatstring( aFormatstring
); // alten Formatstring generieren
1646 // old SO5 versions do behave strange (no output) if standard flag is set
1647 // on formats not prepared for it (not having the following exact types)
1648 BOOL bOldStandard
= bStandard
;
1653 case NUMBERFORMAT_NUMBER
:
1654 case NUMBERFORMAT_DATE
:
1655 case NUMBERFORMAT_TIME
:
1656 case NUMBERFORMAT_DATETIME
:
1657 case NUMBERFORMAT_PERCENT
:
1658 case NUMBERFORMAT_SCIENTIFIC
:
1662 bOldStandard
= FALSE
;
1667 rStream
.WriteByteString( aFormatstring
, rStream
.GetStreamCharSet() );
1668 rStream
<< eType
<< fLimit1
<< fLimit2
<< (USHORT
) eOp1
<< (USHORT
) eOp2
1669 << bOldStandard
<< bIsUsed
;
1670 for (USHORT i
= 0; i
< 4; i
++)
1671 NumFor
[i
].Save(rStream
);
1672 // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1673 rStream
.WriteByteString( aComment
, rStream
.GetStreamCharSet() );
1674 rStream
<< nNewStandardDefined
;
1675 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1676 rStream
<< nNewCurrencyVersionId
;
1677 rStream
<< bNewCurrency
;
1680 for ( USHORT j
=0; j
<4; j
++ )
1682 NumFor
[j
].SaveNewCurrencyMap( rStream
);
1686 // the real standard flag to load with versions >638 if different
1687 if ( bStandard
!= bOldStandard
)
1689 rStream
<< nNewStandardFlagVersionId
;
1690 rStream
<< bStandard
;
1697 BOOL
SvNumberformat::HasNewCurrency() const
1699 for ( USHORT j
=0; j
<4; j
++ )
1701 if ( NumFor
[j
].HasNewCurrency() )
1708 BOOL
SvNumberformat::GetNewCurrencySymbol( String
& rSymbol
,
1709 String
& rExtension
) const
1711 for ( USHORT j
=0; j
<4; j
++ )
1713 if ( NumFor
[j
].GetNewCurrencySymbol( rSymbol
, rExtension
) )
1723 String
SvNumberformat::StripNewCurrencyDelimiters( const String
& rStr
,
1727 xub_StrLen nStartPos
, nPos
, nLen
;
1730 while ( (nPos
= rStr
.SearchAscii( "[$", nStartPos
)) != STRING_NOTFOUND
)
1733 if ( (nEnd
= GetQuoteEnd( rStr
, nPos
)) < nLen
)
1735 aTmp
+= rStr
.Copy( nStartPos
, ++nEnd
- nStartPos
);
1740 aTmp
+= rStr
.Copy( nStartPos
, nPos
- nStartPos
);
1741 nStartPos
= nPos
+ 2;
1743 nEnd
= nStartPos
- 1;
1746 nDash
= rStr
.Search( '-', ++nEnd
);
1747 } while ( (nEnd
= GetQuoteEnd( rStr
, nDash
)) < nLen
);
1749 nEnd
= nStartPos
- 1;
1752 nClose
= rStr
.Search( ']', ++nEnd
);
1753 } while ( (nEnd
= GetQuoteEnd( rStr
, nClose
)) < nLen
);
1754 nPos
= ( nDash
< nClose
? nDash
: nClose
);
1755 if ( !bQuoteSymbol
|| rStr
.GetChar( nStartPos
) == '"' )
1756 aTmp
+= rStr
.Copy( nStartPos
, nPos
- nStartPos
);
1760 aTmp
+= rStr
.Copy( nStartPos
, nPos
- nStartPos
);
1763 nStartPos
= nClose
+ 1;
1766 if ( nLen
> nStartPos
)
1767 aTmp
+= rStr
.Copy( nStartPos
, nLen
- nStartPos
);
1772 void SvNumberformat::Build50Formatstring( String
& rStr
) const
1774 rStr
= StripNewCurrencyDelimiters( sFormatstring
, TRUE
);
1778 void SvNumberformat::ImpGetOutputStandard(double& fNumber
, String
& OutString
)
1780 USHORT nStandardPrec
= rScan
.GetStandardPrec();
1781 if ( fabs(fNumber
) > 1.0E15
) // #58531# war E16
1782 OutString
= ::rtl::math::doubleToUString( fNumber
,
1783 rtl_math_StringFormat_E
, nStandardPrec
/*2*/,
1784 GetFormatter().GetNumDecimalSep().GetChar(0));
1789 // debugger test case for ANSI standard correctness
1790 ::rtl::OUString aTest
;
1791 // expect 0.00123 OK
1792 aTest
= ::rtl::math::doubleToUString( 0.001234567,
1793 rtl_math_StringFormat_G
, 3, '.', sal_True
);
1795 aTest
= ::rtl::math::doubleToUString( 123.4567,
1796 rtl_math_StringFormat_G
, 3, '.', sal_True
);
1798 aTest
= ::rtl::math::doubleToUString( 123.4567,
1799 rtl_math_StringFormat_G
, 4, '.', sal_True
);
1800 // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
1801 // 1000 with an exponent equal to significant digits)
1802 // Currently (24-Jan-2003) we do fail in this case and output 1000
1803 // instead, negligible.
1804 aTest
= ::rtl::math::doubleToUString( 999.6,
1805 rtl_math_StringFormat_G
, 3, '.', sal_True
);
1806 // expect what? result is 1.2e+004
1807 aTest
= ::rtl::math::doubleToUString( 12345.6789,
1808 rtl_math_StringFormat_G
, -3, '.', sal_True
);
1812 OutString
= ::rtl::math::doubleToUString( fNumber
,
1813 rtl_math_StringFormat_F
, nStandardPrec
/*2*/,
1814 GetFormatter().GetNumDecimalSep().GetChar(0), sal_True
);
1815 if (OutString
.GetChar(0) == '-' &&
1816 OutString
.GetTokenCount('0') == OutString
.Len())
1817 OutString
.EraseLeadingChars('-'); // nicht -0
1819 ImpTransliterate( OutString
, NumFor
[0].GetNatNum() );
1823 void SvNumberformat::ImpGetOutputInputLine(double fNumber
, String
& OutString
)
1825 BOOL bModified
= FALSE
;
1826 if ( (eType
& NUMBERFORMAT_PERCENT
) && (fabs(fNumber
) < _D_MAX_D_BY_100
))
1830 OutString
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
1843 OutString
= ::rtl::math::doubleToUString( fNumber
,
1844 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
1845 GetFormatter().GetNumDecimalSep().GetChar(0), sal_True
);
1847 if ( eType
& NUMBERFORMAT_PERCENT
&& bModified
)
1852 short SvNumberformat::ImpCheckCondition(double& fNumber
,
1854 SvNumberformatLimitOps eOp
)
1858 case NUMBERFORMAT_OP_NO
: return -1;
1859 case NUMBERFORMAT_OP_EQ
: return (short) (fNumber
== fLimit
);
1860 case NUMBERFORMAT_OP_NE
: return (short) (fNumber
!= fLimit
);
1861 case NUMBERFORMAT_OP_LT
: return (short) (fNumber
< fLimit
);
1862 case NUMBERFORMAT_OP_LE
: return (short) (fNumber
<= fLimit
);
1863 case NUMBERFORMAT_OP_GT
: return (short) (fNumber
> fLimit
);
1864 case NUMBERFORMAT_OP_GE
: return (short) (fNumber
>= fLimit
);
1869 BOOL
SvNumberformat::GetOutputString(String
& sString
,
1875 if (eType
& NUMBERFORMAT_TEXT
)
1877 else if (NumFor
[3].GetnAnz() > 0)
1881 *ppColor
= NULL
; // no change of color
1884 *ppColor
= NumFor
[nIx
].GetColor();
1885 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
1886 if (rInfo
.eScannedType
== NUMBERFORMAT_TEXT
)
1889 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
1890 for (USHORT i
= 0; i
< nAnz
; i
++)
1892 switch (rInfo
.nTypeArray
[i
])
1894 case NF_SYMBOLTYPE_STAR
:
1897 OutString
+= (sal_Unicode
) 0x1B;
1898 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
1902 case NF_SYMBOLTYPE_BLANK
:
1903 InsertBlanks( OutString
, OutString
.Len(),
1904 rInfo
.sStrArray
[i
].GetChar(1) );
1906 case NF_KEY_GENERAL
: // #77026# "General" is the same as "@"
1907 case NF_SYMBOLTYPE_DEL
:
1908 OutString
+= sString
;
1911 OutString
+= rInfo
.sStrArray
[i
];
1919 void SvNumberformat::GetStringColor( Color
** ppColor
)
1925 if (eType
& NUMBERFORMAT_TEXT
)
1927 else if (NumFor
[3].GetnAnz() > 0)
1931 *ppColor
= NULL
; // no change of color
1934 *ppColor
= NumFor
[nIx
].GetColor();
1938 void SvNumberformat::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
1940 ULONG& x2,ULONG& y2)
1942 x2 = ((y0+nPrec)/y1)*x1 - x0;
1943 y2 = ((y0+nPrec)/y1)*y1 - y0;
1946 ULONG
SvNumberformat::ImpGGT(ULONG x
, ULONG y
)
1963 ULONG
SvNumberformat::ImpGGTRound(ULONG x
, ULONG y
)
1970 while ((double)z
/(double)y
> D_EPS
)
1980 BOOL
SvNumberformat::GetOutputString(double fNumber
,
1985 OutString
.Erase(); // alles loeschen
1986 *ppColor
= NULL
; // keine Farbaenderung
1987 if (eType
& NUMBERFORMAT_LOGICAL
)
1990 OutString
= rScan
.GetTrueString();
1992 OutString
= rScan
.GetFalseString();
1995 if (eType
& NUMBERFORMAT_TEXT
&& bStandard
)
1997 ImpGetOutputStandard(fNumber
, OutString
);
2000 BOOL bHadStandard
= FALSE
;
2001 if (bStandard
) // einzelne Standardformate
2003 if (rScan
.GetStandardPrec() == 300) // alle Zahlformate InputLine
2005 ImpGetOutputInputLine(fNumber
, OutString
);
2010 case NUMBERFORMAT_NUMBER
: // Standardzahlformat
2011 ImpGetOutputStandard(fNumber
, OutString
);
2012 bHadStandard
= TRUE
;
2014 case NUMBERFORMAT_DATE
:
2015 bRes
|= ImpGetDateOutput(fNumber
, 0, OutString
);
2016 bHadStandard
= TRUE
;
2018 case NUMBERFORMAT_TIME
:
2019 bRes
|= ImpGetTimeOutput(fNumber
, 0, OutString
);
2020 bHadStandard
= TRUE
;
2022 case NUMBERFORMAT_DATETIME
:
2023 bRes
|= ImpGetDateTimeOutput(fNumber
, 0, OutString
);
2024 bHadStandard
= TRUE
;
2028 if ( !bHadStandard
)
2030 USHORT nIx
; // Index des Teilformats
2031 short nCheck
= ImpCheckCondition(fNumber
, fLimit1
, eOp1
);
2032 if (nCheck
== -1 || nCheck
== 1) // nur 1 String oder True
2036 nCheck
= ImpCheckCondition(fNumber
, fLimit2
, eOp2
);
2037 if (nCheck
== -1 || nCheck
== 1)
2042 if (nIx
== 1 && fNumber
< 0.0 && // negatives Format
2043 IsNegativeRealNegative() ) // ohne Vorzeichen
2044 fNumber
= -fNumber
; // Vorzeichen eliminieren
2045 *ppColor
= NumFor
[nIx
].GetColor();
2046 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2047 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2048 if (nAnz
== 0 && rInfo
.eScannedType
== NUMBERFORMAT_UNDEFINED
)
2049 return FALSE
; // leer => nichts
2050 else if (nAnz
== 0) // sonst Standard-Format
2052 ImpGetOutputStandard(fNumber
, OutString
);
2055 switch (rInfo
.eScannedType
)
2057 case NUMBERFORMAT_TEXT
:
2058 case NUMBERFORMAT_DEFINED
:
2060 for (USHORT i
= 0; i
< nAnz
; i
++)
2062 switch (rInfo
.nTypeArray
[i
])
2064 case NF_SYMBOLTYPE_STAR
:
2067 OutString
+= (sal_Unicode
) 0x1B;
2068 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2072 case NF_SYMBOLTYPE_BLANK
:
2073 InsertBlanks( OutString
, OutString
.Len(),
2074 rInfo
.sStrArray
[i
].GetChar(1) );
2076 case NF_SYMBOLTYPE_STRING
:
2077 case NF_SYMBOLTYPE_CURRENCY
:
2078 OutString
+= rInfo
.sStrArray
[i
];
2080 case NF_SYMBOLTYPE_THSEP
:
2081 if (rInfo
.nThousand
== 0)
2082 OutString
+= rInfo
.sStrArray
[i
];
2090 case NUMBERFORMAT_DATE
:
2091 bRes
|= ImpGetDateOutput(fNumber
, nIx
, OutString
);
2093 case NUMBERFORMAT_TIME
:
2094 bRes
|= ImpGetTimeOutput(fNumber
, nIx
, OutString
);
2096 case NUMBERFORMAT_DATETIME
:
2097 bRes
|= ImpGetDateTimeOutput(fNumber
, nIx
, OutString
);
2099 case NUMBERFORMAT_NUMBER
:
2100 case NUMBERFORMAT_PERCENT
:
2101 case NUMBERFORMAT_CURRENCY
:
2102 bRes
|= ImpGetNumberOutput(fNumber
, nIx
, OutString
);
2104 case NUMBERFORMAT_FRACTION
:
2106 String sStr
, sFrac
, sDiv
; // Strings, Wert fuer
2107 ULONG nFrac
, nDiv
; // Vorkommaanteil
2108 // Zaehler und Nenner
2112 if (nIx
== 0) // nicht in hinteren
2113 bSign
= TRUE
; // Formaten
2116 double fNum
= floor(fNumber
); // Vorkommateil
2117 fNumber
-= fNum
; // Nachkommateil
2118 if (fNum
> _D_MAX_U_LONG_
|| rInfo
.nCntExp
> 9)
2121 OutString
= rScan
.GetErrorString();
2124 if (rInfo
.nCntExp
== 0)
2126 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2129 ULONG nBasis
= ((ULONG
)floor( // 9, 99, 999 ,...
2130 pow(10.0,rInfo
.nCntExp
))) - 1;
2131 ULONG x0
, y0
, x1
, y1
;
2133 if (rInfo
.nCntExp
<= _MAX_FRACTION_PREC
)
2139 fNumber
-= (fNumber
- 0.5) * 2.0;
2143 // Einstieg in Farey-Serie
2145 x0
= (ULONG
) floor(fNumber
*nBasis
); // z.B. 2/9 <= x < 3/9
2146 if (x0
== 0) // => x0 = 2
2152 else if (x0
== (nBasis
-1)/2) // (b-1)/2, 1/2
2153 { // geht (nBasis ungerade)
2160 y0
= nBasis
; // 1/n; 1/(n-1)
2166 y0
= nBasis
; // z.B. 2/9 2/8
2169 double fUg
= (double) x0
/ (double) y0
;
2170 double fOg
= (double) x1
/ (double) y1
;
2171 ULONG nGgt
= ImpGGT(y0
, x0
); // x0/y0 kuerzen
2173 y0
/= nGgt
; // Einschachteln:
2180 // #i21648# GCC over-optimizes something resulting
2181 // in wrong fTest values throughout the loops.
2184 double fTest
= (double)x1
/(double)y1
;
2190 fTest
= (double)x1
/(double)y1
;
2192 while (fTest
< fUg
&& y1
> 1)
2195 fTest
= (double)x1
/(double)y1
;
2205 nGgt
= ImpGGT(y1
, x1
); // x1/y1 kuerzen
2208 if (x2
*y0
- x0
*y2
== 1 || y1
<= 1) // Test, ob x2/y2
2209 bStop
= TRUE
; // naechste Farey-Zahl
2220 flow
= (double)x0
/(double)y0
;
2221 fup
= (double)x1
/(double)y1
;
2222 while (fNumber
> fup
)
2224 ULONG x2
= ((y0
+nBasis
)/y1
)*x1
- x0
; // naechste Farey-Zahl
2225 ULONG y2
= ((y0
+nBasis
)/y1
)*y1
- y0
;
2226 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2232 fup
= (double)x1
/(double)y1
;
2234 if (fNumber
- flow
< fup
- fNumber
)
2244 if (bUpperHalf
) // Original restaur.
2246 if (nFrac
== 0 && nDiv
== 1) // 1/1
2249 nFrac
= nDiv
- nFrac
;
2252 else // grosse Nenner
2253 { // 0,1234->123/1000
2257 nFrac = ((ULONG)floor(0.5 + fNumber *
2258 pow(10.0,rInfo.nCntExp)));
2261 nFrac
= ((ULONG
)floor(0.5 + fNumber
* 10000000.0));
2262 nGgt
= ImpGGT(nDiv
, nFrac
);
2270 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2280 nFrac
= ((ULONG
)floor(0.5 + fNumber
*
2281 pow(10.0,rInfo
.nCntExp
)));
2282 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2291 if (rInfo
.nCntPre
== 0) // unechter Bruch
2293 double fNum1
= fNum
* (double)nDiv
+ (double)nFrac
;
2294 if (fNum1
> _D_MAX_U_LONG_
)
2296 OutString
= rScan
.GetErrorString();
2299 nFrac
= (ULONG
) floor(fNum1
);
2302 else if (fNum
== 0.0 && nFrac
!= 0)
2307 sprintf( aBuf
, "%.f", fNum
); // simple rounded integer (#100211# - checked)
2308 sStr
.AssignAscii( aBuf
);
2309 ImpTransliterate( sStr
, NumFor
[nIx
].GetNatNum() );
2311 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2318 sFrac
= ImpIntToString( nIx
, nFrac
);
2319 sDiv
= ImpIntToString( nIx
, nDiv
);
2322 USHORT j
= nAnz
-1; // letztes Symbol->rueckw.
2323 xub_StrLen k
; // Nenner:
2324 bRes
|= ImpNumberFill(sDiv
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRAC
);
2326 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRAC
)
2328 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2331 sDiv
.Insert( rInfo
.sStrArray
[j
].GetChar(0), 0 );
2342 bRes
|= ImpNumberFill(sFrac
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRACBLANK
);
2343 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRACBLANK
)
2345 sFrac
.Insert(rInfo
.sStrArray
[j
],0);
2357 k
= sStr
.Len(); // hinter letzter Ziffer
2358 bRes
|= ImpNumberFillWithThousands(sStr
, fNumber
, k
, j
, nIx
,
2361 if (bSign
&& !(nFrac
== 0 && fNum
== 0.0))
2362 OutString
.Insert('-',0); // nicht -0
2368 case NUMBERFORMAT_SCIENTIFIC
:
2373 if (nIx
== 0) // nicht in hinteren
2374 bSign
= TRUE
; // Formaten
2377 String
sStr( ::rtl::math::doubleToUString( fNumber
,
2378 rtl_math_StringFormat_E
,
2379 rInfo
.nCntPre
+ rInfo
.nCntPost
- 1, '.' ));
2383 xub_StrLen nExPos
= sStr
.Search('E');
2384 if ( nExPos
!= STRING_NOTFOUND
)
2386 // split into mantisse and exponent and get rid of "E+" or "E-"
2387 xub_StrLen nExpStart
= nExPos
+ 1;
2388 switch ( sStr
.GetChar( nExpStart
) )
2397 ExpStr
= sStr
.Copy( nExpStart
); // part following the "E+"
2398 sStr
.Erase( nExPos
);
2399 sStr
.EraseAllChars('.'); // cut any decimal delimiter
2400 if ( rInfo
.nCntPre
!= 1 ) // rescale Exp
2402 sal_Int32 nExp
= ExpStr
.ToInt32() * nExpSign
;
2403 nExp
-= sal_Int32(rInfo
.nCntPre
)-1;
2411 ExpStr
= String::CreateFromInt32( nExp
);
2414 USHORT j
= nAnz
-1; // last symbol
2415 xub_StrLen k
; // position in ExpStr
2416 bRes
|= ImpNumberFill(ExpStr
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_EXP
);
2418 xub_StrLen nZeros
= 0; // erase leading zeros
2419 while (nZeros
< k
&& ExpStr
.GetChar(nZeros
) == '0')
2422 ExpStr
.Erase( 0, nZeros
);
2425 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_EXP
)
2427 const String
& rStr
= rInfo
.sStrArray
[j
];
2429 ExpStr
.Insert('-',0);
2430 else if (rStr
.Len() > 1 && rStr
.GetChar(1) == '+')
2431 ExpStr
.Insert('+',0);
2432 ExpStr
.Insert(rStr
.GetChar(0),0);
2438 // weiter Hauptzahl:
2443 k
= sStr
.Len(); // hinter letzter Ziffer
2444 bRes
|= ImpNumberFillWithThousands(sStr
,fNumber
, k
,j
,nIx
,
2451 OutString
+= ExpStr
;
2459 BOOL
SvNumberformat::ImpGetTimeOutput(double fNumber
,
2463 using namespace ::com::sun::star::i18n
;
2464 BOOL bCalendarSet
= FALSE
;
2465 double fNumberOrig
= fNumber
;
2474 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2475 if (rInfo
.bThousand
) // []-Format
2477 if (fNumber
> 1.0E10
) // zu gross
2479 OutString
= rScan
.GetErrorString();
2484 fNumber
-= floor(fNumber
); // sonst Datum abtrennen
2486 xub_StrLen nCntPost
;
2487 if ( rScan
.GetStandardPrec() == 300 &&
2488 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
2489 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2496 nCntPost
= xub_StrLen(rInfo
.nCntPost
);
2498 if (bSign
&& !rInfo
.bThousand
) // kein []-Format
2499 fNumber
= 1.0 - fNumber
; // "Kehrwert"
2500 double fTime
= fNumber
* 86400.0;
2501 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
2502 if (bSign
&& fTime
== 0.0)
2503 bSign
= FALSE
; // nicht -00:00:00
2505 if( floor( fTime
) > _D_MAX_U_LONG_
)
2507 OutString
= rScan
.GetErrorString();
2510 ULONG nSeconds
= (ULONG
)floor( fTime
);
2512 String
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
2513 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
2514 sSecStr
.EraseLeadingChars('0');
2515 sSecStr
.EraseLeadingChars('.');
2518 sSecStr
.EraseTrailingChars('0');
2519 if ( sSecStr
.Len() < xub_StrLen(rInfo
.nCntPost
) )
2520 sSecStr
.Expand( xub_StrLen(rInfo
.nCntPost
), '0' );
2521 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
2522 nCntPost
= sSecStr
.Len();
2525 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
2527 xub_StrLen nSecPos
= 0; // Zum Ziffernweisen
2529 ULONG nHour
, nMin
, nSec
;
2530 if (!rInfo
.bThousand
) // kein [] Format
2532 nHour
= (nSeconds
/3600) % 24;
2533 nMin
= (nSeconds
%3600) / 60;
2536 else if (rInfo
.nThousand
== 3) // [ss]
2542 else if (rInfo
.nThousand
== 2) // [mm]:ss
2545 nMin
= nSeconds
/ 60;
2546 nSec
= nSeconds
% 60;
2548 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
2550 nHour
= nSeconds
/ 3600;
2551 nMin
= (nSeconds
%3600) / 60;
2555 // TODO What should these be set to?
2561 sal_Unicode cAmPm
= ' '; // a oder p
2562 if (rInfo
.nCntExp
) // AM/PM
2569 else if (nHour
< 12)
2578 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2579 for (USHORT i
= 0; i
< nAnz
; i
++)
2581 switch (rInfo
.nTypeArray
[i
])
2583 case NF_SYMBOLTYPE_STAR
:
2586 OutString
+= (sal_Unicode
) 0x1B;
2587 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2591 case NF_SYMBOLTYPE_BLANK
:
2592 InsertBlanks( OutString
, OutString
.Len(),
2593 rInfo
.sStrArray
[i
].GetChar(1) );
2595 case NF_SYMBOLTYPE_STRING
:
2596 case NF_SYMBOLTYPE_CURRENCY
:
2597 case NF_SYMBOLTYPE_DATESEP
:
2598 case NF_SYMBOLTYPE_TIMESEP
:
2599 case NF_SYMBOLTYPE_TIME100SECSEP
:
2600 OutString
+= rInfo
.sStrArray
[i
];
2602 case NF_SYMBOLTYPE_DIGIT
:
2604 xub_StrLen nLen
= ( bInputLine
&& i
> 0 &&
2605 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
2606 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
2607 nCntPost
: rInfo
.sStrArray
[i
].Len() );
2608 for (xub_StrLen j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
2610 OutString
+= sSecStr
.GetChar(nSecPos
);
2615 case NF_KEY_AMPM
: // AM/PM
2617 if ( !bCalendarSet
)
2619 double fDiff
= DateTime(*(rScan
.GetNullDate())) - GetCal().getEpochStart();
2620 fDiff
+= fNumberOrig
;
2621 GetCal().setLocalDateTime( fDiff
);
2622 bCalendarSet
= TRUE
;
2625 OutString
+= GetCal().getDisplayName(
2626 CalendarDisplayIndex::AM_PM
, AmPmValue::AM
, 0 );
2628 OutString
+= GetCal().getDisplayName(
2629 CalendarDisplayIndex::AM_PM
, AmPmValue::PM
, 0 );
2632 case NF_KEY_AP
: // A/P
2640 case NF_KEY_MI
: // M
2641 OutString
+= ImpIntToString( nIx
, nMin
);
2643 case NF_KEY_MMI
: // MM
2644 OutString
+= ImpIntToString( nIx
, nMin
, 2 );
2647 OutString
+= ImpIntToString( nIx
, nHour
);
2649 case NF_KEY_HH
: // HH
2650 OutString
+= ImpIntToString( nIx
, nHour
, 2 );
2653 OutString
+= ImpIntToString( nIx
, nSec
);
2655 case NF_KEY_SS
: // SS
2656 OutString
+= ImpIntToString( nIx
, nSec
, 2 );
2662 if (bSign
&& rInfo
.bThousand
)
2663 OutString
.Insert('-',0);
2668 BOOL
SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor
& rNumFor
) const
2670 if ( GetCal().getUniqueID() != Gregorian::get() )
2672 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
2673 const USHORT nAnz
= rNumFor
.GetnAnz();
2675 for ( i
= 0; i
< nAnz
; i
++ )
2677 switch ( rInfo
.nTypeArray
[i
] )
2679 case NF_SYMBOLTYPE_CALENDAR
:
2694 void SvNumberformat::SwitchToOtherCalendar( String
& rOrgCalendar
,
2695 double& fOrgDateTime
) const
2697 CalendarWrapper
& rCal
= GetCal();
2698 const rtl::OUString
&rGregorian
= Gregorian::get();
2699 if ( rCal
.getUniqueID() == rGregorian
)
2701 using namespace ::com::sun::star::i18n
;
2702 ::com::sun::star::uno::Sequence
< ::rtl::OUString
> xCals
2703 = rCal
.getAllCalendars( rLoc().getLocale() );
2704 sal_Int32 nCnt
= xCals
.getLength();
2707 for ( sal_Int32 j
=0; j
< nCnt
; j
++ )
2709 if ( xCals
[j
] != rGregorian
)
2711 if ( !rOrgCalendar
.Len() )
2713 rOrgCalendar
= rCal
.getUniqueID();
2714 fOrgDateTime
= rCal
.getDateTime();
2716 rCal
.loadCalendar( xCals
[j
], rLoc().getLocale() );
2717 rCal
.setDateTime( fOrgDateTime
);
2726 void SvNumberformat::SwitchToGregorianCalendar( const String
& rOrgCalendar
,
2727 double fOrgDateTime
) const
2729 CalendarWrapper
& rCal
= GetCal();
2730 const rtl::OUString
&rGregorian
= Gregorian::get();
2731 if ( rOrgCalendar
.Len() && rCal
.getUniqueID() != rGregorian
)
2733 rCal
.loadCalendar( rGregorian
, rLoc().getLocale() );
2734 rCal
.setDateTime( fOrgDateTime
);
2739 BOOL
SvNumberformat::ImpFallBackToGregorianCalendar( String
& rOrgCalendar
, double& fOrgDateTime
)
2741 using namespace ::com::sun::star::i18n
;
2742 CalendarWrapper
& rCal
= GetCal();
2743 const rtl::OUString
&rGregorian
= Gregorian::get();
2744 if ( rCal
.getUniqueID() != rGregorian
)
2746 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
2747 if ( nVal
== 0 && rCal
.getLoadedCalendar().Eras
[0].ID
.equalsAsciiL(
2748 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2750 if ( !rOrgCalendar
.Len() )
2752 rOrgCalendar
= rCal
.getUniqueID();
2753 fOrgDateTime
= rCal
.getDateTime();
2755 else if ( rOrgCalendar
== String(rGregorian
) )
2756 rOrgCalendar
.Erase();
2757 rCal
.loadCalendar( rGregorian
, rLoc().getLocale() );
2758 rCal
.setDateTime( fOrgDateTime
);
2766 BOOL
SvNumberformat::ImpSwitchToSpecifiedCalendar( String
& rOrgCalendar
,
2767 double& fOrgDateTime
, const ImpSvNumFor
& rNumFor
) const
2769 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
2770 const USHORT nAnz
= rNumFor
.GetnAnz();
2771 for ( USHORT i
= 0; i
< nAnz
; i
++ )
2773 if ( rInfo
.nTypeArray
[i
] == NF_SYMBOLTYPE_CALENDAR
)
2775 CalendarWrapper
& rCal
= GetCal();
2776 if ( !rOrgCalendar
.Len() )
2778 rOrgCalendar
= rCal
.getUniqueID();
2779 fOrgDateTime
= rCal
.getDateTime();
2781 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
2782 rCal
.setDateTime( fOrgDateTime
);
2791 void SvNumberformat::ImpAppendEraG( String
& OutString
,
2792 const CalendarWrapper
& rCal
, sal_Int16 nNatNum
)
2794 using namespace ::com::sun::star::i18n
;
2795 if ( rCal
.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2798 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
2801 case 1 : cEra
= 'M'; break;
2802 case 2 : cEra
= 'T'; break;
2803 case 3 : cEra
= 'S'; break;
2804 case 4 : cEra
= 'H'; break;
2811 OutString
+= rCal
.getDisplayString( CalendarDisplayCode::SHORT_ERA
, nNatNum
);
2815 BOOL
SvNumberformat::ImpGetDateOutput(double fNumber
,
2819 using namespace ::com::sun::star::i18n
;
2821 CalendarWrapper
& rCal
= GetCal();
2822 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
2824 rCal
.setLocalDateTime( fNumber
);
2825 String aOrgCalendar
; // empty => not changed yet
2826 double fOrgDateTime
;
2827 BOOL bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
2828 if ( bOtherCalendar
)
2829 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2830 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
2831 bOtherCalendar
= FALSE
;
2832 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2833 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2834 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
2835 for (USHORT i
= 0; i
< nAnz
; i
++)
2837 switch (rInfo
.nTypeArray
[i
])
2839 case NF_SYMBOLTYPE_CALENDAR
:
2840 if ( !aOrgCalendar
.Len() )
2842 aOrgCalendar
= rCal
.getUniqueID();
2843 fOrgDateTime
= rCal
.getDateTime();
2845 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
2846 rCal
.setDateTime( fOrgDateTime
);
2847 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2849 case NF_SYMBOLTYPE_STAR
:
2852 OutString
+= (sal_Unicode
) 0x1B;
2853 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2857 case NF_SYMBOLTYPE_BLANK
:
2858 InsertBlanks( OutString
, OutString
.Len(),
2859 rInfo
.sStrArray
[i
].GetChar(1) );
2861 case NF_SYMBOLTYPE_STRING
:
2862 case NF_SYMBOLTYPE_CURRENCY
:
2863 case NF_SYMBOLTYPE_DATESEP
:
2864 case NF_SYMBOLTYPE_TIMESEP
:
2865 case NF_SYMBOLTYPE_TIME100SECSEP
:
2866 OutString
+= rInfo
.sStrArray
[i
];
2869 OutString
+= rCal
.getDisplayString(
2870 CalendarDisplayCode::SHORT_MONTH
, nNatNum
);
2872 case NF_KEY_MM
: // MM
2873 OutString
+= rCal
.getDisplayString(
2874 CalendarDisplayCode::LONG_MONTH
, nNatNum
);
2876 case NF_KEY_MMM
: // MMM
2877 OutString
+= rCal
.getDisplayString(
2878 CalendarDisplayCode::SHORT_MONTH_NAME
, nNatNum
);
2880 case NF_KEY_MMMM
: // MMMM
2881 OutString
+= rCal
.getDisplayString(
2882 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
);
2884 case NF_KEY_MMMMM
: // MMMMM
2885 OutString
+= rCal
.getDisplayString(
2886 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
).GetChar(0);
2889 OutString
+= rCal
.getDisplayString(
2890 CalendarDisplayCode::SHORT_QUARTER
, nNatNum
);
2892 case NF_KEY_QQ
: // QQ
2893 OutString
+= rCal
.getDisplayString(
2894 CalendarDisplayCode::LONG_QUARTER
, nNatNum
);
2897 OutString
+= rCal
.getDisplayString(
2898 CalendarDisplayCode::SHORT_DAY
, nNatNum
);
2900 case NF_KEY_DD
: // DD
2901 OutString
+= rCal
.getDisplayString(
2902 CalendarDisplayCode::LONG_DAY
, nNatNum
);
2904 case NF_KEY_DDD
: // DDD
2906 if ( bOtherCalendar
)
2907 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2908 OutString
+= rCal
.getDisplayString(
2909 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
2910 if ( bOtherCalendar
)
2911 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2914 case NF_KEY_DDDD
: // DDDD
2916 if ( bOtherCalendar
)
2917 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2918 OutString
+= rCal
.getDisplayString(
2919 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2920 if ( bOtherCalendar
)
2921 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2924 case NF_KEY_YY
: // YY
2926 if ( bOtherCalendar
)
2927 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2928 OutString
+= rCal
.getDisplayString(
2929 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
2930 if ( bOtherCalendar
)
2931 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2934 case NF_KEY_YYYY
: // YYYY
2936 if ( bOtherCalendar
)
2937 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2938 OutString
+= rCal
.getDisplayString(
2939 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
2940 if ( bOtherCalendar
)
2941 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2944 case NF_KEY_EC
: // E
2945 OutString
+= rCal
.getDisplayString(
2946 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
2948 case NF_KEY_EEC
: // EE
2950 OutString
+= rCal
.getDisplayString(
2951 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
2953 case NF_KEY_NN
: // NN
2954 case NF_KEY_AAA
: // AAA
2955 OutString
+= rCal
.getDisplayString(
2956 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
2958 case NF_KEY_NNN
: // NNN
2959 case NF_KEY_AAAA
: // AAAA
2960 OutString
+= rCal
.getDisplayString(
2961 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2963 case NF_KEY_NNNN
: // NNNN
2965 OutString
+= rCal
.getDisplayString(
2966 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2967 OutString
+= rLoc().getLongDateDayOfWeekSep();
2970 case NF_KEY_WW
: // WW
2972 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
);
2973 OutString
+= ImpIntToString( nIx
, nVal
);
2977 ImpAppendEraG( OutString
, rCal
, nNatNum
);
2979 case NF_KEY_GG
: // GG
2980 OutString
+= rCal
.getDisplayString(
2981 CalendarDisplayCode::SHORT_ERA
, nNatNum
);
2983 case NF_KEY_GGG
: // GGG
2984 OutString
+= rCal
.getDisplayString(
2985 CalendarDisplayCode::LONG_ERA
, nNatNum
);
2987 case NF_KEY_RR
: // RR => GGGEE
2988 OutString
+= rCal
.getDisplayString(
2989 CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
);
2993 if ( aOrgCalendar
.Len() )
2994 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLocale() ); // restore calendar
2998 BOOL
SvNumberformat::ImpGetDateTimeOutput(double fNumber
,
3002 using namespace ::com::sun::star::i18n
;
3005 CalendarWrapper
& rCal
= GetCal();
3006 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
3009 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3011 xub_StrLen nCntPost
;
3012 if ( rScan
.GetStandardPrec() == 300 &&
3013 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
3014 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
3021 nCntPost
= xub_StrLen(rInfo
.nCntPost
);
3023 double fTime
= (fNumber
- floor( fNumber
)) * 86400.0;
3024 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
3025 if (fTime
>= 86400.0)
3027 // result of fNumber==x.999999999... rounded up, use correct date/time
3029 fNumber
= floor( fNumber
+ 0.5) + fTime
;
3031 rCal
.setLocalDateTime( fNumber
);
3033 String aOrgCalendar
; // empty => not changed yet
3034 double fOrgDateTime
;
3035 BOOL bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
3036 if ( bOtherCalendar
)
3037 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3038 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
3039 bOtherCalendar
= FALSE
;
3040 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
3042 ULONG nSeconds
= (ULONG
)floor( fTime
);
3043 String
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
3044 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
3045 sSecStr
.EraseLeadingChars('0');
3046 sSecStr
.EraseLeadingChars('.');
3049 sSecStr
.EraseTrailingChars('0');
3050 if ( sSecStr
.Len() < xub_StrLen(rInfo
.nCntPost
) )
3051 sSecStr
.Expand( xub_StrLen(rInfo
.nCntPost
), '0' );
3052 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
3053 nCntPost
= sSecStr
.Len();
3056 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
3058 xub_StrLen nSecPos
= 0; // Zum Ziffernweisen
3060 ULONG nHour
, nMin
, nSec
;
3061 if (!rInfo
.bThousand
) // [] Format
3063 nHour
= (nSeconds
/3600) % 24;
3064 nMin
= (nSeconds
%3600) / 60;
3067 else if (rInfo
.nThousand
== 3) // [ss]
3073 else if (rInfo
.nThousand
== 2) // [mm]:ss
3076 nMin
= nSeconds
/ 60;
3077 nSec
= nSeconds
% 60;
3079 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
3081 nHour
= nSeconds
/ 3600;
3082 nMin
= (nSeconds
%3600) / 60;
3086 nHour
= 0; // TODO What should these values be?
3090 sal_Unicode cAmPm
= ' '; // a oder p
3091 if (rInfo
.nCntExp
) // AM/PM
3098 else if (nHour
< 12)
3107 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
3108 for (USHORT i
= 0; i
< nAnz
; i
++)
3110 switch (rInfo
.nTypeArray
[i
])
3112 case NF_SYMBOLTYPE_CALENDAR
:
3113 if ( !aOrgCalendar
.Len() )
3115 aOrgCalendar
= rCal
.getUniqueID();
3116 fOrgDateTime
= rCal
.getDateTime();
3118 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
3119 rCal
.setDateTime( fOrgDateTime
);
3120 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3122 case NF_SYMBOLTYPE_STAR
:
3125 OutString
+= (sal_Unicode
) 0x1B;
3126 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
3130 case NF_SYMBOLTYPE_BLANK
:
3131 InsertBlanks( OutString
, OutString
.Len(),
3132 rInfo
.sStrArray
[i
].GetChar(1) );
3134 case NF_SYMBOLTYPE_STRING
:
3135 case NF_SYMBOLTYPE_CURRENCY
:
3136 case NF_SYMBOLTYPE_DATESEP
:
3137 case NF_SYMBOLTYPE_TIMESEP
:
3138 case NF_SYMBOLTYPE_TIME100SECSEP
:
3139 OutString
+= rInfo
.sStrArray
[i
];
3141 case NF_SYMBOLTYPE_DIGIT
:
3143 xub_StrLen nLen
= ( bInputLine
&& i
> 0 &&
3144 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
3145 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
3146 nCntPost
: rInfo
.sStrArray
[i
].Len() );
3147 for (xub_StrLen j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
3149 OutString
+= sSecStr
.GetChar(nSecPos
);
3154 case NF_KEY_AMPM
: // AM/PM
3157 OutString
+= rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3160 OutString
+= rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3164 case NF_KEY_AP
: // A/P
3172 case NF_KEY_MI
: // M
3173 OutString
+= ImpIntToString( nIx
, nMin
);
3175 case NF_KEY_MMI
: // MM
3176 OutString
+= ImpIntToString( nIx
, nMin
, 2 );
3179 OutString
+= ImpIntToString( nIx
, nHour
);
3181 case NF_KEY_HH
: // HH
3182 OutString
+= ImpIntToString( nIx
, nHour
, 2 );
3185 OutString
+= ImpIntToString( nIx
, nSec
);
3187 case NF_KEY_SS
: // SS
3188 OutString
+= ImpIntToString( nIx
, nSec
, 2 );
3191 OutString
+= rCal
.getDisplayString(
3192 CalendarDisplayCode::SHORT_MONTH
, nNatNum
);
3194 case NF_KEY_MM
: // MM
3195 OutString
+= rCal
.getDisplayString(
3196 CalendarDisplayCode::LONG_MONTH
, nNatNum
);
3198 case NF_KEY_MMM
: // MMM
3199 OutString
+= rCal
.getDisplayString(
3200 CalendarDisplayCode::SHORT_MONTH_NAME
, nNatNum
);
3202 case NF_KEY_MMMM
: // MMMM
3203 OutString
+= rCal
.getDisplayString(
3204 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
);
3206 case NF_KEY_MMMMM
: // MMMMM
3207 OutString
+= rCal
.getDisplayString(
3208 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
).GetChar(0);
3211 OutString
+= rCal
.getDisplayString(
3212 CalendarDisplayCode::SHORT_QUARTER
, nNatNum
);
3214 case NF_KEY_QQ
: // QQ
3215 OutString
+= rCal
.getDisplayString(
3216 CalendarDisplayCode::LONG_QUARTER
, nNatNum
);
3219 OutString
+= rCal
.getDisplayString(
3220 CalendarDisplayCode::SHORT_DAY
, nNatNum
);
3222 case NF_KEY_DD
: // DD
3223 OutString
+= rCal
.getDisplayString(
3224 CalendarDisplayCode::LONG_DAY
, nNatNum
);
3226 case NF_KEY_DDD
: // DDD
3228 if ( bOtherCalendar
)
3229 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3230 OutString
+= rCal
.getDisplayString(
3231 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
3232 if ( bOtherCalendar
)
3233 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3236 case NF_KEY_DDDD
: // DDDD
3238 if ( bOtherCalendar
)
3239 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3240 OutString
+= rCal
.getDisplayString(
3241 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3242 if ( bOtherCalendar
)
3243 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3246 case NF_KEY_YY
: // YY
3248 if ( bOtherCalendar
)
3249 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3250 OutString
+= rCal
.getDisplayString(
3251 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
3252 if ( bOtherCalendar
)
3253 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3256 case NF_KEY_YYYY
: // YYYY
3258 if ( bOtherCalendar
)
3259 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3260 OutString
+= rCal
.getDisplayString(
3261 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3262 if ( bOtherCalendar
)
3263 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3266 case NF_KEY_EC
: // E
3267 OutString
+= rCal
.getDisplayString(
3268 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
3270 case NF_KEY_EEC
: // EE
3272 OutString
+= rCal
.getDisplayString(
3273 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3275 case NF_KEY_NN
: // NN
3276 case NF_KEY_AAA
: // AAA
3277 OutString
+= rCal
.getDisplayString(
3278 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
3280 case NF_KEY_NNN
: // NNN
3281 case NF_KEY_AAAA
: // AAAA
3282 OutString
+= rCal
.getDisplayString(
3283 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3285 case NF_KEY_NNNN
: // NNNN
3287 OutString
+= rCal
.getDisplayString(
3288 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3289 OutString
+= rLoc().getLongDateDayOfWeekSep();
3292 case NF_KEY_WW
: // WW
3294 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
);
3295 OutString
+= ImpIntToString( nIx
, nVal
);
3299 ImpAppendEraG( OutString
, rCal
, nNatNum
);
3301 case NF_KEY_GG
: // GG
3302 OutString
+= rCal
.getDisplayString(
3303 CalendarDisplayCode::SHORT_ERA
, nNatNum
);
3305 case NF_KEY_GGG
: // GGG
3306 OutString
+= rCal
.getDisplayString(
3307 CalendarDisplayCode::LONG_ERA
, nNatNum
);
3309 case NF_KEY_RR
: // RR => GGGEE
3310 OutString
+= rCal
.getDisplayString(
3311 CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
);
3315 if ( aOrgCalendar
.Len() )
3316 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLocale() ); // restore calendar
3320 BOOL
SvNumberformat::ImpGetNumberOutput(double fNumber
,
3328 if (nIx
== 0) // nicht in hinteren
3329 bSign
= TRUE
; // Formaten
3337 if ( ::rtl::math::isSignBitSet( fNumber
) )
3338 fNumber
= -fNumber
; // yes, -0.0 is possible, eliminate '-'
3340 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3341 if (rInfo
.eScannedType
== NUMBERFORMAT_PERCENT
)
3343 if (fNumber
< _D_MAX_D_BY_100
)
3347 OutString
= rScan
.GetErrorString();
3355 BOOL bInteger
= FALSE
;
3356 if ( rInfo
.nThousand
!= FLAG_STANDARD_IN_FORMAT
)
3357 { // special formatting only if no GENERAL keyword in format code
3358 const USHORT nThousand
= rInfo
.nThousand
;
3359 for (i
= 0; i
< nThousand
; i
++)
3361 if (fNumber
> _D_MIN_M_BY_1000
)
3367 nPrecExp
= GetPrecExp( fNumber
);
3370 if (rInfo
.nCntPost
) // NachkommaStellen
3372 if (rInfo
.nCntPost
+ nPrecExp
> 15 && nPrecExp
< 15)
3374 sStr
= ::rtl::math::doubleToUString( fNumber
,
3375 rtl_math_StringFormat_F
, 15-nPrecExp
, '.');
3376 for (long l
= 15-nPrecExp
; l
< (long) rInfo
.nCntPost
; l
++)
3380 sStr
= ::rtl::math::doubleToUString( fNumber
,
3381 rtl_math_StringFormat_F
, rInfo
.nCntPost
, '.' );
3382 sStr
.EraseLeadingChars('0'); // fuehrende Nullen weg
3384 else if (fNumber
== 0.0) // Null
3386 // nothing to be done here, keep empty string sStr,
3387 // ImpNumberFillWithThousands does the rest
3391 sStr
= ::rtl::math::doubleToUString( fNumber
,
3392 rtl_math_StringFormat_F
, 0, '.');
3393 sStr
.EraseLeadingChars('0'); // fuehrende Nullen weg
3395 xub_StrLen nPoint
= sStr
.Search( '.' );
3396 if ( nPoint
!= STRING_NOTFOUND
)
3398 register const sal_Unicode
* p
= sStr
.GetBuffer() + nPoint
;
3399 while ( *++p
== '0' )
3403 sStr
.Erase( nPoint
, 1 ); // . herausnehmen
3406 (sStr
.Len() == 0 || sStr
.GetTokenCount('0') == sStr
.Len()+1)) // nur 00000
3407 bSign
= FALSE
; // nicht -0.00
3408 } // End of != FLAG_STANDARD_IN_FORMAT
3410 // von hinten nach vorn
3412 k
= sStr
.Len(); // hinter letzter Ziffer
3413 j
= NumFor
[nIx
].GetnAnz()-1; // letztes Symbol
3414 // Nachkommastellen:
3415 if (rInfo
.nCntPost
> 0)
3417 BOOL bTrailing
= TRUE
; // ob Endnullen?
3418 BOOL bFilled
= FALSE
; // ob aufgefuellt wurde ?
3420 while (j
> 0 && // rueckwaerts
3421 (nType
= rInfo
.nTypeArray
[j
]) != NF_SYMBOLTYPE_DECSEP
)
3425 case NF_SYMBOLTYPE_STAR
:
3428 sStr
.Insert( (sal_Unicode
) 0x1B, k
/*++*/ );
3429 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3433 case NF_SYMBOLTYPE_BLANK
:
3434 /*k = */ InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3436 case NF_SYMBOLTYPE_STRING
:
3437 case NF_SYMBOLTYPE_CURRENCY
:
3438 case NF_SYMBOLTYPE_PERCENT
:
3439 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3441 case NF_SYMBOLTYPE_THSEP
:
3442 if (rInfo
.nThousand
== 0)
3443 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3445 case NF_SYMBOLTYPE_DIGIT
:
3447 const String
& rStr
= rInfo
.sStrArray
[j
];
3448 const sal_Unicode
* p1
= rStr
.GetBuffer();
3449 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3452 const sal_Unicode c
= *p
;
3454 if ( sStr
.GetChar(k
) != '0' )
3460 else if ( c
== '-' )
3463 sStr
.SetChar( k
, '-' );
3466 else if ( c
== '?' )
3468 sStr
.SetChar( k
, ' ' );
3471 else if ( !bFilled
) // #
3477 case NF_KEY_CCC
: // CCC-Waehrung
3478 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3480 case NF_KEY_GENERAL
: // Standard im String
3483 ImpGetOutputStandard(fNumber
, sNum
);
3484 sNum
.EraseLeadingChars('-');
3485 sStr
.Insert(sNum
, k
);
3495 bRes
|= ImpNumberFillWithThousands(sStr
, fNumber
, k
, j
, nIx
, // ggfs Auffuellen mit .
3497 if ( rInfo
.nCntPost
> 0 )
3499 const String
& rDecSep
= GetFormatter().GetNumDecimalSep();
3500 xub_StrLen nLen
= rDecSep
.Len();
3501 if ( sStr
.Len() > nLen
&& sStr
.Equals( rDecSep
, sStr
.Len() - nLen
, nLen
) )
3502 sStr
.Erase( sStr
.Len() - nLen
); // no decimals => strip DecSep
3506 ImpTransliterate( sStr
, NumFor
[nIx
].GetNatNum() );
3511 BOOL
SvNumberformat::ImpNumberFillWithThousands(
3512 String
& sStr
, // number string
3513 double& rNumber
, // number
3514 xub_StrLen k
, // position within string
3515 USHORT j
, // symbol index within format code
3516 USHORT nIx
, // subformat index
3517 USHORT nDigCnt
) // count of integer digits in format
3520 xub_StrLen nLeadingStringChars
= 0; // inserted StringChars before number
3521 xub_StrLen nDigitCount
= 0; // count of integer digits from the right
3523 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3524 // no normal thousands separators if number divided by thousands
3525 BOOL bDoThousands
= (rInfo
.nThousand
== 0);
3526 utl::DigitGroupingIterator
aGrouping(
3527 GetFormatter().GetLocaleData()->getDigitGrouping());
3528 while (!bStop
) // backwards
3532 switch (rInfo
.nTypeArray
[j
])
3534 case NF_SYMBOLTYPE_DECSEP
:
3537 case NF_SYMBOLTYPE_STRING
:
3538 case NF_SYMBOLTYPE_CURRENCY
:
3539 case NF_SYMBOLTYPE_PERCENT
:
3540 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3542 nLeadingStringChars
=
3543 nLeadingStringChars
+ rInfo
.sStrArray
[j
].Len();
3545 case NF_SYMBOLTYPE_STAR
:
3548 sStr
.Insert( (sal_Unicode
) 0x1B, k
/*++*/ );
3549 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3553 case NF_SYMBOLTYPE_BLANK
:
3554 /*k = */ InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3556 case NF_SYMBOLTYPE_THSEP
:
3558 // #i7284# #102685# Insert separator also if number is divided
3559 // by thousands and the separator is specified somewhere in
3560 // between and not only at the end.
3561 // #i12596# But do not insert if it's a parenthesized negative
3563 // In fact, do not insert if divided and regex [0#,],[^0#] and
3564 // no other digit symbol follows (which was already detected
3565 // during scan of format code, otherwise there would be no
3566 // division), else do insert. Same in ImpNumberFill() below.
3567 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetnAnz()-1 )
3568 bDoThousands
= ((j
== 0) ||
3569 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
3570 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
3571 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
3575 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3576 else if (nDigitCount
< nDigCnt
)
3578 // Leading '#' displays nothing (e.g. no leading
3579 // separator for numbers <1000 with #,##0 format).
3580 // Leading '?' displays blank.
3581 // Everything else, including nothing, displays the
3583 sal_Unicode cLeader
= 0;
3584 if (j
> 0 && rInfo
.nTypeArray
[j
-1] == NF_SYMBOLTYPE_DIGIT
)
3586 const String
& rStr
= rInfo
.sStrArray
[j
-1];
3587 xub_StrLen nLen
= rStr
.Len();
3589 cLeader
= rStr
.GetChar(nLen
-1);
3597 // erAck: 2008-04-03T16:24+0200
3598 // Actually this currently isn't executed
3599 // because the format scanner in the context of
3600 // "?," doesn't generate a group separator but
3601 // a literal ',' character instead that is
3602 // inserted unconditionally. Should be changed
3603 // on some occasion.
3607 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3610 aGrouping
.advance();
3614 case NF_SYMBOLTYPE_DIGIT
:
3616 const String
& rStr
= rInfo
.sStrArray
[j
];
3617 const sal_Unicode
* p1
= rStr
.GetBuffer();
3618 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3636 if (nDigitCount
== nDigCnt
&& k
> 0)
3637 { // more digits than specified
3638 ImpDigitFill(sStr
, 0, k
, nIx
, nDigitCount
, aGrouping
);
3643 case NF_KEY_CCC
: // CCC currency
3644 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3646 case NF_KEY_GENERAL
: // "General" in string
3649 ImpGetOutputStandard(rNumber
, sNum
);
3650 sNum
.EraseLeadingChars('-');
3651 sStr
.Insert(sNum
, k
);
3658 j
--; // next format code string
3660 k
= k
+ nLeadingStringChars
; // MSC converts += to int and then warns, so ...
3661 if (k
> nLeadingStringChars
)
3662 ImpDigitFill(sStr
, nLeadingStringChars
, k
, nIx
, nDigitCount
, aGrouping
);
3666 void SvNumberformat::ImpDigitFill(
3667 String
& sStr
, // number string
3668 xub_StrLen nStart
, // start of digits
3669 xub_StrLen
& k
, // position within string
3670 USHORT nIx
, // subformat index
3671 xub_StrLen
& nDigitCount
, // count of integer digits from the right so far
3672 utl::DigitGroupingIterator
& rGrouping
) // current grouping
3674 if (NumFor
[nIx
].Info().bThousand
) // only if grouping
3675 { // fill in separators
3676 const String
& rThousandSep
= GetFormatter().GetNumThousandSep();
3679 if (nDigitCount
== rGrouping
.getPos())
3681 sStr
.Insert( rThousandSep
, k
);
3682 rGrouping
.advance();
3692 BOOL
SvNumberformat::ImpNumberFill( String
& sStr
, // number string
3693 double& rNumber
, // number for "General" format
3694 xub_StrLen
& k
, // position within string
3695 USHORT
& j
, // symbol index within format code
3696 USHORT nIx
, // subformat index
3697 short eSymbolType
) // type of stop condition
3700 k
= sStr
.Len(); // behind last digit
3701 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3702 // no normal thousands separators if number divided by thousands
3703 BOOL bDoThousands
= (rInfo
.nThousand
== 0);
3705 while (j
> 0 && (nType
= rInfo
.nTypeArray
[j
]) != eSymbolType
)
3709 case NF_SYMBOLTYPE_STAR
:
3712 sStr
.Insert( sal_Unicode(0x1B), k
++ );
3713 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3717 case NF_SYMBOLTYPE_BLANK
:
3718 k
= InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3720 case NF_SYMBOLTYPE_THSEP
:
3722 // Same as in ImpNumberFillWithThousands() above, do not insert
3723 // if divided and regex [0#,],[^0#] and no other digit symbol
3724 // follows (which was already detected during scan of format
3725 // code, otherwise there would be no division), else do insert.
3726 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetnAnz()-1 )
3727 bDoThousands
= ((j
== 0) ||
3728 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
3729 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
3730 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
3731 if ( bDoThousands
&& k
> 0 )
3733 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3737 case NF_SYMBOLTYPE_DIGIT
:
3739 const String
& rStr
= rInfo
.sStrArray
[j
];
3740 const sal_Unicode
* p1
= rStr
.GetBuffer();
3741 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3761 case NF_KEY_CCC
: // CCC-Waehrung
3762 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3764 case NF_KEY_GENERAL
: // Standard im String
3767 ImpGetOutputStandard(rNumber
, sNum
);
3768 sNum
.EraseLeadingChars('-'); // Vorzeichen weg!!
3769 sStr
.Insert(sNum
, k
);
3774 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3777 j
--; // naechster String
3782 void SvNumberformat::GetFormatSpecialInfo(BOOL
& bThousand
,
3785 USHORT
& nAnzLeading
) const
3787 // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3790 GetNumForInfo( 0, nDummyType
, bThousand
, nPrecision
, nAnzLeading
);
3792 // "negative in red" is only useful for the whole format
3794 const Color
* pColor
= NumFor
[1].GetColor();
3795 if (fLimit1
== 0.0 && fLimit2
== 0.0 && pColor
3796 && (*pColor
== rScan
.GetRedColor()))
3802 void SvNumberformat::GetNumForInfo( USHORT nNumFor
, short& rScannedType
,
3803 BOOL
& bThousand
, USHORT
& nPrecision
, USHORT
& nAnzLeading
) const
3805 // take info from a specified sub-format (for XML export)
3810 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nNumFor
].Info();
3811 rScannedType
= rInfo
.eScannedType
;
3812 bThousand
= rInfo
.bThousand
;
3813 nPrecision
= rInfo
.nCntPost
;
3814 if (bStandard
&& rInfo
.eScannedType
== NUMBERFORMAT_NUMBER
)
3822 const USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3823 while (!bStop
&& i
< nAnz
)
3825 short nType
= rInfo
.nTypeArray
[i
];
3826 if ( nType
== NF_SYMBOLTYPE_DIGIT
)
3828 register const sal_Unicode
* p
= rInfo
.sStrArray
[i
].GetBuffer();
3831 while ( *p
++ == '0' )
3834 else if (nType
== NF_SYMBOLTYPE_DECSEP
|| nType
== NF_SYMBOLTYPE_EXP
)
3841 const String
* SvNumberformat::GetNumForString( USHORT nNumFor
, USHORT nPos
,
3842 BOOL bString
/* = FALSE */ ) const
3846 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3849 if ( nPos
== 0xFFFF )
3854 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3855 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3856 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3861 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3865 else if ( nPos
> nAnz
- 1 )
3869 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3870 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3871 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3876 if ( nPos
>= nAnz
|| ((*pType
!= NF_SYMBOLTYPE_STRING
) &&
3877 (*pType
!= NF_SYMBOLTYPE_CURRENCY
)) )
3880 return &NumFor
[nNumFor
].Info().sStrArray
[nPos
];
3884 short SvNumberformat::GetNumForType( USHORT nNumFor
, USHORT nPos
,
3885 BOOL bString
/* = FALSE */ ) const
3889 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3892 if ( nPos
== 0xFFFF )
3897 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3898 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3899 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3904 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3908 else if ( nPos
> nAnz
- 1 )
3912 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3913 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3914 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3919 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3922 return NumFor
[nNumFor
].Info().nTypeArray
[nPos
];
3926 BOOL
SvNumberformat::IsNegativeWithoutSign() const
3928 if ( IsNegativeRealNegative() )
3930 const String
* pStr
= GetNumForString( 1, 0, TRUE
);
3932 return !HasStringNegativeSign( *pStr
);
3938 DateFormat
SvNumberformat::GetDateOrder() const
3940 if ( (eType
& NUMBERFORMAT_DATE
) == NUMBERFORMAT_DATE
)
3942 short const * const pType
= NumFor
[0].Info().nTypeArray
;
3943 USHORT nAnz
= NumFor
[0].GetnAnz();
3944 for ( USHORT j
=0; j
<nAnz
; j
++ )
3969 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
3971 return rLoc().getDateFormat();
3975 sal_uInt32
SvNumberformat::GetExactDateOrder() const
3977 sal_uInt32 nRet
= 0;
3978 if ( (eType
& NUMBERFORMAT_DATE
) != NUMBERFORMAT_DATE
)
3980 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
3983 short const * const pType
= NumFor
[0].Info().nTypeArray
;
3984 USHORT nAnz
= NumFor
[0].GetnAnz();
3986 for ( USHORT j
=0; j
<nAnz
&& nShift
< 3; j
++ )
3992 nRet
= (nRet
<< 8) | 'D';
4000 nRet
= (nRet
<< 8) | 'M';
4009 nRet
= (nRet
<< 8) | 'Y';
4018 void SvNumberformat::GetConditions( SvNumberformatLimitOps
& rOper1
, double& rVal1
,
4019 SvNumberformatLimitOps
& rOper2
, double& rVal2
) const
4028 Color
* SvNumberformat::GetColor( USHORT nNumFor
) const
4033 return NumFor
[nNumFor
].GetColor();
4037 void lcl_SvNumberformat_AddLimitStringImpl( String
& rStr
,
4038 SvNumberformatLimitOps eOp
, double fLimit
, const String
& rDecSep
)
4040 if ( eOp
!= NUMBERFORMAT_OP_NO
)
4044 case NUMBERFORMAT_OP_EQ
:
4045 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4047 case NUMBERFORMAT_OP_NE
:
4048 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4050 case NUMBERFORMAT_OP_LT
:
4051 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4053 case NUMBERFORMAT_OP_LE
:
4054 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4056 case NUMBERFORMAT_OP_GT
:
4057 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4059 case NUMBERFORMAT_OP_GE
:
4060 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4063 OSL_ASSERT( "unsupported number format" );
4066 rStr
+= String( ::rtl::math::doubleToUString( fLimit
,
4067 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
4068 rDecSep
.GetChar(0), sal_True
));
4074 String
SvNumberformat::GetMappedFormatstring(
4075 const NfKeywordTable
& rKeywords
, const LocaleDataWrapper
& rLocWrp
,
4076 BOOL bDontQuote
) const
4080 // 1 subformat matches all if no condition specified,
4081 bDefault
[0] = ( NumFor
[1].GetnAnz() == 0 && eOp1
== NUMBERFORMAT_OP_NO
);
4082 // with 2 subformats [>=0];[<0] is implied if no condition specified
4083 bDefault
[1] = ( !bDefault
[0] && NumFor
[2].GetnAnz() == 0 &&
4084 eOp1
== NUMBERFORMAT_OP_GE
&& fLimit1
== 0.0 &&
4085 eOp2
== NUMBERFORMAT_OP_NO
&& fLimit2
== 0.0 );
4086 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4087 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4088 bDefault
[2] = ( !bDefault
[0] && !bDefault
[1] &&
4089 eOp1
== NUMBERFORMAT_OP_GT
&& fLimit1
== 0.0 &&
4090 eOp2
== NUMBERFORMAT_OP_LT
&& fLimit2
== 0.0 );
4091 BOOL bDefaults
= bDefault
[0] || bDefault
[1] || bDefault
[2];
4092 // from now on bDefault[] values are used to append empty subformats at the end
4093 bDefault
[3] = FALSE
;
4095 { // conditions specified
4096 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
== NUMBERFORMAT_OP_NO
)
4097 bDefault
[0] = bDefault
[1] = TRUE
; // [];x
4098 else if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
!= NUMBERFORMAT_OP_NO
&&
4099 NumFor
[2].GetnAnz() == 0 )
4100 bDefault
[0] = bDefault
[1] = bDefault
[2] = bDefault
[3] = TRUE
; // [];[];;
4101 // nothing to do if conditions specified for every subformat
4103 else if ( bDefault
[0] )
4104 bDefault
[0] = FALSE
; // a single unconditional subformat is never delimited
4107 if ( bDefault
[2] && NumFor
[2].GetnAnz() == 0 && NumFor
[1].GetnAnz() > 0 )
4108 bDefault
[3] = TRUE
; // special cases x;x;; and ;x;;
4109 for ( int i
=0; i
<3 && !bDefault
[i
]; ++i
)
4112 int nSem
= 0; // needed ';' delimiters
4113 int nSub
= 0; // subformats delimited so far
4114 for ( int n
=0; n
<4; n
++ )
4126 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp1
,
4127 fLimit1
, rLocWrp
.getNumDecimalSep() );
4130 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp2
,
4131 fLimit2
, rLocWrp
.getNumDecimalSep() );
4136 const String
& rColorName
= NumFor
[n
].GetColorName();
4137 if ( rColorName
.Len() )
4139 const String
* pKey
= rScan
.GetKeywords() + NF_KEY_FIRSTCOLOR
;
4140 for ( int j
=NF_KEY_FIRSTCOLOR
; j
<=NF_KEY_LASTCOLOR
; j
++, pKey
++ )
4142 if ( *pKey
== rColorName
)
4145 aPrefix
+= rKeywords
[j
];
4152 const SvNumberNatNum
& rNum
= NumFor
[n
].GetNatNum();
4153 // The Thai T NatNum modifier during Xcl export.
4154 if (rNum
.IsSet() && rNum
.GetNatNum() == 1 &&
4155 rKeywords
[NF_KEY_THAI_T
].EqualsAscii( "T") &&
4156 MsLangId::getRealLanguage( rNum
.GetLang()) ==
4159 aPrefix
+= 't'; // must be lowercase, otherwise taken as literal
4162 USHORT nAnz
= NumFor
[n
].GetnAnz();
4163 if ( nSem
&& (nAnz
|| aPrefix
.Len()) )
4165 for ( ; nSem
; --nSem
)
4167 for ( ; nSub
<= n
; ++nSub
)
4168 bDefault
[nSub
] = FALSE
;
4171 if ( aPrefix
.Len() )
4176 const short* pType
= NumFor
[n
].Info().nTypeArray
;
4177 const String
* pStr
= NumFor
[n
].Info().sStrArray
;
4178 for ( USHORT j
=0; j
<nAnz
; j
++ )
4180 if ( 0 <= pType
[j
] && pType
[j
] < NF_KEYWORD_ENTRIES_COUNT
)
4182 aStr
+= rKeywords
[pType
[j
]];
4183 if( NF_KEY_NNNN
== pType
[j
] )
4184 aStr
+= rLocWrp
.getLongDateDayOfWeekSep();
4190 case NF_SYMBOLTYPE_DECSEP
:
4191 aStr
+= rLocWrp
.getNumDecimalSep();
4193 case NF_SYMBOLTYPE_THSEP
:
4194 aStr
+= rLocWrp
.getNumThousandSep();
4196 case NF_SYMBOLTYPE_DATESEP
:
4197 aStr
+= rLocWrp
.getDateSep();
4199 case NF_SYMBOLTYPE_TIMESEP
:
4200 aStr
+= rLocWrp
.getTimeSep();
4202 case NF_SYMBOLTYPE_TIME100SECSEP
:
4203 aStr
+= rLocWrp
.getTime100SecSep();
4205 case NF_SYMBOLTYPE_STRING
:
4208 else if ( pStr
[j
].Len() == 1 )
4228 for ( ; nSub
<4 && bDefault
[nSub
]; ++nSub
)
4229 { // append empty subformats
4236 String
SvNumberformat::ImpGetNatNumString( const SvNumberNatNum
& rNum
,
4237 sal_Int32 nVal
, USHORT nMinDigits
) const
4242 if ( nMinDigits
== 2 )
4243 { // speed up the most common case
4244 if ( 0 <= nVal
&& nVal
< 10 )
4246 sal_Unicode
* p
= aStr
.AllocBuffer( 2 );
4248 *p
= sal_Unicode( '0' + nVal
);
4251 aStr
= String::CreateFromInt32( nVal
);
4255 String
aValStr( String::CreateFromInt32( nVal
) );
4256 if ( aValStr
.Len() >= nMinDigits
)
4260 aStr
.Fill( nMinDigits
- aValStr
.Len(), '0' );
4266 aStr
= String::CreateFromInt32( nVal
);
4267 ImpTransliterate( aStr
, rNum
);
4272 void SvNumberformat::ImpTransliterateImpl( String
& rStr
,
4273 const SvNumberNatNum
& rNum
) const
4275 com::sun::star::lang::Locale
aLocale(
4276 MsLangId::convertLanguageToLocale( rNum
.GetLang() ) );
4277 rStr
= GetFormatter().GetNatNum()->getNativeNumberString( rStr
,
4278 aLocale
, rNum
.GetNatNum() );
4282 void SvNumberformat::GetNatNumXml(
4283 com::sun::star::i18n::NativeNumberXmlAttributes
& rAttr
,
4284 USHORT nNumFor
) const
4288 const SvNumberNatNum
& rNum
= NumFor
[nNumFor
].GetNatNum();
4291 com::sun::star::lang::Locale
aLocale(
4292 MsLangId::convertLanguageToLocale( rNum
.GetLang() ) );
4293 rAttr
= GetFormatter().GetNatNum()->convertToXmlAttributes(
4294 aLocale
, rNum
.GetNatNum() );
4297 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
4300 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
4304 BOOL
SvNumberformat::HasStringNegativeSign( const String
& rStr
)
4306 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4307 xub_StrLen nLen
= rStr
.Len();
4310 const sal_Unicode
* const pBeg
= rStr
.GetBuffer();
4311 const sal_Unicode
* const pEnd
= pBeg
+ nLen
;
4312 register const sal_Unicode
* p
= pBeg
;
4317 } while ( *p
== ' ' && ++p
< pEnd
);
4323 } while ( *p
== ' ' && pBeg
< --p
);
4329 void SvNumberformat::SetComment( const String
& rStr
, String
& rFormat
,
4332 if ( rComment
.Len() )
4333 { // alten Kommentar aus Formatstring loeschen
4334 //! nicht per EraseComment, der Kommentar muss matchen
4340 xub_StrLen nCom
= 0;
4343 nCom
= rFormat
.Search( aTmp
, nCom
);
4344 } while ( (nCom
!= STRING_NOTFOUND
) && (nCom
+ aTmp
.Len() != rFormat
.Len()) );
4345 if ( nCom
!= STRING_NOTFOUND
)
4346 rFormat
.Erase( nCom
);
4349 { // neuen Kommentar setzen
4361 void SvNumberformat::EraseCommentBraces( String
& rStr
)
4363 xub_StrLen nLen
= rStr
.Len();
4364 if ( nLen
&& rStr
.GetChar(0) == '{' )
4369 if ( nLen
&& rStr
.GetChar(0) == ' ' )
4374 if ( nLen
&& rStr
.GetChar( nLen
-1 ) == '}' )
4375 rStr
.Erase( --nLen
, 1 );
4376 if ( nLen
&& rStr
.GetChar( nLen
-1 ) == ' ' )
4377 rStr
.Erase( --nLen
, 1 );
4382 void SvNumberformat::EraseComment( String
& rStr
)
4384 register const sal_Unicode
* p
= rStr
.GetBuffer();
4385 BOOL bInString
= FALSE
;
4386 BOOL bEscaped
= FALSE
;
4387 BOOL bFound
= FALSE
;
4388 xub_StrLen nPos
= 0;
4389 while ( !bFound
&& *p
)
4394 bEscaped
= !bEscaped
;
4398 bInString
= !bInString
;
4401 if ( !bEscaped
&& !bInString
)
4404 nPos
= sal::static_int_cast
< xub_StrLen
>(
4405 p
- rStr
.GetBuffer());
4409 if ( bEscaped
&& *p
!= '\\' )
4419 BOOL
SvNumberformat::IsInQuote( const String
& rStr
, xub_StrLen nPos
,
4420 sal_Unicode cQuote
, sal_Unicode cEscIn
, sal_Unicode cEscOut
)
4422 xub_StrLen nLen
= rStr
.Len();
4425 register const sal_Unicode
* p0
= rStr
.GetBuffer();
4426 register const sal_Unicode
* p
= p0
;
4427 register const sal_Unicode
* p1
= p0
+ nPos
;
4428 BOOL bQuoted
= FALSE
;
4437 if ( *(p
-1) != cEscIn
)
4442 if ( *(p
-1) != cEscOut
)
4453 xub_StrLen
SvNumberformat::GetQuoteEnd( const String
& rStr
, xub_StrLen nPos
,
4454 sal_Unicode cQuote
, sal_Unicode cEscIn
, sal_Unicode cEscOut
)
4456 xub_StrLen nLen
= rStr
.Len();
4458 return STRING_NOTFOUND
;
4459 if ( !IsInQuote( rStr
, nPos
, cQuote
, cEscIn
, cEscOut
) )
4461 if ( rStr
.GetChar( nPos
) == cQuote
)
4462 return nPos
; // schliessendes cQuote
4463 return STRING_NOTFOUND
;
4465 register const sal_Unicode
* p0
= rStr
.GetBuffer();
4466 register const sal_Unicode
* p
= p0
+ nPos
;
4467 register const sal_Unicode
* p1
= p0
+ nLen
;
4470 if ( *p
== cQuote
&& p
> p0
&& *(p
-1) != cEscIn
)
4471 return sal::static_int_cast
< xub_StrLen
>(p
- p0
);
4474 return nLen
; // String Ende
4478 USHORT
SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor
) const
4481 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
4482 short const * const pType
= NumFor
[nNumFor
].Info().nTypeArray
;
4483 for ( USHORT j
=0; j
<nAnz
; ++j
)
4487 case NF_SYMBOLTYPE_STRING
:
4488 case NF_SYMBOLTYPE_CURRENCY
:
4489 case NF_SYMBOLTYPE_DATESEP
:
4490 case NF_SYMBOLTYPE_TIMESEP
:
4491 case NF_SYMBOLTYPE_TIME100SECSEP
:
4492 case NF_SYMBOLTYPE_PERCENT
: