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::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
1921 ULONG& x2,ULONG& y2)
1923 x2 = ((y0+nPrec)/y1)*x1 - x0;
1924 y2 = ((y0+nPrec)/y1)*y1 - y0;
1927 ULONG
SvNumberformat::ImpGGT(ULONG x
, ULONG y
)
1944 ULONG
SvNumberformat::ImpGGTRound(ULONG x
, ULONG y
)
1951 while ((double)z
/(double)y
> D_EPS
)
1961 BOOL
SvNumberformat::GetOutputString(double fNumber
,
1966 OutString
.Erase(); // alles loeschen
1967 *ppColor
= NULL
; // keine Farbaenderung
1968 if (eType
& NUMBERFORMAT_LOGICAL
)
1971 OutString
= rScan
.GetTrueString();
1973 OutString
= rScan
.GetFalseString();
1976 if (eType
& NUMBERFORMAT_TEXT
&& bStandard
)
1978 ImpGetOutputStandard(fNumber
, OutString
);
1981 BOOL bHadStandard
= FALSE
;
1982 if (bStandard
) // einzelne Standardformate
1984 if (rScan
.GetStandardPrec() == 300) // alle Zahlformate InputLine
1986 ImpGetOutputInputLine(fNumber
, OutString
);
1991 case NUMBERFORMAT_NUMBER
: // Standardzahlformat
1992 ImpGetOutputStandard(fNumber
, OutString
);
1993 bHadStandard
= TRUE
;
1995 case NUMBERFORMAT_DATE
:
1996 bRes
|= ImpGetDateOutput(fNumber
, 0, OutString
);
1997 bHadStandard
= TRUE
;
1999 case NUMBERFORMAT_TIME
:
2000 bRes
|= ImpGetTimeOutput(fNumber
, 0, OutString
);
2001 bHadStandard
= TRUE
;
2003 case NUMBERFORMAT_DATETIME
:
2004 bRes
|= ImpGetDateTimeOutput(fNumber
, 0, OutString
);
2005 bHadStandard
= TRUE
;
2009 if ( !bHadStandard
)
2011 USHORT nIx
; // Index des Teilformats
2012 short nCheck
= ImpCheckCondition(fNumber
, fLimit1
, eOp1
);
2013 if (nCheck
== -1 || nCheck
== 1) // nur 1 String oder True
2017 nCheck
= ImpCheckCondition(fNumber
, fLimit2
, eOp2
);
2018 if (nCheck
== -1 || nCheck
== 1)
2023 if (nIx
== 1 && fNumber
< 0.0 && // negatives Format
2024 IsNegativeRealNegative() ) // ohne Vorzeichen
2025 fNumber
= -fNumber
; // Vorzeichen eliminieren
2026 *ppColor
= NumFor
[nIx
].GetColor();
2027 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2028 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2029 if (nAnz
== 0 && rInfo
.eScannedType
== NUMBERFORMAT_UNDEFINED
)
2030 return FALSE
; // leer => nichts
2031 else if (nAnz
== 0) // sonst Standard-Format
2033 ImpGetOutputStandard(fNumber
, OutString
);
2036 switch (rInfo
.eScannedType
)
2038 case NUMBERFORMAT_TEXT
:
2039 case NUMBERFORMAT_DEFINED
:
2041 for (USHORT i
= 0; i
< nAnz
; i
++)
2043 switch (rInfo
.nTypeArray
[i
])
2045 case NF_SYMBOLTYPE_STAR
:
2048 OutString
+= (sal_Unicode
) 0x1B;
2049 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2053 case NF_SYMBOLTYPE_BLANK
:
2054 InsertBlanks( OutString
, OutString
.Len(),
2055 rInfo
.sStrArray
[i
].GetChar(1) );
2057 case NF_SYMBOLTYPE_STRING
:
2058 case NF_SYMBOLTYPE_CURRENCY
:
2059 OutString
+= rInfo
.sStrArray
[i
];
2061 case NF_SYMBOLTYPE_THSEP
:
2062 if (rInfo
.nThousand
== 0)
2063 OutString
+= rInfo
.sStrArray
[i
];
2071 case NUMBERFORMAT_DATE
:
2072 bRes
|= ImpGetDateOutput(fNumber
, nIx
, OutString
);
2074 case NUMBERFORMAT_TIME
:
2075 bRes
|= ImpGetTimeOutput(fNumber
, nIx
, OutString
);
2077 case NUMBERFORMAT_DATETIME
:
2078 bRes
|= ImpGetDateTimeOutput(fNumber
, nIx
, OutString
);
2080 case NUMBERFORMAT_NUMBER
:
2081 case NUMBERFORMAT_PERCENT
:
2082 case NUMBERFORMAT_CURRENCY
:
2083 bRes
|= ImpGetNumberOutput(fNumber
, nIx
, OutString
);
2085 case NUMBERFORMAT_FRACTION
:
2087 String sStr
, sFrac
, sDiv
; // Strings, Wert fuer
2088 ULONG nFrac
, nDiv
; // Vorkommaanteil
2089 // Zaehler und Nenner
2093 if (nIx
== 0) // nicht in hinteren
2094 bSign
= TRUE
; // Formaten
2097 double fNum
= floor(fNumber
); // Vorkommateil
2098 fNumber
-= fNum
; // Nachkommateil
2099 if (fNum
> _D_MAX_U_LONG_
|| rInfo
.nCntExp
> 9)
2102 OutString
= rScan
.GetErrorString();
2105 if (rInfo
.nCntExp
== 0)
2107 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2110 ULONG nBasis
= ((ULONG
)floor( // 9, 99, 999 ,...
2111 pow(10.0,rInfo
.nCntExp
))) - 1;
2112 ULONG x0
, y0
, x1
, y1
;
2114 if (rInfo
.nCntExp
<= _MAX_FRACTION_PREC
)
2120 fNumber
-= (fNumber
- 0.5) * 2.0;
2124 // Einstieg in Farey-Serie
2126 x0
= (ULONG
) floor(fNumber
*nBasis
); // z.B. 2/9 <= x < 3/9
2127 if (x0
== 0) // => x0 = 2
2133 else if (x0
== (nBasis
-1)/2) // (b-1)/2, 1/2
2134 { // geht (nBasis ungerade)
2141 y0
= nBasis
; // 1/n; 1/(n-1)
2147 y0
= nBasis
; // z.B. 2/9 2/8
2150 double fUg
= (double) x0
/ (double) y0
;
2151 double fOg
= (double) x1
/ (double) y1
;
2152 ULONG nGgt
= ImpGGT(y0
, x0
); // x0/y0 kuerzen
2154 y0
/= nGgt
; // Einschachteln:
2161 // #i21648# GCC over-optimizes something resulting
2162 // in wrong fTest values throughout the loops.
2165 double fTest
= (double)x1
/(double)y1
;
2171 fTest
= (double)x1
/(double)y1
;
2173 while (fTest
< fUg
&& y1
> 1)
2176 fTest
= (double)x1
/(double)y1
;
2186 nGgt
= ImpGGT(y1
, x1
); // x1/y1 kuerzen
2189 if (x2
*y0
- x0
*y2
== 1 || y1
<= 1) // Test, ob x2/y2
2190 bStop
= TRUE
; // naechste Farey-Zahl
2201 flow
= (double)x0
/(double)y0
;
2202 fup
= (double)x1
/(double)y1
;
2203 while (fNumber
> fup
)
2205 ULONG x2
= ((y0
+nBasis
)/y1
)*x1
- x0
; // naechste Farey-Zahl
2206 ULONG y2
= ((y0
+nBasis
)/y1
)*y1
- y0
;
2207 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2213 fup
= (double)x1
/(double)y1
;
2215 if (fNumber
- flow
< fup
- fNumber
)
2225 if (bUpperHalf
) // Original restaur.
2227 if (nFrac
== 0 && nDiv
== 1) // 1/1
2230 nFrac
= nDiv
- nFrac
;
2233 else // grosse Nenner
2234 { // 0,1234->123/1000
2238 nFrac = ((ULONG)floor(0.5 + fNumber *
2239 pow(10.0,rInfo.nCntExp)));
2242 nFrac
= ((ULONG
)floor(0.5 + fNumber
* 10000000.0));
2243 nGgt
= ImpGGT(nDiv
, nFrac
);
2251 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2261 nFrac
= ((ULONG
)floor(0.5 + fNumber
*
2262 pow(10.0,rInfo
.nCntExp
)));
2263 nGgt
= ImpGGTRound(nDiv
, nFrac
);
2272 if (rInfo
.nCntPre
== 0) // unechter Bruch
2274 double fNum1
= fNum
* (double)nDiv
+ (double)nFrac
;
2275 if (fNum1
> _D_MAX_U_LONG_
)
2277 OutString
= rScan
.GetErrorString();
2280 nFrac
= (ULONG
) floor(fNum1
);
2283 else if (fNum
== 0.0 && nFrac
!= 0)
2288 sprintf( aBuf
, "%.f", fNum
); // simple rounded integer (#100211# - checked)
2289 sStr
.AssignAscii( aBuf
);
2290 ImpTransliterate( sStr
, NumFor
[nIx
].GetNatNum() );
2292 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2299 sFrac
= ImpIntToString( nIx
, nFrac
);
2300 sDiv
= ImpIntToString( nIx
, nDiv
);
2303 USHORT j
= nAnz
-1; // letztes Symbol->rueckw.
2304 xub_StrLen k
; // Nenner:
2305 bRes
|= ImpNumberFill(sDiv
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRAC
);
2307 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRAC
)
2309 if (rInfo
.nCntPre
> 0 && nFrac
== 0)
2312 sDiv
.Insert( rInfo
.sStrArray
[j
].GetChar(0), 0 );
2323 bRes
|= ImpNumberFill(sFrac
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_FRACBLANK
);
2324 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_FRACBLANK
)
2326 sFrac
.Insert(rInfo
.sStrArray
[j
],0);
2338 k
= sStr
.Len(); // hinter letzter Ziffer
2339 bRes
|= ImpNumberFillWithThousands(sStr
, fNumber
, k
, j
, nIx
,
2342 if (bSign
&& !(nFrac
== 0 && fNum
== 0.0))
2343 OutString
.Insert('-',0); // nicht -0
2349 case NUMBERFORMAT_SCIENTIFIC
:
2354 if (nIx
== 0) // nicht in hinteren
2355 bSign
= TRUE
; // Formaten
2358 String
sStr( ::rtl::math::doubleToUString( fNumber
,
2359 rtl_math_StringFormat_E
,
2360 rInfo
.nCntPre
+ rInfo
.nCntPost
- 1, '.' ));
2364 xub_StrLen nExPos
= sStr
.Search('E');
2365 if ( nExPos
!= STRING_NOTFOUND
)
2367 // split into mantisse and exponent and get rid of "E+" or "E-"
2368 xub_StrLen nExpStart
= nExPos
+ 1;
2369 switch ( sStr
.GetChar( nExpStart
) )
2378 ExpStr
= sStr
.Copy( nExpStart
); // part following the "E+"
2379 sStr
.Erase( nExPos
);
2380 sStr
.EraseAllChars('.'); // cut any decimal delimiter
2381 if ( rInfo
.nCntPre
!= 1 ) // rescale Exp
2383 sal_Int32 nExp
= ExpStr
.ToInt32() * nExpSign
;
2384 nExp
-= sal_Int32(rInfo
.nCntPre
)-1;
2392 ExpStr
= String::CreateFromInt32( nExp
);
2395 USHORT j
= nAnz
-1; // last symbol
2396 xub_StrLen k
; // position in ExpStr
2397 bRes
|= ImpNumberFill(ExpStr
, fNumber
, k
, j
, nIx
, NF_SYMBOLTYPE_EXP
);
2399 xub_StrLen nZeros
= 0; // erase leading zeros
2400 while (nZeros
< k
&& ExpStr
.GetChar(nZeros
) == '0')
2403 ExpStr
.Erase( 0, nZeros
);
2406 if (rInfo
.nTypeArray
[j
] == NF_SYMBOLTYPE_EXP
)
2408 const String
& rStr
= rInfo
.sStrArray
[j
];
2410 ExpStr
.Insert('-',0);
2411 else if (rStr
.Len() > 1 && rStr
.GetChar(1) == '+')
2412 ExpStr
.Insert('+',0);
2413 ExpStr
.Insert(rStr
.GetChar(0),0);
2419 // weiter Hauptzahl:
2424 k
= sStr
.Len(); // hinter letzter Ziffer
2425 bRes
|= ImpNumberFillWithThousands(sStr
,fNumber
, k
,j
,nIx
,
2432 OutString
+= ExpStr
;
2440 BOOL
SvNumberformat::ImpGetTimeOutput(double fNumber
,
2444 using namespace ::com::sun::star::i18n
;
2445 BOOL bCalendarSet
= FALSE
;
2446 double fNumberOrig
= fNumber
;
2455 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2456 if (rInfo
.bThousand
) // []-Format
2458 if (fNumber
> 1.0E10
) // zu gross
2460 OutString
= rScan
.GetErrorString();
2465 fNumber
-= floor(fNumber
); // sonst Datum abtrennen
2467 xub_StrLen nCntPost
;
2468 if ( rScan
.GetStandardPrec() == 300 &&
2469 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
2470 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2477 nCntPost
= xub_StrLen(rInfo
.nCntPost
);
2479 if (bSign
&& !rInfo
.bThousand
) // kein []-Format
2480 fNumber
= 1.0 - fNumber
; // "Kehrwert"
2481 double fTime
= fNumber
* 86400.0;
2482 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
2483 if (bSign
&& fTime
== 0.0)
2484 bSign
= FALSE
; // nicht -00:00:00
2486 if( floor( fTime
) > _D_MAX_U_LONG_
)
2488 OutString
= rScan
.GetErrorString();
2491 ULONG nSeconds
= (ULONG
)floor( fTime
);
2493 String
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
2494 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
2495 sSecStr
.EraseLeadingChars('0');
2496 sSecStr
.EraseLeadingChars('.');
2499 sSecStr
.EraseTrailingChars('0');
2500 if ( sSecStr
.Len() < xub_StrLen(rInfo
.nCntPost
) )
2501 sSecStr
.Expand( xub_StrLen(rInfo
.nCntPost
), '0' );
2502 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
2503 nCntPost
= sSecStr
.Len();
2506 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
2508 xub_StrLen nSecPos
= 0; // Zum Ziffernweisen
2510 ULONG nHour
, nMin
, nSec
;
2511 if (!rInfo
.bThousand
) // kein [] Format
2513 nHour
= (nSeconds
/3600) % 24;
2514 nMin
= (nSeconds
%3600) / 60;
2517 else if (rInfo
.nThousand
== 3) // [ss]
2523 else if (rInfo
.nThousand
== 2) // [mm]:ss
2526 nMin
= nSeconds
/ 60;
2527 nSec
= nSeconds
% 60;
2529 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
2531 nHour
= nSeconds
/ 3600;
2532 nMin
= (nSeconds
%3600) / 60;
2536 // TODO What should these be set to?
2542 sal_Unicode cAmPm
= ' '; // a oder p
2543 if (rInfo
.nCntExp
) // AM/PM
2550 else if (nHour
< 12)
2559 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2560 for (USHORT i
= 0; i
< nAnz
; i
++)
2562 switch (rInfo
.nTypeArray
[i
])
2564 case NF_SYMBOLTYPE_STAR
:
2567 OutString
+= (sal_Unicode
) 0x1B;
2568 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2572 case NF_SYMBOLTYPE_BLANK
:
2573 InsertBlanks( OutString
, OutString
.Len(),
2574 rInfo
.sStrArray
[i
].GetChar(1) );
2576 case NF_SYMBOLTYPE_STRING
:
2577 case NF_SYMBOLTYPE_CURRENCY
:
2578 case NF_SYMBOLTYPE_DATESEP
:
2579 case NF_SYMBOLTYPE_TIMESEP
:
2580 case NF_SYMBOLTYPE_TIME100SECSEP
:
2581 OutString
+= rInfo
.sStrArray
[i
];
2583 case NF_SYMBOLTYPE_DIGIT
:
2585 xub_StrLen nLen
= ( bInputLine
&& i
> 0 &&
2586 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
2587 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
2588 nCntPost
: rInfo
.sStrArray
[i
].Len() );
2589 for (xub_StrLen j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
2591 OutString
+= sSecStr
.GetChar(nSecPos
);
2596 case NF_KEY_AMPM
: // AM/PM
2598 if ( !bCalendarSet
)
2600 double fDiff
= DateTime(*(rScan
.GetNullDate())) - GetCal().getEpochStart();
2601 fDiff
+= fNumberOrig
;
2602 GetCal().setLocalDateTime( fDiff
);
2603 bCalendarSet
= TRUE
;
2606 OutString
+= GetCal().getDisplayName(
2607 CalendarDisplayIndex::AM_PM
, AmPmValue::AM
, 0 );
2609 OutString
+= GetCal().getDisplayName(
2610 CalendarDisplayIndex::AM_PM
, AmPmValue::PM
, 0 );
2613 case NF_KEY_AP
: // A/P
2621 case NF_KEY_MI
: // M
2622 OutString
+= ImpIntToString( nIx
, nMin
);
2624 case NF_KEY_MMI
: // MM
2625 OutString
+= ImpIntToString( nIx
, nMin
, 2 );
2628 OutString
+= ImpIntToString( nIx
, nHour
);
2630 case NF_KEY_HH
: // HH
2631 OutString
+= ImpIntToString( nIx
, nHour
, 2 );
2634 OutString
+= ImpIntToString( nIx
, nSec
);
2636 case NF_KEY_SS
: // SS
2637 OutString
+= ImpIntToString( nIx
, nSec
, 2 );
2643 if (bSign
&& rInfo
.bThousand
)
2644 OutString
.Insert('-',0);
2649 BOOL
SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor
& rNumFor
) const
2651 if ( GetCal().getUniqueID() != Gregorian::get() )
2653 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
2654 const USHORT nAnz
= rNumFor
.GetnAnz();
2656 for ( i
= 0; i
< nAnz
; i
++ )
2658 switch ( rInfo
.nTypeArray
[i
] )
2660 case NF_SYMBOLTYPE_CALENDAR
:
2675 void SvNumberformat::SwitchToOtherCalendar( String
& rOrgCalendar
,
2676 double& fOrgDateTime
) const
2678 CalendarWrapper
& rCal
= GetCal();
2679 const rtl::OUString
&rGregorian
= Gregorian::get();
2680 if ( rCal
.getUniqueID() == rGregorian
)
2682 using namespace ::com::sun::star::i18n
;
2683 ::com::sun::star::uno::Sequence
< ::rtl::OUString
> xCals
2684 = rCal
.getAllCalendars( rLoc().getLocale() );
2685 sal_Int32 nCnt
= xCals
.getLength();
2688 for ( sal_Int32 j
=0; j
< nCnt
; j
++ )
2690 if ( xCals
[j
] != rGregorian
)
2692 if ( !rOrgCalendar
.Len() )
2694 rOrgCalendar
= rCal
.getUniqueID();
2695 fOrgDateTime
= rCal
.getDateTime();
2697 rCal
.loadCalendar( xCals
[j
], rLoc().getLocale() );
2698 rCal
.setDateTime( fOrgDateTime
);
2707 void SvNumberformat::SwitchToGregorianCalendar( const String
& rOrgCalendar
,
2708 double fOrgDateTime
) const
2710 CalendarWrapper
& rCal
= GetCal();
2711 const rtl::OUString
&rGregorian
= Gregorian::get();
2712 if ( rOrgCalendar
.Len() && rCal
.getUniqueID() != rGregorian
)
2714 rCal
.loadCalendar( rGregorian
, rLoc().getLocale() );
2715 rCal
.setDateTime( fOrgDateTime
);
2720 BOOL
SvNumberformat::ImpFallBackToGregorianCalendar( String
& rOrgCalendar
, double& fOrgDateTime
)
2722 using namespace ::com::sun::star::i18n
;
2723 CalendarWrapper
& rCal
= GetCal();
2724 const rtl::OUString
&rGregorian
= Gregorian::get();
2725 if ( rCal
.getUniqueID() != rGregorian
)
2727 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
2728 if ( nVal
== 0 && rCal
.getLoadedCalendar().Eras
[0].ID
.equalsAsciiL(
2729 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2731 if ( !rOrgCalendar
.Len() )
2733 rOrgCalendar
= rCal
.getUniqueID();
2734 fOrgDateTime
= rCal
.getDateTime();
2736 else if ( rOrgCalendar
== String(rGregorian
) )
2737 rOrgCalendar
.Erase();
2738 rCal
.loadCalendar( rGregorian
, rLoc().getLocale() );
2739 rCal
.setDateTime( fOrgDateTime
);
2747 BOOL
SvNumberformat::ImpSwitchToSpecifiedCalendar( String
& rOrgCalendar
,
2748 double& fOrgDateTime
, const ImpSvNumFor
& rNumFor
) const
2750 const ImpSvNumberformatInfo
& rInfo
= rNumFor
.Info();
2751 const USHORT nAnz
= rNumFor
.GetnAnz();
2752 for ( USHORT i
= 0; i
< nAnz
; i
++ )
2754 if ( rInfo
.nTypeArray
[i
] == NF_SYMBOLTYPE_CALENDAR
)
2756 CalendarWrapper
& rCal
= GetCal();
2757 if ( !rOrgCalendar
.Len() )
2759 rOrgCalendar
= rCal
.getUniqueID();
2760 fOrgDateTime
= rCal
.getDateTime();
2762 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
2763 rCal
.setDateTime( fOrgDateTime
);
2772 void SvNumberformat::ImpAppendEraG( String
& OutString
,
2773 const CalendarWrapper
& rCal
, sal_Int16 nNatNum
)
2775 using namespace ::com::sun::star::i18n
;
2776 if ( rCal
.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2779 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::ERA
);
2782 case 1 : cEra
= 'M'; break;
2783 case 2 : cEra
= 'T'; break;
2784 case 3 : cEra
= 'S'; break;
2785 case 4 : cEra
= 'H'; break;
2792 OutString
+= rCal
.getDisplayString( CalendarDisplayCode::SHORT_ERA
, nNatNum
);
2796 BOOL
SvNumberformat::ImpGetDateOutput(double fNumber
,
2800 using namespace ::com::sun::star::i18n
;
2802 CalendarWrapper
& rCal
= GetCal();
2803 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
2805 rCal
.setLocalDateTime( fNumber
);
2806 String aOrgCalendar
; // empty => not changed yet
2807 double fOrgDateTime
;
2808 BOOL bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
2809 if ( bOtherCalendar
)
2810 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2811 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
2812 bOtherCalendar
= FALSE
;
2813 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2814 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
2815 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
2816 for (USHORT i
= 0; i
< nAnz
; i
++)
2818 switch (rInfo
.nTypeArray
[i
])
2820 case NF_SYMBOLTYPE_CALENDAR
:
2821 if ( !aOrgCalendar
.Len() )
2823 aOrgCalendar
= rCal
.getUniqueID();
2824 fOrgDateTime
= rCal
.getDateTime();
2826 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
2827 rCal
.setDateTime( fOrgDateTime
);
2828 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2830 case NF_SYMBOLTYPE_STAR
:
2833 OutString
+= (sal_Unicode
) 0x1B;
2834 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
2838 case NF_SYMBOLTYPE_BLANK
:
2839 InsertBlanks( OutString
, OutString
.Len(),
2840 rInfo
.sStrArray
[i
].GetChar(1) );
2842 case NF_SYMBOLTYPE_STRING
:
2843 case NF_SYMBOLTYPE_CURRENCY
:
2844 case NF_SYMBOLTYPE_DATESEP
:
2845 case NF_SYMBOLTYPE_TIMESEP
:
2846 case NF_SYMBOLTYPE_TIME100SECSEP
:
2847 OutString
+= rInfo
.sStrArray
[i
];
2850 OutString
+= rCal
.getDisplayString(
2851 CalendarDisplayCode::SHORT_MONTH
, nNatNum
);
2853 case NF_KEY_MM
: // MM
2854 OutString
+= rCal
.getDisplayString(
2855 CalendarDisplayCode::LONG_MONTH
, nNatNum
);
2857 case NF_KEY_MMM
: // MMM
2858 OutString
+= rCal
.getDisplayString(
2859 CalendarDisplayCode::SHORT_MONTH_NAME
, nNatNum
);
2861 case NF_KEY_MMMM
: // MMMM
2862 OutString
+= rCal
.getDisplayString(
2863 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
);
2865 case NF_KEY_MMMMM
: // MMMMM
2866 OutString
+= rCal
.getDisplayString(
2867 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
).GetChar(0);
2870 OutString
+= rCal
.getDisplayString(
2871 CalendarDisplayCode::SHORT_QUARTER
, nNatNum
);
2873 case NF_KEY_QQ
: // QQ
2874 OutString
+= rCal
.getDisplayString(
2875 CalendarDisplayCode::LONG_QUARTER
, nNatNum
);
2878 OutString
+= rCal
.getDisplayString(
2879 CalendarDisplayCode::SHORT_DAY
, nNatNum
);
2881 case NF_KEY_DD
: // DD
2882 OutString
+= rCal
.getDisplayString(
2883 CalendarDisplayCode::LONG_DAY
, nNatNum
);
2885 case NF_KEY_DDD
: // DDD
2887 if ( bOtherCalendar
)
2888 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2889 OutString
+= rCal
.getDisplayString(
2890 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
2891 if ( bOtherCalendar
)
2892 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2895 case NF_KEY_DDDD
: // DDDD
2897 if ( bOtherCalendar
)
2898 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2899 OutString
+= rCal
.getDisplayString(
2900 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2901 if ( bOtherCalendar
)
2902 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2905 case NF_KEY_YY
: // YY
2907 if ( bOtherCalendar
)
2908 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2909 OutString
+= rCal
.getDisplayString(
2910 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
2911 if ( bOtherCalendar
)
2912 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2915 case NF_KEY_YYYY
: // YYYY
2917 if ( bOtherCalendar
)
2918 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
2919 OutString
+= rCal
.getDisplayString(
2920 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
2921 if ( bOtherCalendar
)
2922 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
2925 case NF_KEY_EC
: // E
2926 OutString
+= rCal
.getDisplayString(
2927 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
2929 case NF_KEY_EEC
: // EE
2931 OutString
+= rCal
.getDisplayString(
2932 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
2934 case NF_KEY_NN
: // NN
2935 case NF_KEY_AAA
: // AAA
2936 OutString
+= rCal
.getDisplayString(
2937 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
2939 case NF_KEY_NNN
: // NNN
2940 case NF_KEY_AAAA
: // AAAA
2941 OutString
+= rCal
.getDisplayString(
2942 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2944 case NF_KEY_NNNN
: // NNNN
2946 OutString
+= rCal
.getDisplayString(
2947 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
2948 OutString
+= rLoc().getLongDateDayOfWeekSep();
2951 case NF_KEY_WW
: // WW
2953 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
);
2954 OutString
+= ImpIntToString( nIx
, nVal
);
2958 ImpAppendEraG( OutString
, rCal
, nNatNum
);
2960 case NF_KEY_GG
: // GG
2961 OutString
+= rCal
.getDisplayString(
2962 CalendarDisplayCode::SHORT_ERA
, nNatNum
);
2964 case NF_KEY_GGG
: // GGG
2965 OutString
+= rCal
.getDisplayString(
2966 CalendarDisplayCode::LONG_ERA
, nNatNum
);
2968 case NF_KEY_RR
: // RR => GGGEE
2969 OutString
+= rCal
.getDisplayString(
2970 CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
);
2974 if ( aOrgCalendar
.Len() )
2975 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLocale() ); // restore calendar
2979 BOOL
SvNumberformat::ImpGetDateTimeOutput(double fNumber
,
2983 using namespace ::com::sun::star::i18n
;
2986 CalendarWrapper
& rCal
= GetCal();
2987 double fDiff
= DateTime(*(rScan
.GetNullDate())) - rCal
.getEpochStart();
2990 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
2992 xub_StrLen nCntPost
;
2993 if ( rScan
.GetStandardPrec() == 300 &&
2994 0 < rInfo
.nCntPost
&& rInfo
.nCntPost
< 7 )
2995 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
3002 nCntPost
= xub_StrLen(rInfo
.nCntPost
);
3004 double fTime
= (fNumber
- floor( fNumber
)) * 86400.0;
3005 fTime
= ::rtl::math::round( fTime
, int(nCntPost
) );
3006 if (fTime
>= 86400.0)
3008 // result of fNumber==x.999999999... rounded up, use correct date/time
3010 fNumber
= floor( fNumber
+ 0.5) + fTime
;
3012 rCal
.setLocalDateTime( fNumber
);
3014 String aOrgCalendar
; // empty => not changed yet
3015 double fOrgDateTime
;
3016 BOOL bOtherCalendar
= ImpIsOtherCalendar( NumFor
[nIx
] );
3017 if ( bOtherCalendar
)
3018 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3019 if ( ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
) )
3020 bOtherCalendar
= FALSE
;
3021 sal_Int16 nNatNum
= NumFor
[nIx
].GetNatNum().GetNatNum();
3023 ULONG nSeconds
= (ULONG
)floor( fTime
);
3024 String
sSecStr( ::rtl::math::doubleToUString( fTime
-nSeconds
,
3025 rtl_math_StringFormat_F
, int(nCntPost
), '.'));
3026 sSecStr
.EraseLeadingChars('0');
3027 sSecStr
.EraseLeadingChars('.');
3030 sSecStr
.EraseTrailingChars('0');
3031 if ( sSecStr
.Len() < xub_StrLen(rInfo
.nCntPost
) )
3032 sSecStr
.Expand( xub_StrLen(rInfo
.nCntPost
), '0' );
3033 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
3034 nCntPost
= sSecStr
.Len();
3037 ImpTransliterate( sSecStr
, NumFor
[nIx
].GetNatNum() );
3039 xub_StrLen nSecPos
= 0; // Zum Ziffernweisen
3041 ULONG nHour
, nMin
, nSec
;
3042 if (!rInfo
.bThousand
) // [] Format
3044 nHour
= (nSeconds
/3600) % 24;
3045 nMin
= (nSeconds
%3600) / 60;
3048 else if (rInfo
.nThousand
== 3) // [ss]
3054 else if (rInfo
.nThousand
== 2) // [mm]:ss
3057 nMin
= nSeconds
/ 60;
3058 nSec
= nSeconds
% 60;
3060 else if (rInfo
.nThousand
== 1) // [hh]:mm:ss
3062 nHour
= nSeconds
/ 3600;
3063 nMin
= (nSeconds
%3600) / 60;
3067 nHour
= 0; // TODO What should these values be?
3071 sal_Unicode cAmPm
= ' '; // a oder p
3072 if (rInfo
.nCntExp
) // AM/PM
3079 else if (nHour
< 12)
3088 const USHORT nAnz
= NumFor
[nIx
].GetnAnz();
3089 for (USHORT i
= 0; i
< nAnz
; i
++)
3091 switch (rInfo
.nTypeArray
[i
])
3093 case NF_SYMBOLTYPE_CALENDAR
:
3094 if ( !aOrgCalendar
.Len() )
3096 aOrgCalendar
= rCal
.getUniqueID();
3097 fOrgDateTime
= rCal
.getDateTime();
3099 rCal
.loadCalendar( rInfo
.sStrArray
[i
], rLoc().getLocale() );
3100 rCal
.setDateTime( fOrgDateTime
);
3101 ImpFallBackToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3103 case NF_SYMBOLTYPE_STAR
:
3106 OutString
+= (sal_Unicode
) 0x1B;
3107 OutString
+= rInfo
.sStrArray
[i
].GetChar(1);
3111 case NF_SYMBOLTYPE_BLANK
:
3112 InsertBlanks( OutString
, OutString
.Len(),
3113 rInfo
.sStrArray
[i
].GetChar(1) );
3115 case NF_SYMBOLTYPE_STRING
:
3116 case NF_SYMBOLTYPE_CURRENCY
:
3117 case NF_SYMBOLTYPE_DATESEP
:
3118 case NF_SYMBOLTYPE_TIMESEP
:
3119 case NF_SYMBOLTYPE_TIME100SECSEP
:
3120 OutString
+= rInfo
.sStrArray
[i
];
3122 case NF_SYMBOLTYPE_DIGIT
:
3124 xub_StrLen nLen
= ( bInputLine
&& i
> 0 &&
3125 (rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_STRING
||
3126 rInfo
.nTypeArray
[i
-1] == NF_SYMBOLTYPE_TIME100SECSEP
) ?
3127 nCntPost
: rInfo
.sStrArray
[i
].Len() );
3128 for (xub_StrLen j
= 0; j
< nLen
&& nSecPos
< nCntPost
; j
++)
3130 OutString
+= sSecStr
.GetChar(nSecPos
);
3135 case NF_KEY_AMPM
: // AM/PM
3138 OutString
+= rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3141 OutString
+= rCal
.getDisplayName( CalendarDisplayIndex::AM_PM
,
3145 case NF_KEY_AP
: // A/P
3153 case NF_KEY_MI
: // M
3154 OutString
+= ImpIntToString( nIx
, nMin
);
3156 case NF_KEY_MMI
: // MM
3157 OutString
+= ImpIntToString( nIx
, nMin
, 2 );
3160 OutString
+= ImpIntToString( nIx
, nHour
);
3162 case NF_KEY_HH
: // HH
3163 OutString
+= ImpIntToString( nIx
, nHour
, 2 );
3166 OutString
+= ImpIntToString( nIx
, nSec
);
3168 case NF_KEY_SS
: // SS
3169 OutString
+= ImpIntToString( nIx
, nSec
, 2 );
3172 OutString
+= rCal
.getDisplayString(
3173 CalendarDisplayCode::SHORT_MONTH
, nNatNum
);
3175 case NF_KEY_MM
: // MM
3176 OutString
+= rCal
.getDisplayString(
3177 CalendarDisplayCode::LONG_MONTH
, nNatNum
);
3179 case NF_KEY_MMM
: // MMM
3180 OutString
+= rCal
.getDisplayString(
3181 CalendarDisplayCode::SHORT_MONTH_NAME
, nNatNum
);
3183 case NF_KEY_MMMM
: // MMMM
3184 OutString
+= rCal
.getDisplayString(
3185 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
);
3187 case NF_KEY_MMMMM
: // MMMMM
3188 OutString
+= rCal
.getDisplayString(
3189 CalendarDisplayCode::LONG_MONTH_NAME
, nNatNum
).GetChar(0);
3192 OutString
+= rCal
.getDisplayString(
3193 CalendarDisplayCode::SHORT_QUARTER
, nNatNum
);
3195 case NF_KEY_QQ
: // QQ
3196 OutString
+= rCal
.getDisplayString(
3197 CalendarDisplayCode::LONG_QUARTER
, nNatNum
);
3200 OutString
+= rCal
.getDisplayString(
3201 CalendarDisplayCode::SHORT_DAY
, nNatNum
);
3203 case NF_KEY_DD
: // DD
3204 OutString
+= rCal
.getDisplayString(
3205 CalendarDisplayCode::LONG_DAY
, nNatNum
);
3207 case NF_KEY_DDD
: // DDD
3209 if ( bOtherCalendar
)
3210 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3211 OutString
+= rCal
.getDisplayString(
3212 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
3213 if ( bOtherCalendar
)
3214 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3217 case NF_KEY_DDDD
: // DDDD
3219 if ( bOtherCalendar
)
3220 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3221 OutString
+= rCal
.getDisplayString(
3222 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3223 if ( bOtherCalendar
)
3224 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3227 case NF_KEY_YY
: // YY
3229 if ( bOtherCalendar
)
3230 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3231 OutString
+= rCal
.getDisplayString(
3232 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
3233 if ( bOtherCalendar
)
3234 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3237 case NF_KEY_YYYY
: // YYYY
3239 if ( bOtherCalendar
)
3240 SwitchToGregorianCalendar( aOrgCalendar
, fOrgDateTime
);
3241 OutString
+= rCal
.getDisplayString(
3242 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3243 if ( bOtherCalendar
)
3244 SwitchToOtherCalendar( aOrgCalendar
, fOrgDateTime
);
3247 case NF_KEY_EC
: // E
3248 OutString
+= rCal
.getDisplayString(
3249 CalendarDisplayCode::SHORT_YEAR
, nNatNum
);
3251 case NF_KEY_EEC
: // EE
3253 OutString
+= rCal
.getDisplayString(
3254 CalendarDisplayCode::LONG_YEAR
, nNatNum
);
3256 case NF_KEY_NN
: // NN
3257 case NF_KEY_AAA
: // AAA
3258 OutString
+= rCal
.getDisplayString(
3259 CalendarDisplayCode::SHORT_DAY_NAME
, nNatNum
);
3261 case NF_KEY_NNN
: // NNN
3262 case NF_KEY_AAAA
: // AAAA
3263 OutString
+= rCal
.getDisplayString(
3264 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3266 case NF_KEY_NNNN
: // NNNN
3268 OutString
+= rCal
.getDisplayString(
3269 CalendarDisplayCode::LONG_DAY_NAME
, nNatNum
);
3270 OutString
+= rLoc().getLongDateDayOfWeekSep();
3273 case NF_KEY_WW
: // WW
3275 sal_Int16 nVal
= rCal
.getValue( CalendarFieldIndex::WEEK_OF_YEAR
);
3276 OutString
+= ImpIntToString( nIx
, nVal
);
3280 ImpAppendEraG( OutString
, rCal
, nNatNum
);
3282 case NF_KEY_GG
: // GG
3283 OutString
+= rCal
.getDisplayString(
3284 CalendarDisplayCode::SHORT_ERA
, nNatNum
);
3286 case NF_KEY_GGG
: // GGG
3287 OutString
+= rCal
.getDisplayString(
3288 CalendarDisplayCode::LONG_ERA
, nNatNum
);
3290 case NF_KEY_RR
: // RR => GGGEE
3291 OutString
+= rCal
.getDisplayString(
3292 CalendarDisplayCode::LONG_YEAR_AND_ERA
, nNatNum
);
3296 if ( aOrgCalendar
.Len() )
3297 rCal
.loadCalendar( aOrgCalendar
, rLoc().getLocale() ); // restore calendar
3301 BOOL
SvNumberformat::ImpGetNumberOutput(double fNumber
,
3309 if (nIx
== 0) // nicht in hinteren
3310 bSign
= TRUE
; // Formaten
3318 if ( ::rtl::math::isSignBitSet( fNumber
) )
3319 fNumber
= -fNumber
; // yes, -0.0 is possible, eliminate '-'
3321 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3322 if (rInfo
.eScannedType
== NUMBERFORMAT_PERCENT
)
3324 if (fNumber
< _D_MAX_D_BY_100
)
3328 OutString
= rScan
.GetErrorString();
3336 BOOL bInteger
= FALSE
;
3337 if ( rInfo
.nThousand
!= FLAG_STANDARD_IN_FORMAT
)
3338 { // special formatting only if no GENERAL keyword in format code
3339 const USHORT nThousand
= rInfo
.nThousand
;
3340 for (i
= 0; i
< nThousand
; i
++)
3342 if (fNumber
> _D_MIN_M_BY_1000
)
3348 nPrecExp
= GetPrecExp( fNumber
);
3351 if (rInfo
.nCntPost
) // NachkommaStellen
3353 if (rInfo
.nCntPost
+ nPrecExp
> 15 && nPrecExp
< 15)
3355 sStr
= ::rtl::math::doubleToUString( fNumber
,
3356 rtl_math_StringFormat_F
, 15-nPrecExp
, '.');
3357 for (long l
= 15-nPrecExp
; l
< (long) rInfo
.nCntPost
; l
++)
3361 sStr
= ::rtl::math::doubleToUString( fNumber
,
3362 rtl_math_StringFormat_F
, rInfo
.nCntPost
, '.' );
3363 sStr
.EraseLeadingChars('0'); // fuehrende Nullen weg
3365 else if (fNumber
== 0.0) // Null
3367 // nothing to be done here, keep empty string sStr,
3368 // ImpNumberFillWithThousands does the rest
3372 sStr
= ::rtl::math::doubleToUString( fNumber
,
3373 rtl_math_StringFormat_F
, 0, '.');
3374 sStr
.EraseLeadingChars('0'); // fuehrende Nullen weg
3376 xub_StrLen nPoint
= sStr
.Search( '.' );
3377 if ( nPoint
!= STRING_NOTFOUND
)
3379 register const sal_Unicode
* p
= sStr
.GetBuffer() + nPoint
;
3380 while ( *++p
== '0' )
3384 sStr
.Erase( nPoint
, 1 ); // . herausnehmen
3387 (sStr
.Len() == 0 || sStr
.GetTokenCount('0') == sStr
.Len()+1)) // nur 00000
3388 bSign
= FALSE
; // nicht -0.00
3389 } // End of != FLAG_STANDARD_IN_FORMAT
3391 // von hinten nach vorn
3393 k
= sStr
.Len(); // hinter letzter Ziffer
3394 j
= NumFor
[nIx
].GetnAnz()-1; // letztes Symbol
3395 // Nachkommastellen:
3396 if (rInfo
.nCntPost
> 0)
3398 BOOL bTrailing
= TRUE
; // ob Endnullen?
3399 BOOL bFilled
= FALSE
; // ob aufgefuellt wurde ?
3401 while (j
> 0 && // rueckwaerts
3402 (nType
= rInfo
.nTypeArray
[j
]) != NF_SYMBOLTYPE_DECSEP
)
3406 case NF_SYMBOLTYPE_STAR
:
3409 sStr
.Insert( (sal_Unicode
) 0x1B, k
/*++*/ );
3410 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3414 case NF_SYMBOLTYPE_BLANK
:
3415 /*k = */ InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3417 case NF_SYMBOLTYPE_STRING
:
3418 case NF_SYMBOLTYPE_CURRENCY
:
3419 case NF_SYMBOLTYPE_PERCENT
:
3420 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3422 case NF_SYMBOLTYPE_THSEP
:
3423 if (rInfo
.nThousand
== 0)
3424 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3426 case NF_SYMBOLTYPE_DIGIT
:
3428 const String
& rStr
= rInfo
.sStrArray
[j
];
3429 const sal_Unicode
* p1
= rStr
.GetBuffer();
3430 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3433 const sal_Unicode c
= *p
;
3435 if ( sStr
.GetChar(k
) != '0' )
3441 else if ( c
== '-' )
3444 sStr
.SetChar( k
, '-' );
3447 else if ( c
== '?' )
3449 sStr
.SetChar( k
, ' ' );
3452 else if ( !bFilled
) // #
3458 case NF_KEY_CCC
: // CCC-Waehrung
3459 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3461 case NF_KEY_GENERAL
: // Standard im String
3464 ImpGetOutputStandard(fNumber
, sNum
);
3465 sNum
.EraseLeadingChars('-');
3466 sStr
.Insert(sNum
, k
);
3476 bRes
|= ImpNumberFillWithThousands(sStr
, fNumber
, k
, j
, nIx
, // ggfs Auffuellen mit .
3478 if ( rInfo
.nCntPost
> 0 )
3480 const String
& rDecSep
= GetFormatter().GetNumDecimalSep();
3481 xub_StrLen nLen
= rDecSep
.Len();
3482 if ( sStr
.Len() > nLen
&& sStr
.Equals( rDecSep
, sStr
.Len() - nLen
, nLen
) )
3483 sStr
.Erase( sStr
.Len() - nLen
); // no decimals => strip DecSep
3487 ImpTransliterate( sStr
, NumFor
[nIx
].GetNatNum() );
3492 BOOL
SvNumberformat::ImpNumberFillWithThousands(
3493 String
& sStr
, // number string
3494 double& rNumber
, // number
3495 xub_StrLen k
, // position within string
3496 USHORT j
, // symbol index within format code
3497 USHORT nIx
, // subformat index
3498 USHORT nDigCnt
) // count of integer digits in format
3501 xub_StrLen nLeadingStringChars
= 0; // inserted StringChars before number
3502 xub_StrLen nDigitCount
= 0; // count of integer digits from the right
3504 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3505 // no normal thousands separators if number divided by thousands
3506 BOOL bDoThousands
= (rInfo
.nThousand
== 0);
3507 utl::DigitGroupingIterator
aGrouping(
3508 GetFormatter().GetLocaleData()->getDigitGrouping());
3509 while (!bStop
) // backwards
3513 switch (rInfo
.nTypeArray
[j
])
3515 case NF_SYMBOLTYPE_DECSEP
:
3518 case NF_SYMBOLTYPE_STRING
:
3519 case NF_SYMBOLTYPE_CURRENCY
:
3520 case NF_SYMBOLTYPE_PERCENT
:
3521 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3523 nLeadingStringChars
=
3524 nLeadingStringChars
+ rInfo
.sStrArray
[j
].Len();
3526 case NF_SYMBOLTYPE_STAR
:
3529 sStr
.Insert( (sal_Unicode
) 0x1B, k
/*++*/ );
3530 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3534 case NF_SYMBOLTYPE_BLANK
:
3535 /*k = */ InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3537 case NF_SYMBOLTYPE_THSEP
:
3539 // #i7284# #102685# Insert separator also if number is divided
3540 // by thousands and the separator is specified somewhere in
3541 // between and not only at the end.
3542 // #i12596# But do not insert if it's a parenthesized negative
3544 // In fact, do not insert if divided and regex [0#,],[^0#] and
3545 // no other digit symbol follows (which was already detected
3546 // during scan of format code, otherwise there would be no
3547 // division), else do insert. Same in ImpNumberFill() below.
3548 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetnAnz()-1 )
3549 bDoThousands
= ((j
== 0) ||
3550 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
3551 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
3552 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
3556 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3557 else if (nDigitCount
< nDigCnt
)
3559 // Leading '#' displays nothing (e.g. no leading
3560 // separator for numbers <1000 with #,##0 format).
3561 // Leading '?' displays blank.
3562 // Everything else, including nothing, displays the
3564 sal_Unicode cLeader
= 0;
3565 if (j
> 0 && rInfo
.nTypeArray
[j
-1] == NF_SYMBOLTYPE_DIGIT
)
3567 const String
& rStr
= rInfo
.sStrArray
[j
-1];
3568 xub_StrLen nLen
= rStr
.Len();
3570 cLeader
= rStr
.GetChar(nLen
-1);
3578 // erAck: 2008-04-03T16:24+0200
3579 // Actually this currently isn't executed
3580 // because the format scanner in the context of
3581 // "?," doesn't generate a group separator but
3582 // a literal ',' character instead that is
3583 // inserted unconditionally. Should be changed
3584 // on some occasion.
3588 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3591 aGrouping
.advance();
3595 case NF_SYMBOLTYPE_DIGIT
:
3597 const String
& rStr
= rInfo
.sStrArray
[j
];
3598 const sal_Unicode
* p1
= rStr
.GetBuffer();
3599 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3617 if (nDigitCount
== nDigCnt
&& k
> 0)
3618 { // more digits than specified
3619 ImpDigitFill(sStr
, 0, k
, nIx
, nDigitCount
, aGrouping
);
3624 case NF_KEY_CCC
: // CCC currency
3625 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3627 case NF_KEY_GENERAL
: // "General" in string
3630 ImpGetOutputStandard(rNumber
, sNum
);
3631 sNum
.EraseLeadingChars('-');
3632 sStr
.Insert(sNum
, k
);
3639 j
--; // next format code string
3641 k
= k
+ nLeadingStringChars
; // MSC converts += to int and then warns, so ...
3642 if (k
> nLeadingStringChars
)
3643 ImpDigitFill(sStr
, nLeadingStringChars
, k
, nIx
, nDigitCount
, aGrouping
);
3647 void SvNumberformat::ImpDigitFill(
3648 String
& sStr
, // number string
3649 xub_StrLen nStart
, // start of digits
3650 xub_StrLen
& k
, // position within string
3651 USHORT nIx
, // subformat index
3652 xub_StrLen
& nDigitCount
, // count of integer digits from the right so far
3653 utl::DigitGroupingIterator
& rGrouping
) // current grouping
3655 if (NumFor
[nIx
].Info().bThousand
) // only if grouping
3656 { // fill in separators
3657 const String
& rThousandSep
= GetFormatter().GetNumThousandSep();
3660 if (nDigitCount
== rGrouping
.getPos())
3662 sStr
.Insert( rThousandSep
, k
);
3663 rGrouping
.advance();
3673 BOOL
SvNumberformat::ImpNumberFill( String
& sStr
, // number string
3674 double& rNumber
, // number for "General" format
3675 xub_StrLen
& k
, // position within string
3676 USHORT
& j
, // symbol index within format code
3677 USHORT nIx
, // subformat index
3678 short eSymbolType
) // type of stop condition
3681 k
= sStr
.Len(); // behind last digit
3682 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nIx
].Info();
3683 // no normal thousands separators if number divided by thousands
3684 BOOL bDoThousands
= (rInfo
.nThousand
== 0);
3686 while (j
> 0 && (nType
= rInfo
.nTypeArray
[j
]) != eSymbolType
)
3690 case NF_SYMBOLTYPE_STAR
:
3693 sStr
.Insert( sal_Unicode(0x1B), k
++ );
3694 sStr
.Insert(rInfo
.sStrArray
[j
].GetChar(1),k
);
3698 case NF_SYMBOLTYPE_BLANK
:
3699 k
= InsertBlanks( sStr
,k
,rInfo
.sStrArray
[j
].GetChar(1) );
3701 case NF_SYMBOLTYPE_THSEP
:
3703 // Same as in ImpNumberFillWithThousands() above, do not insert
3704 // if divided and regex [0#,],[^0#] and no other digit symbol
3705 // follows (which was already detected during scan of format
3706 // code, otherwise there would be no division), else do insert.
3707 if ( !bDoThousands
&& j
< NumFor
[nIx
].GetnAnz()-1 )
3708 bDoThousands
= ((j
== 0) ||
3709 (rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_DIGIT
&&
3710 rInfo
.nTypeArray
[j
-1] != NF_SYMBOLTYPE_THSEP
) ||
3711 (rInfo
.nTypeArray
[j
+1] == NF_SYMBOLTYPE_DIGIT
));
3712 if ( bDoThousands
&& k
> 0 )
3714 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3718 case NF_SYMBOLTYPE_DIGIT
:
3720 const String
& rStr
= rInfo
.sStrArray
[j
];
3721 const sal_Unicode
* p1
= rStr
.GetBuffer();
3722 register const sal_Unicode
* p
= p1
+ rStr
.Len();
3742 case NF_KEY_CCC
: // CCC-Waehrung
3743 sStr
.Insert(rScan
.GetCurAbbrev(), k
);
3745 case NF_KEY_GENERAL
: // Standard im String
3748 ImpGetOutputStandard(rNumber
, sNum
);
3749 sNum
.EraseLeadingChars('-'); // Vorzeichen weg!!
3750 sStr
.Insert(sNum
, k
);
3755 sStr
.Insert(rInfo
.sStrArray
[j
],k
);
3758 j
--; // naechster String
3763 void SvNumberformat::GetFormatSpecialInfo(BOOL
& bThousand
,
3766 USHORT
& nAnzLeading
) const
3768 // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3771 GetNumForInfo( 0, nDummyType
, bThousand
, nPrecision
, nAnzLeading
);
3773 // "negative in red" is only useful for the whole format
3775 const Color
* pColor
= NumFor
[1].GetColor();
3776 if (fLimit1
== 0.0 && fLimit2
== 0.0 && pColor
3777 && (*pColor
== rScan
.GetRedColor()))
3783 void SvNumberformat::GetNumForInfo( USHORT nNumFor
, short& rScannedType
,
3784 BOOL
& bThousand
, USHORT
& nPrecision
, USHORT
& nAnzLeading
) const
3786 // take info from a specified sub-format (for XML export)
3791 const ImpSvNumberformatInfo
& rInfo
= NumFor
[nNumFor
].Info();
3792 rScannedType
= rInfo
.eScannedType
;
3793 bThousand
= rInfo
.bThousand
;
3794 nPrecision
= rInfo
.nCntPost
;
3795 if (bStandard
&& rInfo
.eScannedType
== NUMBERFORMAT_NUMBER
)
3803 const USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3804 while (!bStop
&& i
< nAnz
)
3806 short nType
= rInfo
.nTypeArray
[i
];
3807 if ( nType
== NF_SYMBOLTYPE_DIGIT
)
3809 register const sal_Unicode
* p
= rInfo
.sStrArray
[i
].GetBuffer();
3812 while ( *p
++ == '0' )
3815 else if (nType
== NF_SYMBOLTYPE_DECSEP
|| nType
== NF_SYMBOLTYPE_EXP
)
3822 const String
* SvNumberformat::GetNumForString( USHORT nNumFor
, USHORT nPos
,
3823 BOOL bString
/* = FALSE */ ) const
3827 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3830 if ( nPos
== 0xFFFF )
3835 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3836 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3837 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3842 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3846 else if ( nPos
> nAnz
- 1 )
3850 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3851 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3852 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3857 if ( nPos
>= nAnz
|| ((*pType
!= NF_SYMBOLTYPE_STRING
) &&
3858 (*pType
!= NF_SYMBOLTYPE_CURRENCY
)) )
3861 return &NumFor
[nNumFor
].Info().sStrArray
[nPos
];
3865 short SvNumberformat::GetNumForType( USHORT nNumFor
, USHORT nPos
,
3866 BOOL bString
/* = FALSE */ ) const
3870 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
3873 if ( nPos
== 0xFFFF )
3878 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3879 while ( nPos
> 0 && (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3880 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3885 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3889 else if ( nPos
> nAnz
- 1 )
3893 short* pType
= NumFor
[nNumFor
].Info().nTypeArray
+ nPos
;
3894 while ( nPos
< nAnz
&& (*pType
!= NF_SYMBOLTYPE_STRING
) &&
3895 (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3900 if ( (*pType
!= NF_SYMBOLTYPE_STRING
) && (*pType
!= NF_SYMBOLTYPE_CURRENCY
) )
3903 return NumFor
[nNumFor
].Info().nTypeArray
[nPos
];
3907 BOOL
SvNumberformat::IsNegativeWithoutSign() const
3909 if ( IsNegativeRealNegative() )
3911 const String
* pStr
= GetNumForString( 1, 0, TRUE
);
3913 return !HasStringNegativeSign( *pStr
);
3919 DateFormat
SvNumberformat::GetDateOrder() const
3921 if ( (eType
& NUMBERFORMAT_DATE
) == NUMBERFORMAT_DATE
)
3923 short const * const pType
= NumFor
[0].Info().nTypeArray
;
3924 USHORT nAnz
= NumFor
[0].GetnAnz();
3925 for ( USHORT j
=0; j
<nAnz
; j
++ )
3950 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
3952 return rLoc().getDateFormat();
3956 sal_uInt32
SvNumberformat::GetExactDateOrder() const
3958 sal_uInt32 nRet
= 0;
3959 if ( (eType
& NUMBERFORMAT_DATE
) != NUMBERFORMAT_DATE
)
3961 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
3964 short const * const pType
= NumFor
[0].Info().nTypeArray
;
3965 USHORT nAnz
= NumFor
[0].GetnAnz();
3967 for ( USHORT j
=0; j
<nAnz
&& nShift
< 3; j
++ )
3973 nRet
= (nRet
<< 8) | 'D';
3981 nRet
= (nRet
<< 8) | 'M';
3990 nRet
= (nRet
<< 8) | 'Y';
3999 void SvNumberformat::GetConditions( SvNumberformatLimitOps
& rOper1
, double& rVal1
,
4000 SvNumberformatLimitOps
& rOper2
, double& rVal2
) const
4009 Color
* SvNumberformat::GetColor( USHORT nNumFor
) const
4014 return NumFor
[nNumFor
].GetColor();
4018 void lcl_SvNumberformat_AddLimitStringImpl( String
& rStr
,
4019 SvNumberformatLimitOps eOp
, double fLimit
, const String
& rDecSep
)
4021 if ( eOp
!= NUMBERFORMAT_OP_NO
)
4025 case NUMBERFORMAT_OP_EQ
:
4026 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4028 case NUMBERFORMAT_OP_NE
:
4029 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4031 case NUMBERFORMAT_OP_LT
:
4032 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4034 case NUMBERFORMAT_OP_LE
:
4035 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4037 case NUMBERFORMAT_OP_GT
:
4038 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4040 case NUMBERFORMAT_OP_GE
:
4041 rStr
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4044 OSL_ASSERT( "unsupported number format" );
4047 rStr
+= String( ::rtl::math::doubleToUString( fLimit
,
4048 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
4049 rDecSep
.GetChar(0), sal_True
));
4055 String
SvNumberformat::GetMappedFormatstring(
4056 const NfKeywordTable
& rKeywords
, const LocaleDataWrapper
& rLocWrp
,
4057 BOOL bDontQuote
) const
4061 // 1 subformat matches all if no condition specified,
4062 bDefault
[0] = ( NumFor
[1].GetnAnz() == 0 && eOp1
== NUMBERFORMAT_OP_NO
);
4063 // with 2 subformats [>=0];[<0] is implied if no condition specified
4064 bDefault
[1] = ( !bDefault
[0] && NumFor
[2].GetnAnz() == 0 &&
4065 eOp1
== NUMBERFORMAT_OP_GE
&& fLimit1
== 0.0 &&
4066 eOp2
== NUMBERFORMAT_OP_NO
&& fLimit2
== 0.0 );
4067 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4068 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4069 bDefault
[2] = ( !bDefault
[0] && !bDefault
[1] &&
4070 eOp1
== NUMBERFORMAT_OP_GT
&& fLimit1
== 0.0 &&
4071 eOp2
== NUMBERFORMAT_OP_LT
&& fLimit2
== 0.0 );
4072 BOOL bDefaults
= bDefault
[0] || bDefault
[1] || bDefault
[2];
4073 // from now on bDefault[] values are used to append empty subformats at the end
4074 bDefault
[3] = FALSE
;
4076 { // conditions specified
4077 if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
== NUMBERFORMAT_OP_NO
)
4078 bDefault
[0] = bDefault
[1] = TRUE
; // [];x
4079 else if ( eOp1
!= NUMBERFORMAT_OP_NO
&& eOp2
!= NUMBERFORMAT_OP_NO
&&
4080 NumFor
[2].GetnAnz() == 0 )
4081 bDefault
[0] = bDefault
[1] = bDefault
[2] = bDefault
[3] = TRUE
; // [];[];;
4082 // nothing to do if conditions specified for every subformat
4084 else if ( bDefault
[0] )
4085 bDefault
[0] = FALSE
; // a single unconditional subformat is never delimited
4088 if ( bDefault
[2] && NumFor
[2].GetnAnz() == 0 && NumFor
[1].GetnAnz() > 0 )
4089 bDefault
[3] = TRUE
; // special cases x;x;; and ;x;;
4090 for ( int i
=0; i
<3 && !bDefault
[i
]; ++i
)
4093 int nSem
= 0; // needed ';' delimiters
4094 int nSub
= 0; // subformats delimited so far
4095 for ( int n
=0; n
<4; n
++ )
4107 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp1
,
4108 fLimit1
, rLocWrp
.getNumDecimalSep() );
4111 lcl_SvNumberformat_AddLimitStringImpl( aPrefix
, eOp2
,
4112 fLimit2
, rLocWrp
.getNumDecimalSep() );
4117 const String
& rColorName
= NumFor
[n
].GetColorName();
4118 if ( rColorName
.Len() )
4120 const String
* pKey
= rScan
.GetKeywords() + NF_KEY_FIRSTCOLOR
;
4121 for ( int j
=NF_KEY_FIRSTCOLOR
; j
<=NF_KEY_LASTCOLOR
; j
++, pKey
++ )
4123 if ( *pKey
== rColorName
)
4126 aPrefix
+= rKeywords
[j
];
4133 const SvNumberNatNum
& rNum
= NumFor
[n
].GetNatNum();
4134 // The Thai T NatNum modifier during Xcl export.
4135 if (rNum
.IsSet() && rNum
.GetNatNum() == 1 &&
4136 rKeywords
[NF_KEY_THAI_T
].EqualsAscii( "T") &&
4137 MsLangId::getRealLanguage( rNum
.GetLang()) ==
4140 aPrefix
+= 't'; // must be lowercase, otherwise taken as literal
4143 USHORT nAnz
= NumFor
[n
].GetnAnz();
4144 if ( nSem
&& (nAnz
|| aPrefix
.Len()) )
4146 for ( ; nSem
; --nSem
)
4148 for ( ; nSub
<= n
; ++nSub
)
4149 bDefault
[nSub
] = FALSE
;
4152 if ( aPrefix
.Len() )
4157 const short* pType
= NumFor
[n
].Info().nTypeArray
;
4158 const String
* pStr
= NumFor
[n
].Info().sStrArray
;
4159 for ( USHORT j
=0; j
<nAnz
; j
++ )
4161 if ( 0 <= pType
[j
] && pType
[j
] < NF_KEYWORD_ENTRIES_COUNT
)
4163 aStr
+= rKeywords
[pType
[j
]];
4164 if( NF_KEY_NNNN
== pType
[j
] )
4165 aStr
+= rLocWrp
.getLongDateDayOfWeekSep();
4171 case NF_SYMBOLTYPE_DECSEP
:
4172 aStr
+= rLocWrp
.getNumDecimalSep();
4174 case NF_SYMBOLTYPE_THSEP
:
4175 aStr
+= rLocWrp
.getNumThousandSep();
4177 case NF_SYMBOLTYPE_DATESEP
:
4178 aStr
+= rLocWrp
.getDateSep();
4180 case NF_SYMBOLTYPE_TIMESEP
:
4181 aStr
+= rLocWrp
.getTimeSep();
4183 case NF_SYMBOLTYPE_TIME100SECSEP
:
4184 aStr
+= rLocWrp
.getTime100SecSep();
4186 case NF_SYMBOLTYPE_STRING
:
4189 else if ( pStr
[j
].Len() == 1 )
4209 for ( ; nSub
<4 && bDefault
[nSub
]; ++nSub
)
4210 { // append empty subformats
4217 String
SvNumberformat::ImpGetNatNumString( const SvNumberNatNum
& rNum
,
4218 sal_Int32 nVal
, USHORT nMinDigits
) const
4223 if ( nMinDigits
== 2 )
4224 { // speed up the most common case
4225 if ( 0 <= nVal
&& nVal
< 10 )
4227 sal_Unicode
* p
= aStr
.AllocBuffer( 2 );
4229 *p
= sal_Unicode( '0' + nVal
);
4232 aStr
= String::CreateFromInt32( nVal
);
4236 String
aValStr( String::CreateFromInt32( nVal
) );
4237 if ( aValStr
.Len() >= nMinDigits
)
4241 aStr
.Fill( nMinDigits
- aValStr
.Len(), '0' );
4247 aStr
= String::CreateFromInt32( nVal
);
4248 ImpTransliterate( aStr
, rNum
);
4253 void SvNumberformat::ImpTransliterateImpl( String
& rStr
,
4254 const SvNumberNatNum
& rNum
) const
4256 com::sun::star::lang::Locale
aLocale(
4257 MsLangId::convertLanguageToLocale( rNum
.GetLang() ) );
4258 rStr
= GetFormatter().GetNatNum()->getNativeNumberString( rStr
,
4259 aLocale
, rNum
.GetNatNum() );
4263 void SvNumberformat::GetNatNumXml(
4264 com::sun::star::i18n::NativeNumberXmlAttributes
& rAttr
,
4265 USHORT nNumFor
) const
4269 const SvNumberNatNum
& rNum
= NumFor
[nNumFor
].GetNatNum();
4272 com::sun::star::lang::Locale
aLocale(
4273 MsLangId::convertLanguageToLocale( rNum
.GetLang() ) );
4274 rAttr
= GetFormatter().GetNatNum()->convertToXmlAttributes(
4275 aLocale
, rNum
.GetNatNum() );
4278 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
4281 rAttr
= com::sun::star::i18n::NativeNumberXmlAttributes();
4285 BOOL
SvNumberformat::HasStringNegativeSign( const String
& rStr
)
4287 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4288 xub_StrLen nLen
= rStr
.Len();
4291 const sal_Unicode
* const pBeg
= rStr
.GetBuffer();
4292 const sal_Unicode
* const pEnd
= pBeg
+ nLen
;
4293 register const sal_Unicode
* p
= pBeg
;
4298 } while ( *p
== ' ' && ++p
< pEnd
);
4304 } while ( *p
== ' ' && pBeg
< --p
);
4310 void SvNumberformat::SetComment( const String
& rStr
, String
& rFormat
,
4313 if ( rComment
.Len() )
4314 { // alten Kommentar aus Formatstring loeschen
4315 //! nicht per EraseComment, der Kommentar muss matchen
4321 xub_StrLen nCom
= 0;
4324 nCom
= rFormat
.Search( aTmp
, nCom
);
4325 } while ( (nCom
!= STRING_NOTFOUND
) && (nCom
+ aTmp
.Len() != rFormat
.Len()) );
4326 if ( nCom
!= STRING_NOTFOUND
)
4327 rFormat
.Erase( nCom
);
4330 { // neuen Kommentar setzen
4342 void SvNumberformat::EraseCommentBraces( String
& rStr
)
4344 xub_StrLen nLen
= rStr
.Len();
4345 if ( nLen
&& rStr
.GetChar(0) == '{' )
4350 if ( nLen
&& rStr
.GetChar(0) == ' ' )
4355 if ( nLen
&& rStr
.GetChar( nLen
-1 ) == '}' )
4356 rStr
.Erase( --nLen
, 1 );
4357 if ( nLen
&& rStr
.GetChar( nLen
-1 ) == ' ' )
4358 rStr
.Erase( --nLen
, 1 );
4363 void SvNumberformat::EraseComment( String
& rStr
)
4365 register const sal_Unicode
* p
= rStr
.GetBuffer();
4366 BOOL bInString
= FALSE
;
4367 BOOL bEscaped
= FALSE
;
4368 BOOL bFound
= FALSE
;
4369 xub_StrLen nPos
= 0;
4370 while ( !bFound
&& *p
)
4375 bEscaped
= !bEscaped
;
4379 bInString
= !bInString
;
4382 if ( !bEscaped
&& !bInString
)
4385 nPos
= sal::static_int_cast
< xub_StrLen
>(
4386 p
- rStr
.GetBuffer());
4390 if ( bEscaped
&& *p
!= '\\' )
4400 BOOL
SvNumberformat::IsInQuote( const String
& rStr
, xub_StrLen nPos
,
4401 sal_Unicode cQuote
, sal_Unicode cEscIn
, sal_Unicode cEscOut
)
4403 xub_StrLen nLen
= rStr
.Len();
4406 register const sal_Unicode
* p0
= rStr
.GetBuffer();
4407 register const sal_Unicode
* p
= p0
;
4408 register const sal_Unicode
* p1
= p0
+ nPos
;
4409 BOOL bQuoted
= FALSE
;
4418 if ( *(p
-1) != cEscIn
)
4423 if ( *(p
-1) != cEscOut
)
4434 xub_StrLen
SvNumberformat::GetQuoteEnd( const String
& rStr
, xub_StrLen nPos
,
4435 sal_Unicode cQuote
, sal_Unicode cEscIn
, sal_Unicode cEscOut
)
4437 xub_StrLen nLen
= rStr
.Len();
4439 return STRING_NOTFOUND
;
4440 if ( !IsInQuote( rStr
, nPos
, cQuote
, cEscIn
, cEscOut
) )
4442 if ( rStr
.GetChar( nPos
) == cQuote
)
4443 return nPos
; // schliessendes cQuote
4444 return STRING_NOTFOUND
;
4446 register const sal_Unicode
* p0
= rStr
.GetBuffer();
4447 register const sal_Unicode
* p
= p0
+ nPos
;
4448 register const sal_Unicode
* p1
= p0
+ nLen
;
4451 if ( *p
== cQuote
&& p
> p0
&& *(p
-1) != cEscIn
)
4452 return sal::static_int_cast
< xub_StrLen
>(p
- p0
);
4455 return nLen
; // String Ende
4459 USHORT
SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor
) const
4462 USHORT nAnz
= NumFor
[nNumFor
].GetnAnz();
4463 short const * const pType
= NumFor
[nNumFor
].Info().nTypeArray
;
4464 for ( USHORT j
=0; j
<nAnz
; ++j
)
4468 case NF_SYMBOLTYPE_STRING
:
4469 case NF_SYMBOLTYPE_CURRENCY
:
4470 case NF_SYMBOLTYPE_DATESEP
:
4471 case NF_SYMBOLTYPE_TIMESEP
:
4472 case NF_SYMBOLTYPE_TIME100SECSEP
:
4473 case NF_SYMBOLTYPE_PERCENT
: