merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / numbers / zformat.cxx
blob65c0592143976bc2462909c7ab718d80a4705cf2
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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"
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <float.h>
36 // #include <math.h>
37 #include <errno.h>
38 #include <stdlib.h>
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>
51 #define _ZFORMAT_CXX
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"
60 using namespace svt;
62 namespace {
63 struct Gregorian
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
88 // static
89 xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c )
91 if( c >= 32 )
93 USHORT n = 2; // Default fuer Zeichen > 128 (HACK!)
94 if( c <= 127 )
95 n = cCharWidths[ c - 32 ];
96 while( n-- )
97 r.Insert( ' ', nPos++ );
99 return 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;
109 else
111 long nPrecExp = 1;
112 while( fAbsVal < 1 )
114 fAbsVal *= 10;
115 nPrecExp--;
117 while( fAbsVal >= 10 )
119 fAbsVal /= 10;
120 nPrecExp++;
122 return nPrecExp;
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];
153 switch ( nType )
154 { // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR
155 case NF_SYMBOLTYPE_CURRENCY :
156 rStream << short( NF_SYMBOLTYPE_STRING );
157 break;
158 case NF_SYMBOLTYPE_CURRDEL :
159 case NF_SYMBOLTYPE_CURREXT :
160 rStream << short(0); // werden ignoriert (hoffentlich..)
161 break;
162 default:
163 if ( nType > NF_KEY_LASTKEYWORD_SO5 )
164 rStream << short( NF_SYMBOLTYPE_STRING ); // all new keywords are string
165 else
166 rStream << nType;
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 //============================================================================
188 // static
189 BYTE SvNumberNatNum::MapDBNumToNatNum( BYTE nDBNum, LanguageType eLang, BOOL bDate )
191 BYTE nNatNum = 0;
192 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
193 eLang &= 0x03FF; // 10 bit primary language
194 if ( bDate )
196 if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN )
197 nNatNum = 9;
198 else if ( nDBNum <= 3 )
199 nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3
201 else
203 switch ( nDBNum )
205 case 1:
206 switch ( eLang )
208 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 4; break;
209 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break;
210 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 1; break;
212 break;
213 case 2:
214 switch ( eLang )
216 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 5; break;
217 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break;
218 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 2; break;
220 break;
221 case 3:
222 switch ( eLang )
224 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 6; break;
225 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break;
226 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 3; break;
228 break;
229 case 4:
230 switch ( eLang )
232 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break;
233 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 9; break;
235 break;
238 return nNatNum;
242 // static
243 BYTE SvNumberNatNum::MapNatNumToDBNum( BYTE nNatNum, LanguageType eLang, BOOL bDate )
245 BYTE nDBNum = 0;
246 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
247 eLang &= 0x03FF; // 10 bit primary language
248 if ( bDate )
250 if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN )
251 nDBNum = 4;
252 else if ( nNatNum <= 3 )
253 nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3
255 else
257 switch ( nNatNum )
259 case 1:
260 switch ( eLang )
262 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break;
263 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 1; break;
265 break;
266 case 2:
267 switch ( eLang )
269 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 2; break;
271 break;
272 case 3:
273 switch ( eLang )
275 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 3; break;
277 break;
278 case 4:
279 switch ( eLang )
281 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 1; break;
282 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break;
284 break;
285 case 5:
286 switch ( eLang )
288 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 2; break;
289 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break;
291 break;
292 case 6:
293 switch ( eLang )
295 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 3; break;
297 break;
298 case 7:
299 switch ( eLang )
301 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break;
303 break;
304 case 8:
305 break;
306 case 9:
307 switch ( eLang )
309 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 4; break;
311 break;
312 case 10:
313 break;
314 case 11:
315 break;
318 return nDBNum;
321 /***********************Funktionen SvNumFor******************************/
323 ImpSvNumFor::ImpSvNumFor()
325 nAnzStrings = 0;
326 aI.nTypeArray = NULL;
327 aI.sStrArray = NULL;
328 aI.eScannedType = NUMBERFORMAT_UNDEFINED;
329 aI.bThousand = FALSE;
330 aI.nThousand = 0;
331 aI.nCntPre = 0;
332 aI.nCntPost = 0;
333 aI.nCntExp = 0;
334 pColor = NULL;
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 )
349 if ( aI.nTypeArray )
350 delete [] aI.nTypeArray;
351 if ( aI.sStrArray )
352 delete [] aI.sStrArray;
353 nAnzStrings = nAnz;
354 if ( nAnz )
356 aI.nTypeArray = new short[nAnz];
357 aI.sStrArray = new String[nAnz];
359 else
361 aI.nTypeArray = NULL;
362 aI.sStrArray = NULL;
367 void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
369 Enlarge( rNumFor.nAnzStrings );
370 aI.Copy( rNumFor.aI, nAnzStrings );
371 sColorName = rNumFor.sColorName;
372 if ( pSc )
373 pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents
374 else
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 )
389 USHORT nAnz;
390 rStream >> nAnz; //! noch nicht direkt nAnzStrings wg. Enlarge
391 Enlarge( nAnz );
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 )
404 return TRUE;
406 return FALSE;
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];
420 else
421 rExtension.Erase();
422 return TRUE;
425 //! kein Erase an rSymbol, rExtension
426 return FALSE;
430 void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
432 USHORT j;
433 USHORT nCnt = 0;
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 :
441 nCnt++;
442 break;
445 rStream << nCnt;
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];
454 break;
460 void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
462 USHORT nCnt;
463 rStream >> nCnt;
464 for ( USHORT j=0; j<nCnt; j++ )
466 USHORT nPos;
467 short nType;
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 )
516 rScan(rSc),
517 eLnge(eLge),
518 nNewStandardDefined(0),
519 bStarFlag( FALSE )
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;
530 eOp1 = rFormat.eOp1;
531 eOp2 = rFormat.eOp2;
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 :
594 return TRUE;
596 return FALSE;
600 SvNumberformat::SvNumberformat(String& rString,
601 ImpSvNumberformatScan* pSc,
602 ImpSvNumberInputScan* pISc,
603 xub_StrLen& nCheckPos,
604 LanguageType& eLan,
605 BOOL bStan)
607 rScan(*pSc),
608 nNewStandardDefined(0),
609 bStarFlag( FALSE )
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
629 else
630 eLnge = eLan;
631 bStandard = bStan;
632 bIsUsed = FALSE;
633 fLimit1 = 0.0;
634 fLimit2 = 0.0;
635 eOp1 = NUMBERFORMAT_OP_NO;
636 eOp2 = NUMBERFORMAT_OP_NO;
637 eType = NUMBERFORMAT_DEFINED;
639 BOOL bCancel = FALSE;
640 BOOL bCondition = FALSE;
641 short eSymbolType;
642 xub_StrLen nPos = 0;
643 xub_StrLen nPosOld;
644 nCheckPos = 0;
645 String aComment;
647 // Split into 4 sub formats
648 USHORT nIndex;
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());
655 String sStr;
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 )
665 bCondition = TRUE;
666 eOp1 = (SvNumberformatLimitOps) eSymbolType;
668 else if ( nIndex == 1 && bCondition )
669 eOp2 = (SvNumberformatLimitOps) eSymbolType;
670 else // error
672 bCancel = TRUE; // break for
673 nCheckPos = nPosOld;
675 if (!bCancel)
677 double fNumber;
678 xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr);
679 if (nAnzChars > 0)
681 short F_Type;
682 if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
683 ( F_Type != NUMBERFORMAT_NUMBER &&
684 F_Type != NUMBERFORMAT_SCIENTIFIC) )
686 fNumber = 0.0;
687 nPos = nPos - nAnzChars;
688 rString.Erase(nPos, nAnzChars);
689 rString.Insert('0',nPos);
690 nPos++;
693 else
695 fNumber = 0.0;
696 rString.Insert('0',nPos++);
698 if (nIndex == 0)
699 fLimit1 = fNumber;
700 else
701 fLimit2 = fNumber;
702 if ( rString.GetChar(nPos) == ']' )
703 nPos++;
704 else
706 bCancel = TRUE; // break for
707 nCheckPos = nPos;
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
721 nCheckPos = nPosOld;
723 else
725 Color* pColor = pSc->GetColor( sStr);
726 NumFor[nIndex].SetColor( pColor, sStr);
727 if (pColor == NULL)
728 { // error
729 bCancel = TRUE; // break for
730 nCheckPos = nPosOld;
734 break;
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
759 nCheckPos = nPosOld;
761 else
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 );
770 break;
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
784 nCheckPos = nPosOld;
786 else
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 );
795 break;
796 case BRACKET_SYMBOLTYPE_LOCALE :
798 if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW )
800 bCancel = TRUE; // break for
801 nCheckPos = nPosOld;
803 else
805 xub_StrLen nTmp = 2;
806 LanguageType eLang = ImpGetLanguageType( sStr, nTmp );
807 if ( eLang == LANGUAGE_DONTKNOW )
809 bCancel = TRUE; // break for
810 nCheckPos = nPosOld;
812 else
814 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) );
815 sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii();
816 NumFor[nIndex].SetNatNumLang( eLang );
820 break;
822 if ( !bCancel )
824 rString.Erase(nPosOld,nPos-nPosOld);
825 rString.Insert(sStr,nPosOld);
826 nPos = nPosOld + sStr.Len();
827 rString.Insert(']', nPos);
828 rString.Insert('[', nPosOld);
829 nPos += 2;
830 nPosOld = nPos; // position before string
833 } while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
835 // The remaining format code string
836 if ( !bCancel )
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
844 if (sStr.Len() == 0)
845 { // empty sub format
847 else
849 xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment );
850 USHORT nAnz = pSc->GetAnzResStrings();
851 if (nAnz == 0) // error
852 nStrPos = 1;
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());
860 aNat += ']';
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
869 // have both.
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 &&
878 ((eLanguage =
879 MsLangId::getRealLanguage( eLan))
880 == LANGUAGE_THAI) &&
881 NumFor[nIndex].GetNatNum().GetLang() ==
882 LANGUAGE_DONTKNOW)
884 String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-"));
885 aLID += String::CreateFromInt32( sal_Int32(
886 eLanguage), 16 ).ToUpperAscii();
887 aLID += ']';
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);
897 nPos++;
899 NumFor[nIndex].Enlarge(nAnz);
900 pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
901 // type check
902 if (nIndex == 0)
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 !=
909 eType)
910 eType = NUMBERFORMAT_DEFINED;
912 else
914 nCheckPos = nPosOld + nStrPos; // error in string
915 bCancel = TRUE; // break for
919 else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error
921 nCheckPos = nPosOld;
922 bCancel = TRUE;
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
932 if ( !bCancel )
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;
946 bCancel = TRUE;
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() );
959 String aTmp;
960 if ( !pSc->ScanFormat( aAdd, aTmp ) )
962 USHORT nAnz = pSc->GetAnzResStrings();
963 if ( nAnz )
965 NumFor[0].Enlarge(nAnz);
966 pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
967 rString += aAdd;
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() );
978 String aTmp;
979 if ( !pSc->ScanFormat( aAdd, aTmp ) )
981 USHORT nAnz = pSc->GetAnzResStrings();
982 if ( nAnz )
984 NumFor[nIndex].Enlarge(nAnz);
985 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
986 rString += ';';
987 rString += aAdd;
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() );
996 String aTmp;
997 if ( !pSc->ScanFormat( aAdd, aTmp ) )
999 USHORT nAnz = pSc->GetAnzResStrings();
1000 if ( nAnz )
1002 NumFor[nIndex].Enlarge(nAnz);
1003 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
1004 rString += ';';
1005 rString += aAdd;
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 //---------------------------------------------------------------------------
1028 // Next_Symbol
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
1040 // | BLANK | |
1041 // | Sonst | Symbol += Zeichen | SsGetString
1042 //---------------+-------------------+-----------------------+---------------
1043 // SsGetString | ; | | SsStop
1044 // | Sonst | Symbol+=Zeichen |
1045 //---------------+-------------------+-----------------------+---------------
1046 // SsGetBracketed| <, > = | del [ |
1047 // | | Symbol += Zeichen | SsGetCon
1048 // | BLANK | |
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 |
1061 // | ] | | SsStop
1062 // | sonst | Fehler | SsStop
1063 //---------------+-------------------+-----------------------+---------------
1064 // * : Sonderbedingung
1066 enum ScanState
1068 SsStop,
1069 SsStart,
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
1079 // static
1080 xub_StrLen SvNumberformat::ImpGetNumber(String& rString,
1081 xub_StrLen& nPos,
1082 String& sSymbol)
1084 xub_StrLen nStartPos = nPos;
1085 sal_Unicode cToken;
1086 xub_StrLen nLen = rString.Len();
1087 sSymbol.Erase();
1088 while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
1090 if (cToken == ' ')
1091 { // delete spaces
1092 rString.Erase(nPos,1);
1093 nLen--;
1095 else
1097 nPos++;
1098 sSymbol += cToken;
1101 return nPos - nStartPos;
1105 // static
1106 LanguageType SvNumberformat::ImpGetLanguageType( const String& rString,
1107 xub_StrLen& nPos )
1109 sal_Int32 nNum = 0;
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' )
1116 nNum *= 16;
1117 nNum += cToken - '0';
1119 else if ( 'a' <= cToken && cToken <= 'f' )
1121 nNum *= 16;
1122 nNum += cToken - 'a' + 10;
1124 else if ( 'A' <= cToken && cToken <= 'F' )
1126 nNum *= 16;
1127 nNum += cToken - 'A' + 10;
1129 else
1130 return LANGUAGE_DONTKNOW;
1131 ++nPos;
1133 return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum :
1134 LANGUAGE_DONTKNOW;
1138 short SvNumberformat::ImpNextSymbol(String& rString,
1139 xub_StrLen& nPos,
1140 String& sSymbol)
1142 short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1143 sal_Unicode cToken;
1144 sal_Unicode cLetter = ' '; // Zwischenergebnis
1145 xub_StrLen nLen = rString.Len();
1146 ScanState eState = SsStart;
1147 sSymbol.Erase();
1148 const String* pKeywords = rScan.GetKeywords();
1149 while (nPos < nLen && eState != SsStop)
1151 cToken = rString.GetChar(nPos);
1152 nPos++;
1153 switch (eState)
1155 case SsStart:
1157 if (cToken == '[')
1159 eState = SsGetBracketed;
1160 sSymbol += cToken;
1162 else if (cToken == ';')
1164 eState = SsGetString;
1165 nPos--;
1166 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1168 else if (cToken == ']')
1170 eState = SsStop;
1171 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1173 else if (cToken == ' ') // Skip Blanks
1175 rString.Erase(nPos-1,1);
1176 nPos--;
1177 nLen--;
1179 else
1181 sSymbol += cToken;
1182 eState = SsGetString;
1183 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1186 break;
1187 case SsGetBracketed:
1189 switch (cToken)
1191 case '<':
1192 case '>':
1193 case '=':
1195 sSymbol.EraseAllChars('[');
1196 sSymbol += cToken;
1197 cLetter = cToken;
1198 eState = SsGetCon;
1199 switch (cToken)
1201 case '<': eSymbolType = NUMBERFORMAT_OP_LT; break;
1202 case '>': eSymbolType = NUMBERFORMAT_OP_GT; break;
1203 case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break;
1204 default: break;
1207 break;
1208 case ' ':
1210 rString.Erase(nPos-1,1);
1211 nPos--;
1212 nLen--;
1214 break;
1215 case '$' :
1217 if ( rString.GetChar(nPos) == '-' )
1218 { // [$-xxx] locale
1219 sSymbol.EraseAllChars('[');
1220 eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
1221 eState = SsGetPrefix;
1223 else
1224 { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1225 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1226 eState = SsGetString;
1228 sSymbol += cToken;
1230 break;
1231 case '~' :
1232 { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1233 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1234 sSymbol += cToken;
1235 eState = SsGetString;
1237 break;
1238 default:
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
1270 sSymbol += cToken;
1271 eState = SsGetTime;
1272 cLetter = cToken;
1274 else
1276 sSymbol.EraseAllChars('[');
1277 sSymbol += cToken;
1278 eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1279 eState = SsGetPrefix;
1282 break;
1285 break;
1286 case SsGetString:
1288 if (cToken == ';')
1289 eState = SsStop;
1290 else
1291 sSymbol += cToken;
1293 break;
1294 case SsGetTime:
1296 if (cToken == ']')
1298 sSymbol += cToken;
1299 eState = SsGetString;
1300 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1302 else
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)
1311 sSymbol += cToken;
1312 cLetter = ' ';
1314 else
1316 sSymbol.EraseAllChars('[');
1317 sSymbol += cToken;
1318 eState = SsGetPrefix;
1321 else
1323 sSymbol.EraseAllChars('[');
1324 sSymbol += cToken;
1325 eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1326 eState = SsGetPrefix;
1330 break;
1331 case SsGetCon:
1333 switch (cToken)
1335 case '<':
1337 eState = SsStop;
1338 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1340 break;
1341 case '>':
1343 if (cLetter == '<')
1345 sSymbol += cToken;
1346 cLetter = ' ';
1347 eState = SsStop;
1348 eSymbolType = NUMBERFORMAT_OP_NE;
1350 else
1352 eState = SsStop;
1353 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1356 break;
1357 case '=':
1359 if (cLetter == '<')
1361 sSymbol += cToken;
1362 cLetter = ' ';
1363 eSymbolType = NUMBERFORMAT_OP_LE;
1365 else if (cLetter == '>')
1367 sSymbol += cToken;
1368 cLetter = ' ';
1369 eSymbolType = NUMBERFORMAT_OP_GE;
1371 else
1373 eState = SsStop;
1374 eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1377 break;
1378 case ' ':
1380 rString.Erase(nPos-1,1);
1381 nPos--;
1382 nLen--;
1384 break;
1385 default:
1387 eState = SsStop;
1388 nPos--;
1390 break;
1393 break;
1394 case SsGetPrefix:
1396 if (cToken == ']')
1397 eState = SsStop;
1398 else
1399 sSymbol += cToken;
1401 break;
1402 default:
1403 break;
1404 } // of switch
1405 } // of while
1407 return eSymbolType;
1410 NfHackConversion SvNumberformat::Load( SvStream& rStream,
1411 ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
1412 ImpSvNumberInputScan& rISc )
1414 rHdr.StartEntry();
1415 USHORT nOp1, nOp2;
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 );
1450 else
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;
1481 BOOL bGoOn = TRUE;
1482 while ( rHdr.BytesLeft() && bGoOn )
1483 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1484 USHORT nId;
1485 rStream >> nId;
1486 switch ( nId )
1488 case nNewCurrencyVersionId :
1490 bNewCurrencyLoaded = TRUE;
1491 rStream >> bNewCurrency;
1492 if ( bNewCurrency )
1494 for ( USHORT j=0; j<4; j++ )
1496 NumFor[j].LoadNewCurrencyMap( rStream );
1500 break;
1501 case nNewStandardFlagVersionId :
1502 rStream >> bStandard; // the real standard flag
1503 break;
1504 default:
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.
1511 rHdr.EndEntry();
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 );
1526 // Zustaende merken
1527 short nDefined = ( eType & NUMBERFORMAT_DEFINED );
1528 USHORT nNewStandard = nNewStandardDefined;
1529 // neu parsen etc.
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 );
1536 delete pFormat;
1537 // Zustaende wiederherstellen
1538 eType |= nDefined;
1539 if ( nNewStandard )
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 );
1551 break;
1552 case NF_CONVERT_GERMAN_ENGLISH :
1553 ConvertLanguage( *pHackConverter,
1554 LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, TRUE );
1555 break;
1556 default:
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;
1567 sal_uInt32 nKey;
1568 short nType = eType;
1569 String aFormatString( sFormatstring );
1570 if ( bSystem )
1571 rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
1572 nKey, eConvertFrom, eConvertTo );
1573 else
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" );
1578 if ( pFormat )
1580 ImpCopyNumberformat( *pFormat );
1581 // aus Formatter/Scanner uebernommene Werte zuruecksetzen
1582 if ( bSystem )
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 );
1595 // static
1596 void SvNumberformat::LoadString( SvStream& rStream, String& rStr )
1598 CharSet eStream = rStream.GetStreamCharSet();
1599 ByteString aStr;
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 );
1606 else
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() );
1612 while ( p < pEnd )
1614 if ( *p == cStream )
1615 *pUni = cTarget;
1616 else
1617 *pUni = ByteString::ConvertToUnicode( *p, eStream );
1618 p++;
1619 pUni++;
1621 *pUni = 0;
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 );
1635 #endif
1637 BOOL bNewCurrency = HasNewCurrency();
1638 if ( bNewCurrency )
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;
1649 if ( bOldStandard )
1651 switch ( eType )
1653 case NUMBERFORMAT_NUMBER :
1654 case NUMBERFORMAT_DATE :
1655 case NUMBERFORMAT_TIME :
1656 case NUMBERFORMAT_DATETIME :
1657 case NUMBERFORMAT_PERCENT :
1658 case NUMBERFORMAT_SCIENTIFIC :
1659 // ok to save
1660 break;
1661 default:
1662 bOldStandard = FALSE;
1666 rHdr.StartEntry();
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;
1678 if ( 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;
1693 rHdr.EndEntry();
1697 BOOL SvNumberformat::HasNewCurrency() const
1699 for ( USHORT j=0; j<4; j++ )
1701 if ( NumFor[j].HasNewCurrency() )
1702 return TRUE;
1704 return FALSE;
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 ) )
1714 return TRUE;
1716 rSymbol.Erase();
1717 rExtension.Erase();
1718 return FALSE;
1722 // static
1723 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
1724 BOOL bQuoteSymbol )
1726 String aTmp;
1727 xub_StrLen nStartPos, nPos, nLen;
1728 nLen = rStr.Len();
1729 nStartPos = 0;
1730 while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND )
1732 xub_StrLen nEnd;
1733 if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen )
1735 aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos );
1736 nStartPos = nEnd;
1738 else
1740 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1741 nStartPos = nPos + 2;
1742 xub_StrLen nDash;
1743 nEnd = nStartPos - 1;
1746 nDash = rStr.Search( '-', ++nEnd );
1747 } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen );
1748 xub_StrLen nClose;
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 );
1757 else
1759 aTmp += '"';
1760 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1761 aTmp += '"';
1763 nStartPos = nClose + 1;
1766 if ( nLen > nStartPos )
1767 aTmp += rStr.Copy( nStartPos, nLen - nStartPos );
1768 return aTmp;
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));
1785 else
1787 #if 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 );
1794 // expect 123 OK
1795 aTest = ::rtl::math::doubleToUString( 123.4567,
1796 rtl_math_StringFormat_G, 3, '.', sal_True );
1797 // expect 123.5 OK
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 );
1810 #endif
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() );
1820 return;
1823 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
1825 BOOL bModified = FALSE;
1826 if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
1828 if (fNumber == 0.0)
1830 OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
1831 return;
1833 fNumber *= 100;
1834 bModified = TRUE;
1837 if (fNumber == 0.0)
1839 OutString = '0';
1840 return;
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)
1848 OutString += '%';
1849 return;
1852 short SvNumberformat::ImpCheckCondition(double& fNumber,
1853 double& fLimit,
1854 SvNumberformatLimitOps eOp)
1856 switch(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);
1865 default: return -1;
1869 BOOL SvNumberformat::GetOutputString(String& sString,
1870 String& OutString,
1871 Color** ppColor)
1873 OutString.Erase();
1874 USHORT nIx;
1875 if (eType & NUMBERFORMAT_TEXT)
1876 nIx = 0;
1877 else if (NumFor[3].GetnAnz() > 0)
1878 nIx = 3;
1879 else
1881 *ppColor = NULL; // no change of color
1882 return FALSE;
1884 *ppColor = NumFor[nIx].GetColor();
1885 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
1886 if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
1888 BOOL bRes = FALSE;
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:
1895 if( bStarFlag )
1897 OutString += (sal_Unicode) 0x1B;
1898 OutString += rInfo.sStrArray[i].GetChar(1);
1899 bRes = TRUE;
1901 break;
1902 case NF_SYMBOLTYPE_BLANK:
1903 InsertBlanks( OutString, OutString.Len(),
1904 rInfo.sStrArray[i].GetChar(1) );
1905 break;
1906 case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
1907 case NF_SYMBOLTYPE_DEL :
1908 OutString += sString;
1909 break;
1910 default:
1911 OutString += rInfo.sStrArray[i];
1914 return bRes;
1916 return FALSE;
1919 void SvNumberformat::GetStringColor( Color** ppColor )
1921 if (!ppColor)
1922 return;
1924 USHORT nIx;
1925 if (eType & NUMBERFORMAT_TEXT)
1926 nIx = 0;
1927 else if (NumFor[3].GetnAnz() > 0)
1928 nIx = 3;
1929 else
1931 *ppColor = NULL; // no change of color
1932 return;
1934 *ppColor = NumFor[nIx].GetColor();
1938 void SvNumberformat::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
1939 ULONG y0, ULONG y1,
1940 ULONG& x2,ULONG& y2)
1942 x2 = ((y0+nPrec)/y1)*x1 - x0;
1943 y2 = ((y0+nPrec)/y1)*y1 - y0;
1946 ULONG SvNumberformat::ImpGGT(ULONG x, ULONG y)
1948 if (y == 0)
1949 return x;
1950 else
1952 ULONG z = x%y;
1953 while (z)
1955 x = y;
1956 y = z;
1957 z = x%y;
1959 return y;
1963 ULONG SvNumberformat::ImpGGTRound(ULONG x, ULONG y)
1965 if (y == 0)
1966 return x;
1967 else
1969 ULONG z = x%y;
1970 while ((double)z/(double)y > D_EPS)
1972 x = y;
1973 y = z;
1974 z = x%y;
1976 return y;
1980 BOOL SvNumberformat::GetOutputString(double fNumber,
1981 String& OutString,
1982 Color** ppColor)
1984 BOOL bRes = FALSE;
1985 OutString.Erase(); // alles loeschen
1986 *ppColor = NULL; // keine Farbaenderung
1987 if (eType & NUMBERFORMAT_LOGICAL)
1989 if (fNumber)
1990 OutString = rScan.GetTrueString();
1991 else
1992 OutString = rScan.GetFalseString();
1993 return FALSE;
1995 if (eType & NUMBERFORMAT_TEXT && bStandard)
1997 ImpGetOutputStandard(fNumber, OutString);
1998 return FALSE;
2000 BOOL bHadStandard = FALSE;
2001 if (bStandard) // einzelne Standardformate
2003 if (rScan.GetStandardPrec() == 300) // alle Zahlformate InputLine
2005 ImpGetOutputInputLine(fNumber, OutString);
2006 return FALSE;
2008 switch (eType)
2010 case NUMBERFORMAT_NUMBER: // Standardzahlformat
2011 ImpGetOutputStandard(fNumber, OutString);
2012 bHadStandard = TRUE;
2013 break;
2014 case NUMBERFORMAT_DATE:
2015 bRes |= ImpGetDateOutput(fNumber, 0, OutString);
2016 bHadStandard = TRUE;
2017 break;
2018 case NUMBERFORMAT_TIME:
2019 bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
2020 bHadStandard = TRUE;
2021 break;
2022 case NUMBERFORMAT_DATETIME:
2023 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
2024 bHadStandard = TRUE;
2025 break;
2028 if ( !bHadStandard )
2030 USHORT nIx; // Index des Teilformats
2031 short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
2032 if (nCheck == -1 || nCheck == 1) // nur 1 String oder True
2033 nIx = 0;
2034 else
2036 nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
2037 if (nCheck == -1 || nCheck == 1)
2038 nIx = 1;
2039 else
2040 nIx = 2;
2042 if (nIx == 1 && fNumber < 0.0 && // negatives Format
2043 IsNegativeRealNegative() ) // ohne Vorzeichen
2044 fNumber = -fNumber; // Vorzeichen eliminieren
2045 *ppColor = NumFor[nIx].GetColor();
2046 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2047 const USHORT nAnz = NumFor[nIx].GetnAnz();
2048 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
2049 return FALSE; // leer => nichts
2050 else if (nAnz == 0) // sonst Standard-Format
2052 ImpGetOutputStandard(fNumber, OutString);
2053 return FALSE;
2055 switch (rInfo.eScannedType)
2057 case NUMBERFORMAT_TEXT:
2058 case NUMBERFORMAT_DEFINED:
2060 for (USHORT i = 0; i < nAnz; i++)
2062 switch (rInfo.nTypeArray[i])
2064 case NF_SYMBOLTYPE_STAR:
2065 if( bStarFlag )
2067 OutString += (sal_Unicode) 0x1B;
2068 OutString += rInfo.sStrArray[i].GetChar(1);
2069 bRes = TRUE;
2071 break;
2072 case NF_SYMBOLTYPE_BLANK:
2073 InsertBlanks( OutString, OutString.Len(),
2074 rInfo.sStrArray[i].GetChar(1) );
2075 break;
2076 case NF_SYMBOLTYPE_STRING:
2077 case NF_SYMBOLTYPE_CURRENCY:
2078 OutString += rInfo.sStrArray[i];
2079 break;
2080 case NF_SYMBOLTYPE_THSEP:
2081 if (rInfo.nThousand == 0)
2082 OutString += rInfo.sStrArray[i];
2083 break;
2084 default:
2085 break;
2089 break;
2090 case NUMBERFORMAT_DATE:
2091 bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
2092 break;
2093 case NUMBERFORMAT_TIME:
2094 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
2095 break;
2096 case NUMBERFORMAT_DATETIME:
2097 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
2098 break;
2099 case NUMBERFORMAT_NUMBER:
2100 case NUMBERFORMAT_PERCENT:
2101 case NUMBERFORMAT_CURRENCY:
2102 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
2103 break;
2104 case NUMBERFORMAT_FRACTION:
2106 String sStr, sFrac, sDiv; // Strings, Wert fuer
2107 ULONG nFrac, nDiv; // Vorkommaanteil
2108 // Zaehler und Nenner
2109 BOOL bSign = FALSE;
2110 if (fNumber < 0)
2112 if (nIx == 0) // nicht in hinteren
2113 bSign = TRUE; // Formaten
2114 fNumber = -fNumber;
2116 double fNum = floor(fNumber); // Vorkommateil
2117 fNumber -= fNum; // Nachkommateil
2118 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
2119 // zu gross
2121 OutString = rScan.GetErrorString();
2122 return FALSE;
2124 if (rInfo.nCntExp == 0)
2126 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2127 return FALSE;
2129 ULONG nBasis = ((ULONG)floor( // 9, 99, 999 ,...
2130 pow(10.0,rInfo.nCntExp))) - 1;
2131 ULONG x0, y0, x1, y1;
2133 if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
2135 BOOL bUpperHalf;
2136 if (fNumber > 0.5)
2138 bUpperHalf = TRUE;
2139 fNumber -= (fNumber - 0.5) * 2.0;
2141 else
2142 bUpperHalf = FALSE;
2143 // Einstieg in Farey-Serie
2144 // finden:
2145 x0 = (ULONG) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
2146 if (x0 == 0) // => x0 = 2
2148 y0 = 1;
2149 x1 = 1;
2150 y1 = nBasis;
2152 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2
2153 { // geht (nBasis ungerade)
2154 y0 = nBasis;
2155 x1 = 1;
2156 y1 = 2;
2158 else if (x0 == 1)
2160 y0 = nBasis; // 1/n; 1/(n-1)
2161 x1 = 1;
2162 y1 = nBasis - 1;
2164 else
2166 y0 = nBasis; // z.B. 2/9 2/8
2167 x1 = x0;
2168 y1 = nBasis - 1;
2169 double fUg = (double) x0 / (double) y0;
2170 double fOg = (double) x1 / (double) y1;
2171 ULONG nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
2172 x0 /= nGgt;
2173 y0 /= nGgt; // Einschachteln:
2174 ULONG x2 = 0;
2175 ULONG y2 = 0;
2176 BOOL bStop = FALSE;
2177 while (!bStop)
2179 #ifdef GCC
2180 // #i21648# GCC over-optimizes something resulting
2181 // in wrong fTest values throughout the loops.
2182 volatile
2183 #endif
2184 double fTest = (double)x1/(double)y1;
2185 while (!bStop)
2187 while (fTest > fOg)
2189 x1--;
2190 fTest = (double)x1/(double)y1;
2192 while (fTest < fUg && y1 > 1)
2194 y1--;
2195 fTest = (double)x1/(double)y1;
2197 if (fTest <= fOg)
2199 fOg = fTest;
2200 bStop = TRUE;
2202 else if (y1 == 1)
2203 bStop = TRUE;
2204 } // of while
2205 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen
2206 x2 = x1 / nGgt;
2207 y2 = y1 / nGgt;
2208 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2
2209 bStop = TRUE; // naechste Farey-Zahl
2210 else
2212 y1--;
2213 bStop = FALSE;
2215 } // of while
2216 x1 = x2;
2217 y1 = y2;
2218 } // of else
2219 double fup, flow;
2220 flow = (double)x0/(double)y0;
2221 fup = (double)x1/(double)y1;
2222 while (fNumber > fup)
2224 ULONG x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
2225 ULONG y2 = ((y0+nBasis)/y1)*y1 - y0;
2226 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2227 x0 = x1;
2228 y0 = y1;
2229 x1 = x2;
2230 y1 = y2;
2231 flow = fup;
2232 fup = (double)x1/(double)y1;
2234 if (fNumber - flow < fup - fNumber)
2236 nFrac = x0;
2237 nDiv = y0;
2239 else
2241 nFrac = x1;
2242 nDiv = y1;
2244 if (bUpperHalf) // Original restaur.
2246 if (nFrac == 0 && nDiv == 1) // 1/1
2247 fNum += 1.0;
2248 else
2249 nFrac = nDiv - nFrac;
2252 else // grosse Nenner
2253 { // 0,1234->123/1000
2254 ULONG nGgt;
2256 nDiv = nBasis+1;
2257 nFrac = ((ULONG)floor(0.5 + fNumber *
2258 pow(10.0,rInfo.nCntExp)));
2260 nDiv = 10000000;
2261 nFrac = ((ULONG)floor(0.5 + fNumber * 10000000.0));
2262 nGgt = ImpGGT(nDiv, nFrac);
2263 if (nGgt > 1)
2265 nDiv /= nGgt;
2266 nFrac /= nGgt;
2268 if (nDiv > nBasis)
2270 nGgt = ImpGGTRound(nDiv, nFrac);
2271 if (nGgt > 1)
2273 nDiv /= nGgt;
2274 nFrac /= nGgt;
2277 if (nDiv > nBasis)
2279 nDiv = nBasis;
2280 nFrac = ((ULONG)floor(0.5 + fNumber *
2281 pow(10.0,rInfo.nCntExp)));
2282 nGgt = ImpGGTRound(nDiv, nFrac);
2283 if (nGgt > 1)
2285 nDiv /= nGgt;
2286 nFrac /= nGgt;
2291 if (rInfo.nCntPre == 0) // unechter Bruch
2293 double fNum1 = fNum * (double)nDiv + (double)nFrac;
2294 if (fNum1 > _D_MAX_U_LONG_)
2296 OutString = rScan.GetErrorString();
2297 return FALSE;
2299 nFrac = (ULONG) floor(fNum1);
2300 sStr.Erase();
2302 else if (fNum == 0.0 && nFrac != 0)
2303 sStr.Erase();
2304 else
2306 char aBuf[100];
2307 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
2308 sStr.AssignAscii( aBuf );
2309 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
2311 if (rInfo.nCntPre > 0 && nFrac == 0)
2313 sFrac.Erase();
2314 sDiv.Erase();
2316 else
2318 sFrac = ImpIntToString( nIx, nFrac );
2319 sDiv = ImpIntToString( nIx, nDiv );
2322 USHORT j = nAnz-1; // letztes Symbol->rueckw.
2323 xub_StrLen k; // Nenner:
2324 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
2325 BOOL bCont = TRUE;
2326 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
2328 if (rInfo.nCntPre > 0 && nFrac == 0)
2329 sDiv.Insert(' ',0);
2330 else
2331 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
2332 if ( j )
2333 j--;
2334 else
2335 bCont = FALSE;
2337 // weiter Zaehler:
2338 if ( !bCont )
2339 sFrac.Erase();
2340 else
2342 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
2343 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
2345 sFrac.Insert(rInfo.sStrArray[j],0);
2346 if ( j )
2347 j--;
2348 else
2349 bCont = FALSE;
2352 // weiter Hauptzahl
2353 if ( !bCont )
2354 sStr.Erase();
2355 else
2357 k = sStr.Len(); // hinter letzter Ziffer
2358 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
2359 rInfo.nCntPre);
2361 if (bSign && !(nFrac == 0 && fNum == 0.0))
2362 OutString.Insert('-',0); // nicht -0
2363 OutString += sStr;
2364 OutString += sFrac;
2365 OutString += sDiv;
2367 break;
2368 case NUMBERFORMAT_SCIENTIFIC:
2370 BOOL bSign = FALSE;
2371 if (fNumber < 0)
2373 if (nIx == 0) // nicht in hinteren
2374 bSign = TRUE; // Formaten
2375 fNumber = -fNumber;
2377 String sStr( ::rtl::math::doubleToUString( fNumber,
2378 rtl_math_StringFormat_E,
2379 rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
2381 String ExpStr;
2382 short nExpSign = 1;
2383 xub_StrLen nExPos = sStr.Search('E');
2384 if ( nExPos != STRING_NOTFOUND )
2386 // split into mantisse and exponent and get rid of "E+" or "E-"
2387 xub_StrLen nExpStart = nExPos + 1;
2388 switch ( sStr.GetChar( nExpStart ) )
2390 case '-' :
2391 nExpSign = -1;
2392 // fallthru
2393 case '+' :
2394 ++nExpStart;
2395 break;
2397 ExpStr = sStr.Copy( nExpStart ); // part following the "E+"
2398 sStr.Erase( nExPos );
2399 sStr.EraseAllChars('.'); // cut any decimal delimiter
2400 if ( rInfo.nCntPre != 1 ) // rescale Exp
2402 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
2403 nExp -= sal_Int32(rInfo.nCntPre)-1;
2404 if ( nExp < 0 )
2406 nExpSign = -1;
2407 nExp = -nExp;
2409 else
2410 nExpSign = 1;
2411 ExpStr = String::CreateFromInt32( nExp );
2414 USHORT j = nAnz-1; // last symbol
2415 xub_StrLen k; // position in ExpStr
2416 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
2418 xub_StrLen nZeros = 0; // erase leading zeros
2419 while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
2420 ++nZeros;
2421 if (nZeros)
2422 ExpStr.Erase( 0, nZeros);
2424 BOOL bCont = TRUE;
2425 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
2427 const String& rStr = rInfo.sStrArray[j];
2428 if (nExpSign == -1)
2429 ExpStr.Insert('-',0);
2430 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
2431 ExpStr.Insert('+',0);
2432 ExpStr.Insert(rStr.GetChar(0),0);
2433 if ( j )
2434 j--;
2435 else
2436 bCont = FALSE;
2438 // weiter Hauptzahl:
2439 if ( !bCont )
2440 sStr.Erase();
2441 else
2443 k = sStr.Len(); // hinter letzter Ziffer
2444 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
2445 rInfo.nCntPre +
2446 rInfo.nCntPost);
2448 if (bSign)
2449 sStr.Insert('-',0);
2450 OutString = sStr;
2451 OutString += ExpStr;
2453 break;
2456 return bRes;
2459 BOOL SvNumberformat::ImpGetTimeOutput(double fNumber,
2460 USHORT nIx,
2461 String& OutString)
2463 using namespace ::com::sun::star::i18n;
2464 BOOL bCalendarSet = FALSE;
2465 double fNumberOrig = fNumber;
2466 BOOL bRes = FALSE;
2467 BOOL bSign = FALSE;
2468 if (fNumber < 0.0)
2470 fNumber = -fNumber;
2471 if (nIx == 0)
2472 bSign = TRUE;
2474 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2475 if (rInfo.bThousand) // []-Format
2477 if (fNumber > 1.0E10) // zu gross
2479 OutString = rScan.GetErrorString();
2480 return FALSE;
2483 else
2484 fNumber -= floor(fNumber); // sonst Datum abtrennen
2485 BOOL bInputLine;
2486 xub_StrLen nCntPost;
2487 if ( rScan.GetStandardPrec() == 300 &&
2488 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2489 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2490 bInputLine = TRUE;
2491 nCntPost = 7;
2493 else
2495 bInputLine = FALSE;
2496 nCntPost = xub_StrLen(rInfo.nCntPost);
2498 if (bSign && !rInfo.bThousand) // kein []-Format
2499 fNumber = 1.0 - fNumber; // "Kehrwert"
2500 double fTime = fNumber * 86400.0;
2501 fTime = ::rtl::math::round( fTime, int(nCntPost) );
2502 if (bSign && fTime == 0.0)
2503 bSign = FALSE; // nicht -00:00:00
2505 if( floor( fTime ) > _D_MAX_U_LONG_ )
2507 OutString = rScan.GetErrorString();
2508 return FALSE;
2510 ULONG nSeconds = (ULONG)floor( fTime );
2512 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
2513 rtl_math_StringFormat_F, int(nCntPost), '.'));
2514 sSecStr.EraseLeadingChars('0');
2515 sSecStr.EraseLeadingChars('.');
2516 if ( bInputLine )
2518 sSecStr.EraseTrailingChars('0');
2519 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
2520 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
2521 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2522 nCntPost = sSecStr.Len();
2524 else
2525 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2527 xub_StrLen nSecPos = 0; // Zum Ziffernweisen
2528 // abarbeiten
2529 ULONG nHour, nMin, nSec;
2530 if (!rInfo.bThousand) // kein [] Format
2532 nHour = (nSeconds/3600) % 24;
2533 nMin = (nSeconds%3600) / 60;
2534 nSec = nSeconds%60;
2536 else if (rInfo.nThousand == 3) // [ss]
2538 nHour = 0;
2539 nMin = 0;
2540 nSec = nSeconds;
2542 else if (rInfo.nThousand == 2) // [mm]:ss
2544 nHour = 0;
2545 nMin = nSeconds / 60;
2546 nSec = nSeconds % 60;
2548 else if (rInfo.nThousand == 1) // [hh]:mm:ss
2550 nHour = nSeconds / 3600;
2551 nMin = (nSeconds%3600) / 60;
2552 nSec = nSeconds%60;
2554 else {
2555 // TODO What should these be set to?
2556 nHour = 0;
2557 nMin = 0;
2558 nSec = 0;
2561 sal_Unicode cAmPm = ' '; // a oder p
2562 if (rInfo.nCntExp) // AM/PM
2564 if (nHour == 0)
2566 nHour = 12;
2567 cAmPm = 'a';
2569 else if (nHour < 12)
2570 cAmPm = 'a';
2571 else
2573 cAmPm = 'p';
2574 if (nHour > 12)
2575 nHour -= 12;
2578 const USHORT nAnz = NumFor[nIx].GetnAnz();
2579 for (USHORT i = 0; i < nAnz; i++)
2581 switch (rInfo.nTypeArray[i])
2583 case NF_SYMBOLTYPE_STAR:
2584 if( bStarFlag )
2586 OutString += (sal_Unicode) 0x1B;
2587 OutString += rInfo.sStrArray[i].GetChar(1);
2588 bRes = TRUE;
2590 break;
2591 case NF_SYMBOLTYPE_BLANK:
2592 InsertBlanks( OutString, OutString.Len(),
2593 rInfo.sStrArray[i].GetChar(1) );
2594 break;
2595 case NF_SYMBOLTYPE_STRING:
2596 case NF_SYMBOLTYPE_CURRENCY:
2597 case NF_SYMBOLTYPE_DATESEP:
2598 case NF_SYMBOLTYPE_TIMESEP:
2599 case NF_SYMBOLTYPE_TIME100SECSEP:
2600 OutString += rInfo.sStrArray[i];
2601 break;
2602 case NF_SYMBOLTYPE_DIGIT:
2604 xub_StrLen nLen = ( bInputLine && i > 0 &&
2605 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
2606 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
2607 nCntPost : rInfo.sStrArray[i].Len() );
2608 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
2610 OutString += sSecStr.GetChar(nSecPos);
2611 nSecPos++;
2614 break;
2615 case NF_KEY_AMPM: // AM/PM
2617 if ( !bCalendarSet )
2619 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
2620 fDiff += fNumberOrig;
2621 GetCal().setLocalDateTime( fDiff );
2622 bCalendarSet = TRUE;
2624 if (cAmPm == 'a')
2625 OutString += GetCal().getDisplayName(
2626 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
2627 else
2628 OutString += GetCal().getDisplayName(
2629 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
2631 break;
2632 case NF_KEY_AP: // A/P
2634 if (cAmPm == 'a')
2635 OutString += 'a';
2636 else
2637 OutString += 'p';
2639 break;
2640 case NF_KEY_MI: // M
2641 OutString += ImpIntToString( nIx, nMin );
2642 break;
2643 case NF_KEY_MMI: // MM
2644 OutString += ImpIntToString( nIx, nMin, 2 );
2645 break;
2646 case NF_KEY_H: // H
2647 OutString += ImpIntToString( nIx, nHour );
2648 break;
2649 case NF_KEY_HH: // HH
2650 OutString += ImpIntToString( nIx, nHour, 2 );
2651 break;
2652 case NF_KEY_S: // S
2653 OutString += ImpIntToString( nIx, nSec );
2654 break;
2655 case NF_KEY_SS: // SS
2656 OutString += ImpIntToString( nIx, nSec, 2 );
2657 break;
2658 default:
2659 break;
2662 if (bSign && rInfo.bThousand)
2663 OutString.Insert('-',0);
2664 return bRes;
2668 BOOL SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
2670 if ( GetCal().getUniqueID() != Gregorian::get() )
2671 return FALSE;
2672 const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2673 const USHORT nAnz = rNumFor.GetnAnz();
2674 USHORT i;
2675 for ( i = 0; i < nAnz; i++ )
2677 switch ( rInfo.nTypeArray[i] )
2679 case NF_SYMBOLTYPE_CALENDAR :
2680 return FALSE;
2681 case NF_KEY_EC :
2682 case NF_KEY_EEC :
2683 case NF_KEY_R :
2684 case NF_KEY_RR :
2685 case NF_KEY_AAA :
2686 case NF_KEY_AAAA :
2687 return TRUE;
2690 return FALSE;
2694 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
2695 double& fOrgDateTime ) const
2697 CalendarWrapper& rCal = GetCal();
2698 const rtl::OUString &rGregorian = Gregorian::get();
2699 if ( rCal.getUniqueID() == rGregorian )
2701 using namespace ::com::sun::star::i18n;
2702 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
2703 = rCal.getAllCalendars( rLoc().getLocale() );
2704 sal_Int32 nCnt = xCals.getLength();
2705 if ( nCnt > 1 )
2707 for ( sal_Int32 j=0; j < nCnt; j++ )
2709 if ( xCals[j] != rGregorian )
2711 if ( !rOrgCalendar.Len() )
2713 rOrgCalendar = rCal.getUniqueID();
2714 fOrgDateTime = rCal.getDateTime();
2716 rCal.loadCalendar( xCals[j], rLoc().getLocale() );
2717 rCal.setDateTime( fOrgDateTime );
2718 break; // for
2726 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
2727 double fOrgDateTime ) const
2729 CalendarWrapper& rCal = GetCal();
2730 const rtl::OUString &rGregorian = Gregorian::get();
2731 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
2733 rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2734 rCal.setDateTime( fOrgDateTime );
2739 BOOL SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
2741 using namespace ::com::sun::star::i18n;
2742 CalendarWrapper& rCal = GetCal();
2743 const rtl::OUString &rGregorian = Gregorian::get();
2744 if ( rCal.getUniqueID() != rGregorian )
2746 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2747 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
2748 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2750 if ( !rOrgCalendar.Len() )
2752 rOrgCalendar = rCal.getUniqueID();
2753 fOrgDateTime = rCal.getDateTime();
2755 else if ( rOrgCalendar == String(rGregorian) )
2756 rOrgCalendar.Erase();
2757 rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2758 rCal.setDateTime( fOrgDateTime );
2759 return TRUE;
2762 return FALSE;
2766 BOOL SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
2767 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
2769 const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2770 const USHORT nAnz = rNumFor.GetnAnz();
2771 for ( USHORT i = 0; i < nAnz; i++ )
2773 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
2775 CalendarWrapper& rCal = GetCal();
2776 if ( !rOrgCalendar.Len() )
2778 rOrgCalendar = rCal.getUniqueID();
2779 fOrgDateTime = rCal.getDateTime();
2781 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2782 rCal.setDateTime( fOrgDateTime );
2783 return TRUE;
2786 return FALSE;
2790 // static
2791 void SvNumberformat::ImpAppendEraG( String& OutString,
2792 const CalendarWrapper& rCal, sal_Int16 nNatNum )
2794 using namespace ::com::sun::star::i18n;
2795 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2797 sal_Unicode cEra;
2798 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2799 switch ( nVal )
2801 case 1 : cEra = 'M'; break;
2802 case 2 : cEra = 'T'; break;
2803 case 3 : cEra = 'S'; break;
2804 case 4 : cEra = 'H'; break;
2805 default:
2806 cEra = '?';
2808 OutString += cEra;
2810 else
2811 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
2815 BOOL SvNumberformat::ImpGetDateOutput(double fNumber,
2816 USHORT nIx,
2817 String& OutString)
2819 using namespace ::com::sun::star::i18n;
2820 BOOL bRes = FALSE;
2821 CalendarWrapper& rCal = GetCal();
2822 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
2823 fNumber += fDiff;
2824 rCal.setLocalDateTime( fNumber );
2825 String aOrgCalendar; // empty => not changed yet
2826 double fOrgDateTime;
2827 BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
2828 if ( bOtherCalendar )
2829 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2830 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
2831 bOtherCalendar = FALSE;
2832 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2833 const USHORT nAnz = NumFor[nIx].GetnAnz();
2834 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
2835 for (USHORT i = 0; i < nAnz; i++)
2837 switch (rInfo.nTypeArray[i])
2839 case NF_SYMBOLTYPE_CALENDAR :
2840 if ( !aOrgCalendar.Len() )
2842 aOrgCalendar = rCal.getUniqueID();
2843 fOrgDateTime = rCal.getDateTime();
2845 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2846 rCal.setDateTime( fOrgDateTime );
2847 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2848 break;
2849 case NF_SYMBOLTYPE_STAR:
2850 if( bStarFlag )
2852 OutString += (sal_Unicode) 0x1B;
2853 OutString += rInfo.sStrArray[i].GetChar(1);
2854 bRes = TRUE;
2856 break;
2857 case NF_SYMBOLTYPE_BLANK:
2858 InsertBlanks( OutString, OutString.Len(),
2859 rInfo.sStrArray[i].GetChar(1) );
2860 break;
2861 case NF_SYMBOLTYPE_STRING:
2862 case NF_SYMBOLTYPE_CURRENCY:
2863 case NF_SYMBOLTYPE_DATESEP:
2864 case NF_SYMBOLTYPE_TIMESEP:
2865 case NF_SYMBOLTYPE_TIME100SECSEP:
2866 OutString += rInfo.sStrArray[i];
2867 break;
2868 case NF_KEY_M: // M
2869 OutString += rCal.getDisplayString(
2870 CalendarDisplayCode::SHORT_MONTH, nNatNum );
2871 break;
2872 case NF_KEY_MM: // MM
2873 OutString += rCal.getDisplayString(
2874 CalendarDisplayCode::LONG_MONTH, nNatNum );
2875 break;
2876 case NF_KEY_MMM: // MMM
2877 OutString += rCal.getDisplayString(
2878 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
2879 break;
2880 case NF_KEY_MMMM: // MMMM
2881 OutString += rCal.getDisplayString(
2882 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
2883 break;
2884 case NF_KEY_MMMMM: // MMMMM
2885 OutString += rCal.getDisplayString(
2886 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
2887 break;
2888 case NF_KEY_Q: // Q
2889 OutString += rCal.getDisplayString(
2890 CalendarDisplayCode::SHORT_QUARTER, nNatNum );
2891 break;
2892 case NF_KEY_QQ: // QQ
2893 OutString += rCal.getDisplayString(
2894 CalendarDisplayCode::LONG_QUARTER, nNatNum );
2895 break;
2896 case NF_KEY_D: // D
2897 OutString += rCal.getDisplayString(
2898 CalendarDisplayCode::SHORT_DAY, nNatNum );
2899 break;
2900 case NF_KEY_DD: // DD
2901 OutString += rCal.getDisplayString(
2902 CalendarDisplayCode::LONG_DAY, nNatNum );
2903 break;
2904 case NF_KEY_DDD: // DDD
2906 if ( bOtherCalendar )
2907 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2908 OutString += rCal.getDisplayString(
2909 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
2910 if ( bOtherCalendar )
2911 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2913 break;
2914 case NF_KEY_DDDD: // DDDD
2916 if ( bOtherCalendar )
2917 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2918 OutString += rCal.getDisplayString(
2919 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2920 if ( bOtherCalendar )
2921 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2923 break;
2924 case NF_KEY_YY: // YY
2926 if ( bOtherCalendar )
2927 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2928 OutString += rCal.getDisplayString(
2929 CalendarDisplayCode::SHORT_YEAR, nNatNum );
2930 if ( bOtherCalendar )
2931 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2933 break;
2934 case NF_KEY_YYYY: // YYYY
2936 if ( bOtherCalendar )
2937 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2938 OutString += rCal.getDisplayString(
2939 CalendarDisplayCode::LONG_YEAR, nNatNum );
2940 if ( bOtherCalendar )
2941 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2943 break;
2944 case NF_KEY_EC: // E
2945 OutString += rCal.getDisplayString(
2946 CalendarDisplayCode::SHORT_YEAR, nNatNum );
2947 break;
2948 case NF_KEY_EEC: // EE
2949 case NF_KEY_R: // R
2950 OutString += rCal.getDisplayString(
2951 CalendarDisplayCode::LONG_YEAR, nNatNum );
2952 break;
2953 case NF_KEY_NN: // NN
2954 case NF_KEY_AAA: // AAA
2955 OutString += rCal.getDisplayString(
2956 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
2957 break;
2958 case NF_KEY_NNN: // NNN
2959 case NF_KEY_AAAA: // AAAA
2960 OutString += rCal.getDisplayString(
2961 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2962 break;
2963 case NF_KEY_NNNN: // NNNN
2965 OutString += rCal.getDisplayString(
2966 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2967 OutString += rLoc().getLongDateDayOfWeekSep();
2969 break;
2970 case NF_KEY_WW : // WW
2972 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
2973 OutString += ImpIntToString( nIx, nVal );
2975 break;
2976 case NF_KEY_G: // G
2977 ImpAppendEraG( OutString, rCal, nNatNum );
2978 break;
2979 case NF_KEY_GG: // GG
2980 OutString += rCal.getDisplayString(
2981 CalendarDisplayCode::SHORT_ERA, nNatNum );
2982 break;
2983 case NF_KEY_GGG: // GGG
2984 OutString += rCal.getDisplayString(
2985 CalendarDisplayCode::LONG_ERA, nNatNum );
2986 break;
2987 case NF_KEY_RR: // RR => GGGEE
2988 OutString += rCal.getDisplayString(
2989 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
2990 break;
2993 if ( aOrgCalendar.Len() )
2994 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
2995 return bRes;
2998 BOOL SvNumberformat::ImpGetDateTimeOutput(double fNumber,
2999 USHORT nIx,
3000 String& OutString)
3002 using namespace ::com::sun::star::i18n;
3003 BOOL bRes = FALSE;
3005 CalendarWrapper& rCal = GetCal();
3006 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
3007 fNumber += fDiff;
3009 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3010 BOOL bInputLine;
3011 xub_StrLen nCntPost;
3012 if ( rScan.GetStandardPrec() == 300 &&
3013 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
3014 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
3015 bInputLine = TRUE;
3016 nCntPost = 7;
3018 else
3020 bInputLine = FALSE;
3021 nCntPost = xub_StrLen(rInfo.nCntPost);
3023 double fTime = (fNumber - floor( fNumber )) * 86400.0;
3024 fTime = ::rtl::math::round( fTime, int(nCntPost) );
3025 if (fTime >= 86400.0)
3027 // result of fNumber==x.999999999... rounded up, use correct date/time
3028 fTime -= 86400.0;
3029 fNumber = floor( fNumber + 0.5) + fTime;
3031 rCal.setLocalDateTime( fNumber );
3033 String aOrgCalendar; // empty => not changed yet
3034 double fOrgDateTime;
3035 BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3036 if ( bOtherCalendar )
3037 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3038 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3039 bOtherCalendar = FALSE;
3040 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3042 ULONG nSeconds = (ULONG)floor( fTime );
3043 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
3044 rtl_math_StringFormat_F, int(nCntPost), '.'));
3045 sSecStr.EraseLeadingChars('0');
3046 sSecStr.EraseLeadingChars('.');
3047 if ( bInputLine )
3049 sSecStr.EraseTrailingChars('0');
3050 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
3051 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
3052 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3053 nCntPost = sSecStr.Len();
3055 else
3056 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3058 xub_StrLen nSecPos = 0; // Zum Ziffernweisen
3059 // abarbeiten
3060 ULONG nHour, nMin, nSec;
3061 if (!rInfo.bThousand) // [] Format
3063 nHour = (nSeconds/3600) % 24;
3064 nMin = (nSeconds%3600) / 60;
3065 nSec = nSeconds%60;
3067 else if (rInfo.nThousand == 3) // [ss]
3069 nHour = 0;
3070 nMin = 0;
3071 nSec = nSeconds;
3073 else if (rInfo.nThousand == 2) // [mm]:ss
3075 nHour = 0;
3076 nMin = nSeconds / 60;
3077 nSec = nSeconds % 60;
3079 else if (rInfo.nThousand == 1) // [hh]:mm:ss
3081 nHour = nSeconds / 3600;
3082 nMin = (nSeconds%3600) / 60;
3083 nSec = nSeconds%60;
3085 else {
3086 nHour = 0; // TODO What should these values be?
3087 nMin = 0;
3088 nSec = 0;
3090 sal_Unicode cAmPm = ' '; // a oder p
3091 if (rInfo.nCntExp) // AM/PM
3093 if (nHour == 0)
3095 nHour = 12;
3096 cAmPm = 'a';
3098 else if (nHour < 12)
3099 cAmPm = 'a';
3100 else
3102 cAmPm = 'p';
3103 if (nHour > 12)
3104 nHour -= 12;
3107 const USHORT nAnz = NumFor[nIx].GetnAnz();
3108 for (USHORT i = 0; i < nAnz; i++)
3110 switch (rInfo.nTypeArray[i])
3112 case NF_SYMBOLTYPE_CALENDAR :
3113 if ( !aOrgCalendar.Len() )
3115 aOrgCalendar = rCal.getUniqueID();
3116 fOrgDateTime = rCal.getDateTime();
3118 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
3119 rCal.setDateTime( fOrgDateTime );
3120 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3121 break;
3122 case NF_SYMBOLTYPE_STAR:
3123 if( bStarFlag )
3125 OutString += (sal_Unicode) 0x1B;
3126 OutString += rInfo.sStrArray[i].GetChar(1);
3127 bRes = TRUE;
3129 break;
3130 case NF_SYMBOLTYPE_BLANK:
3131 InsertBlanks( OutString, OutString.Len(),
3132 rInfo.sStrArray[i].GetChar(1) );
3133 break;
3134 case NF_SYMBOLTYPE_STRING:
3135 case NF_SYMBOLTYPE_CURRENCY:
3136 case NF_SYMBOLTYPE_DATESEP:
3137 case NF_SYMBOLTYPE_TIMESEP:
3138 case NF_SYMBOLTYPE_TIME100SECSEP:
3139 OutString += rInfo.sStrArray[i];
3140 break;
3141 case NF_SYMBOLTYPE_DIGIT:
3143 xub_StrLen nLen = ( bInputLine && i > 0 &&
3144 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
3145 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
3146 nCntPost : rInfo.sStrArray[i].Len() );
3147 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
3149 OutString += sSecStr.GetChar(nSecPos);
3150 nSecPos++;
3153 break;
3154 case NF_KEY_AMPM: // AM/PM
3156 if (cAmPm == 'a')
3157 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3158 AmPmValue::AM, 0 );
3159 else
3160 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3161 AmPmValue::PM, 0 );
3163 break;
3164 case NF_KEY_AP: // A/P
3166 if (cAmPm == 'a')
3167 OutString += 'a';
3168 else
3169 OutString += 'p';
3171 break;
3172 case NF_KEY_MI: // M
3173 OutString += ImpIntToString( nIx, nMin );
3174 break;
3175 case NF_KEY_MMI: // MM
3176 OutString += ImpIntToString( nIx, nMin, 2 );
3177 break;
3178 case NF_KEY_H: // H
3179 OutString += ImpIntToString( nIx, nHour );
3180 break;
3181 case NF_KEY_HH: // HH
3182 OutString += ImpIntToString( nIx, nHour, 2 );
3183 break;
3184 case NF_KEY_S: // S
3185 OutString += ImpIntToString( nIx, nSec );
3186 break;
3187 case NF_KEY_SS: // SS
3188 OutString += ImpIntToString( nIx, nSec, 2 );
3189 break;
3190 case NF_KEY_M: // M
3191 OutString += rCal.getDisplayString(
3192 CalendarDisplayCode::SHORT_MONTH, nNatNum );
3193 break;
3194 case NF_KEY_MM: // MM
3195 OutString += rCal.getDisplayString(
3196 CalendarDisplayCode::LONG_MONTH, nNatNum );
3197 break;
3198 case NF_KEY_MMM: // MMM
3199 OutString += rCal.getDisplayString(
3200 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
3201 break;
3202 case NF_KEY_MMMM: // MMMM
3203 OutString += rCal.getDisplayString(
3204 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
3205 break;
3206 case NF_KEY_MMMMM: // MMMMM
3207 OutString += rCal.getDisplayString(
3208 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
3209 break;
3210 case NF_KEY_Q: // Q
3211 OutString += rCal.getDisplayString(
3212 CalendarDisplayCode::SHORT_QUARTER, nNatNum );
3213 break;
3214 case NF_KEY_QQ: // QQ
3215 OutString += rCal.getDisplayString(
3216 CalendarDisplayCode::LONG_QUARTER, nNatNum );
3217 break;
3218 case NF_KEY_D: // D
3219 OutString += rCal.getDisplayString(
3220 CalendarDisplayCode::SHORT_DAY, nNatNum );
3221 break;
3222 case NF_KEY_DD: // DD
3223 OutString += rCal.getDisplayString(
3224 CalendarDisplayCode::LONG_DAY, nNatNum );
3225 break;
3226 case NF_KEY_DDD: // DDD
3228 if ( bOtherCalendar )
3229 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3230 OutString += rCal.getDisplayString(
3231 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3232 if ( bOtherCalendar )
3233 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3235 break;
3236 case NF_KEY_DDDD: // DDDD
3238 if ( bOtherCalendar )
3239 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3240 OutString += rCal.getDisplayString(
3241 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3242 if ( bOtherCalendar )
3243 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3245 break;
3246 case NF_KEY_YY: // YY
3248 if ( bOtherCalendar )
3249 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3250 OutString += rCal.getDisplayString(
3251 CalendarDisplayCode::SHORT_YEAR, nNatNum );
3252 if ( bOtherCalendar )
3253 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3255 break;
3256 case NF_KEY_YYYY: // YYYY
3258 if ( bOtherCalendar )
3259 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3260 OutString += rCal.getDisplayString(
3261 CalendarDisplayCode::LONG_YEAR, nNatNum );
3262 if ( bOtherCalendar )
3263 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3265 break;
3266 case NF_KEY_EC: // E
3267 OutString += rCal.getDisplayString(
3268 CalendarDisplayCode::SHORT_YEAR, nNatNum );
3269 break;
3270 case NF_KEY_EEC: // EE
3271 case NF_KEY_R: // R
3272 OutString += rCal.getDisplayString(
3273 CalendarDisplayCode::LONG_YEAR, nNatNum );
3274 break;
3275 case NF_KEY_NN: // NN
3276 case NF_KEY_AAA: // AAA
3277 OutString += rCal.getDisplayString(
3278 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3279 break;
3280 case NF_KEY_NNN: // NNN
3281 case NF_KEY_AAAA: // AAAA
3282 OutString += rCal.getDisplayString(
3283 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3284 break;
3285 case NF_KEY_NNNN: // NNNN
3287 OutString += rCal.getDisplayString(
3288 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3289 OutString += rLoc().getLongDateDayOfWeekSep();
3291 break;
3292 case NF_KEY_WW : // WW
3294 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3295 OutString += ImpIntToString( nIx, nVal );
3297 break;
3298 case NF_KEY_G: // G
3299 ImpAppendEraG( OutString, rCal, nNatNum );
3300 break;
3301 case NF_KEY_GG: // GG
3302 OutString += rCal.getDisplayString(
3303 CalendarDisplayCode::SHORT_ERA, nNatNum );
3304 break;
3305 case NF_KEY_GGG: // GGG
3306 OutString += rCal.getDisplayString(
3307 CalendarDisplayCode::LONG_ERA, nNatNum );
3308 break;
3309 case NF_KEY_RR: // RR => GGGEE
3310 OutString += rCal.getDisplayString(
3311 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3312 break;
3315 if ( aOrgCalendar.Len() )
3316 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
3317 return bRes;
3320 BOOL SvNumberformat::ImpGetNumberOutput(double fNumber,
3321 USHORT nIx,
3322 String& OutString)
3324 BOOL bRes = FALSE;
3325 BOOL bSign;
3326 if (fNumber < 0.0)
3328 if (nIx == 0) // nicht in hinteren
3329 bSign = TRUE; // Formaten
3330 else
3331 bSign = FALSE;
3332 fNumber = -fNumber;
3334 else
3336 bSign = FALSE;
3337 if ( ::rtl::math::isSignBitSet( fNumber ) )
3338 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
3340 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3341 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
3343 if (fNumber < _D_MAX_D_BY_100)
3344 fNumber *= 100.0;
3345 else
3347 OutString = rScan.GetErrorString();
3348 return FALSE;
3351 USHORT i, j;
3352 xub_StrLen k;
3353 String sStr;
3354 long nPrecExp;
3355 BOOL bInteger = FALSE;
3356 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
3357 { // special formatting only if no GENERAL keyword in format code
3358 const USHORT nThousand = rInfo.nThousand;
3359 for (i = 0; i < nThousand; i++)
3361 if (fNumber > _D_MIN_M_BY_1000)
3362 fNumber /= 1000.0;
3363 else
3364 fNumber = 0.0;
3366 if (fNumber > 0.0)
3367 nPrecExp = GetPrecExp( fNumber );
3368 else
3369 nPrecExp = 0;
3370 if (rInfo.nCntPost) // NachkommaStellen
3372 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
3374 sStr = ::rtl::math::doubleToUString( fNumber,
3375 rtl_math_StringFormat_F, 15-nPrecExp, '.');
3376 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
3377 sStr += '0';
3379 else
3380 sStr = ::rtl::math::doubleToUString( fNumber,
3381 rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
3382 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
3384 else if (fNumber == 0.0) // Null
3386 // nothing to be done here, keep empty string sStr,
3387 // ImpNumberFillWithThousands does the rest
3389 else // Integer
3391 sStr = ::rtl::math::doubleToUString( fNumber,
3392 rtl_math_StringFormat_F, 0, '.');
3393 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
3395 xub_StrLen nPoint = sStr.Search( '.' );
3396 if ( nPoint != STRING_NOTFOUND )
3398 register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
3399 while ( *++p == '0' )
3401 if ( !*p )
3402 bInteger = TRUE;
3403 sStr.Erase( nPoint, 1 ); // . herausnehmen
3405 if (bSign &&
3406 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000
3407 bSign = FALSE; // nicht -0.00
3408 } // End of != FLAG_STANDARD_IN_FORMAT
3410 // von hinten nach vorn
3411 // editieren:
3412 k = sStr.Len(); // hinter letzter Ziffer
3413 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol
3414 // Nachkommastellen:
3415 if (rInfo.nCntPost > 0)
3417 BOOL bTrailing = TRUE; // ob Endnullen?
3418 BOOL bFilled = FALSE; // ob aufgefuellt wurde ?
3419 short nType;
3420 while (j > 0 && // rueckwaerts
3421 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
3423 switch ( nType )
3425 case NF_SYMBOLTYPE_STAR:
3426 if( bStarFlag )
3428 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
3429 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3430 bRes = TRUE;
3432 break;
3433 case NF_SYMBOLTYPE_BLANK:
3434 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3435 break;
3436 case NF_SYMBOLTYPE_STRING:
3437 case NF_SYMBOLTYPE_CURRENCY:
3438 case NF_SYMBOLTYPE_PERCENT:
3439 sStr.Insert(rInfo.sStrArray[j],k);
3440 break;
3441 case NF_SYMBOLTYPE_THSEP:
3442 if (rInfo.nThousand == 0)
3443 sStr.Insert(rInfo.sStrArray[j],k);
3444 break;
3445 case NF_SYMBOLTYPE_DIGIT:
3447 const String& rStr = rInfo.sStrArray[j];
3448 const sal_Unicode* p1 = rStr.GetBuffer();
3449 register const sal_Unicode* p = p1 + rStr.Len();
3450 while ( p1 < p-- )
3452 const sal_Unicode c = *p;
3453 k--;
3454 if ( sStr.GetChar(k) != '0' )
3455 bTrailing = FALSE;
3456 if (bTrailing)
3458 if ( c == '0' )
3459 bFilled = TRUE;
3460 else if ( c == '-' )
3462 if ( bInteger )
3463 sStr.SetChar( k, '-' );
3464 bFilled = TRUE;
3466 else if ( c == '?' )
3468 sStr.SetChar( k, ' ' );
3469 bFilled = TRUE;
3471 else if ( !bFilled ) // #
3472 sStr.Erase(k,1);
3474 } // of for
3475 } // of case digi
3476 break;
3477 case NF_KEY_CCC: // CCC-Waehrung
3478 sStr.Insert(rScan.GetCurAbbrev(), k);
3479 break;
3480 case NF_KEY_GENERAL: // Standard im String
3482 String sNum;
3483 ImpGetOutputStandard(fNumber, sNum);
3484 sNum.EraseLeadingChars('-');
3485 sStr.Insert(sNum, k);
3487 break;
3488 default:
3489 break;
3490 } // of switch
3491 j--;
3492 } // of while
3493 } // of Nachkomma
3495 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
3496 rInfo.nCntPre);
3497 if ( rInfo.nCntPost > 0 )
3499 const String& rDecSep = GetFormatter().GetNumDecimalSep();
3500 xub_StrLen nLen = rDecSep.Len();
3501 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
3502 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep
3504 if (bSign)
3505 sStr.Insert('-',0);
3506 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
3507 OutString = sStr;
3508 return bRes;
3511 BOOL SvNumberformat::ImpNumberFillWithThousands(
3512 String& sStr, // number string
3513 double& rNumber, // number
3514 xub_StrLen k, // position within string
3515 USHORT j, // symbol index within format code
3516 USHORT nIx, // subformat index
3517 USHORT nDigCnt) // count of integer digits in format
3519 BOOL bRes = FALSE;
3520 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
3521 xub_StrLen nDigitCount = 0; // count of integer digits from the right
3522 BOOL bStop = FALSE;
3523 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3524 // no normal thousands separators if number divided by thousands
3525 BOOL bDoThousands = (rInfo.nThousand == 0);
3526 utl::DigitGroupingIterator aGrouping(
3527 GetFormatter().GetLocaleData()->getDigitGrouping());
3528 while (!bStop) // backwards
3530 if (j == 0)
3531 bStop = TRUE;
3532 switch (rInfo.nTypeArray[j])
3534 case NF_SYMBOLTYPE_DECSEP:
3535 aGrouping.reset();
3536 // fall thru
3537 case NF_SYMBOLTYPE_STRING:
3538 case NF_SYMBOLTYPE_CURRENCY:
3539 case NF_SYMBOLTYPE_PERCENT:
3540 sStr.Insert(rInfo.sStrArray[j],k);
3541 if ( k == 0 )
3542 nLeadingStringChars =
3543 nLeadingStringChars + rInfo.sStrArray[j].Len();
3544 break;
3545 case NF_SYMBOLTYPE_STAR:
3546 if( bStarFlag )
3548 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
3549 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3550 bRes = TRUE;
3552 break;
3553 case NF_SYMBOLTYPE_BLANK:
3554 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3555 break;
3556 case NF_SYMBOLTYPE_THSEP:
3558 // #i7284# #102685# Insert separator also if number is divided
3559 // by thousands and the separator is specified somewhere in
3560 // between and not only at the end.
3561 // #i12596# But do not insert if it's a parenthesized negative
3562 // format like (#,)
3563 // In fact, do not insert if divided and regex [0#,],[^0#] and
3564 // no other digit symbol follows (which was already detected
3565 // during scan of format code, otherwise there would be no
3566 // division), else do insert. Same in ImpNumberFill() below.
3567 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3568 bDoThousands = ((j == 0) ||
3569 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3570 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3571 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3572 if ( bDoThousands )
3574 if (k > 0)
3575 sStr.Insert(rInfo.sStrArray[j],k);
3576 else if (nDigitCount < nDigCnt)
3578 // Leading '#' displays nothing (e.g. no leading
3579 // separator for numbers <1000 with #,##0 format).
3580 // Leading '?' displays blank.
3581 // Everything else, including nothing, displays the
3582 // separator.
3583 sal_Unicode cLeader = 0;
3584 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
3586 const String& rStr = rInfo.sStrArray[j-1];
3587 xub_StrLen nLen = rStr.Len();
3588 if (nLen)
3589 cLeader = rStr.GetChar(nLen-1);
3591 switch (cLeader)
3593 case '#':
3594 ; // nothing
3595 break;
3596 case '?':
3597 // erAck: 2008-04-03T16:24+0200
3598 // Actually this currently isn't executed
3599 // because the format scanner in the context of
3600 // "?," doesn't generate a group separator but
3601 // a literal ',' character instead that is
3602 // inserted unconditionally. Should be changed
3603 // on some occasion.
3604 sStr.Insert(' ',k);
3605 break;
3606 default:
3607 sStr.Insert(rInfo.sStrArray[j],k);
3610 aGrouping.advance();
3613 break;
3614 case NF_SYMBOLTYPE_DIGIT:
3616 const String& rStr = rInfo.sStrArray[j];
3617 const sal_Unicode* p1 = rStr.GetBuffer();
3618 register const sal_Unicode* p = p1 + rStr.Len();
3619 while ( p1 < p-- )
3621 nDigitCount++;
3622 if (k > 0)
3623 k--;
3624 else
3626 switch (*p)
3628 case '0':
3629 sStr.Insert('0',0);
3630 break;
3631 case '?':
3632 sStr.Insert(' ',0);
3633 break;
3636 if (nDigitCount == nDigCnt && k > 0)
3637 { // more digits than specified
3638 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
3642 break;
3643 case NF_KEY_CCC: // CCC currency
3644 sStr.Insert(rScan.GetCurAbbrev(), k);
3645 break;
3646 case NF_KEY_GENERAL: // "General" in string
3648 String sNum;
3649 ImpGetOutputStandard(rNumber, sNum);
3650 sNum.EraseLeadingChars('-');
3651 sStr.Insert(sNum, k);
3653 break;
3655 default:
3656 break;
3657 } // switch
3658 j--; // next format code string
3659 } // while
3660 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ...
3661 if (k > nLeadingStringChars)
3662 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
3663 return bRes;
3666 void SvNumberformat::ImpDigitFill(
3667 String& sStr, // number string
3668 xub_StrLen nStart, // start of digits
3669 xub_StrLen& k, // position within string
3670 USHORT nIx, // subformat index
3671 xub_StrLen & nDigitCount, // count of integer digits from the right so far
3672 utl::DigitGroupingIterator & rGrouping ) // current grouping
3674 if (NumFor[nIx].Info().bThousand) // only if grouping
3675 { // fill in separators
3676 const String& rThousandSep = GetFormatter().GetNumThousandSep();
3677 while (k > nStart)
3679 if (nDigitCount == rGrouping.getPos())
3681 sStr.Insert( rThousandSep, k );
3682 rGrouping.advance();
3684 nDigitCount++;
3685 k--;
3688 else // simply skip
3689 k = nStart;
3692 BOOL SvNumberformat::ImpNumberFill( String& sStr, // number string
3693 double& rNumber, // number for "General" format
3694 xub_StrLen& k, // position within string
3695 USHORT& j, // symbol index within format code
3696 USHORT nIx, // subformat index
3697 short eSymbolType ) // type of stop condition
3699 BOOL bRes = FALSE;
3700 k = sStr.Len(); // behind last digit
3701 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3702 // no normal thousands separators if number divided by thousands
3703 BOOL bDoThousands = (rInfo.nThousand == 0);
3704 short nType;
3705 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
3706 { // rueckwaerts:
3707 switch ( nType )
3709 case NF_SYMBOLTYPE_STAR:
3710 if( bStarFlag )
3712 sStr.Insert( sal_Unicode(0x1B), k++ );
3713 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3714 bRes = TRUE;
3716 break;
3717 case NF_SYMBOLTYPE_BLANK:
3718 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3719 break;
3720 case NF_SYMBOLTYPE_THSEP:
3722 // Same as in ImpNumberFillWithThousands() above, do not insert
3723 // if divided and regex [0#,],[^0#] and no other digit symbol
3724 // follows (which was already detected during scan of format
3725 // code, otherwise there would be no division), else do insert.
3726 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3727 bDoThousands = ((j == 0) ||
3728 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3729 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3730 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3731 if ( bDoThousands && k > 0 )
3733 sStr.Insert(rInfo.sStrArray[j],k);
3736 break;
3737 case NF_SYMBOLTYPE_DIGIT:
3739 const String& rStr = rInfo.sStrArray[j];
3740 const sal_Unicode* p1 = rStr.GetBuffer();
3741 register const sal_Unicode* p = p1 + rStr.Len();
3742 while ( p1 < p-- )
3744 if (k > 0)
3745 k--;
3746 else
3748 switch (*p)
3750 case '0':
3751 sStr.Insert('0',0);
3752 break;
3753 case '?':
3754 sStr.Insert(' ',0);
3755 break;
3760 break;
3761 case NF_KEY_CCC: // CCC-Waehrung
3762 sStr.Insert(rScan.GetCurAbbrev(), k);
3763 break;
3764 case NF_KEY_GENERAL: // Standard im String
3766 String sNum;
3767 ImpGetOutputStandard(rNumber, sNum);
3768 sNum.EraseLeadingChars('-'); // Vorzeichen weg!!
3769 sStr.Insert(sNum, k);
3771 break;
3773 default:
3774 sStr.Insert(rInfo.sStrArray[j],k);
3775 break;
3776 } // of switch
3777 j--; // naechster String
3778 } // of while
3779 return bRes;
3782 void SvNumberformat::GetFormatSpecialInfo(BOOL& bThousand,
3783 BOOL& IsRed,
3784 USHORT& nPrecision,
3785 USHORT& nAnzLeading) const
3787 // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3789 short nDummyType;
3790 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
3792 // "negative in red" is only useful for the whole format
3794 const Color* pColor = NumFor[1].GetColor();
3795 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
3796 && (*pColor == rScan.GetRedColor()))
3797 IsRed = TRUE;
3798 else
3799 IsRed = FALSE;
3802 void SvNumberformat::GetNumForInfo( USHORT nNumFor, short& rScannedType,
3803 BOOL& bThousand, USHORT& nPrecision, USHORT& nAnzLeading ) const
3805 // take info from a specified sub-format (for XML export)
3807 if ( nNumFor > 3 )
3808 return; // invalid
3810 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
3811 rScannedType = rInfo.eScannedType;
3812 bThousand = rInfo.bThousand;
3813 nPrecision = rInfo.nCntPost;
3814 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
3815 // StandardFormat
3816 nAnzLeading = 1;
3817 else
3819 nAnzLeading = 0;
3820 BOOL bStop = FALSE;
3821 USHORT i = 0;
3822 const USHORT nAnz = NumFor[nNumFor].GetnAnz();
3823 while (!bStop && i < nAnz)
3825 short nType = rInfo.nTypeArray[i];
3826 if ( nType == NF_SYMBOLTYPE_DIGIT)
3828 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
3829 while ( *p == '#' )
3830 p++;
3831 while ( *p++ == '0' )
3832 nAnzLeading++;
3834 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
3835 bStop = TRUE;
3836 i++;
3841 const String* SvNumberformat::GetNumForString( USHORT nNumFor, USHORT nPos,
3842 BOOL bString /* = FALSE */ ) const
3844 if ( nNumFor > 3 )
3845 return NULL;
3846 USHORT nAnz = NumFor[nNumFor].GetnAnz();
3847 if ( !nAnz )
3848 return NULL;
3849 if ( nPos == 0xFFFF )
3851 nPos = nAnz - 1;
3852 if ( bString )
3853 { // rueckwaerts
3854 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3855 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3856 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3858 pType--;
3859 nPos--;
3861 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3862 return NULL;
3865 else if ( nPos > nAnz - 1 )
3866 return NULL;
3867 else if ( bString )
3868 { // vorwaerts
3869 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3870 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3871 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3873 pType++;
3874 nPos++;
3876 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
3877 (*pType != NF_SYMBOLTYPE_CURRENCY)) )
3878 return NULL;
3880 return &NumFor[nNumFor].Info().sStrArray[nPos];
3884 short SvNumberformat::GetNumForType( USHORT nNumFor, USHORT nPos,
3885 BOOL bString /* = FALSE */ ) const
3887 if ( nNumFor > 3 )
3888 return 0;
3889 USHORT nAnz = NumFor[nNumFor].GetnAnz();
3890 if ( !nAnz )
3891 return 0;
3892 if ( nPos == 0xFFFF )
3894 nPos = nAnz - 1;
3895 if ( bString )
3896 { // rueckwaerts
3897 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3898 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3899 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3901 pType--;
3902 nPos--;
3904 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3905 return 0;
3908 else if ( nPos > nAnz - 1 )
3909 return 0;
3910 else if ( bString )
3911 { // vorwaerts
3912 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3913 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3914 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3916 pType++;
3917 nPos++;
3919 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3920 return 0;
3922 return NumFor[nNumFor].Info().nTypeArray[nPos];
3926 BOOL SvNumberformat::IsNegativeWithoutSign() const
3928 if ( IsNegativeRealNegative() )
3930 const String* pStr = GetNumForString( 1, 0, TRUE );
3931 if ( pStr )
3932 return !HasStringNegativeSign( *pStr );
3934 return FALSE;
3938 DateFormat SvNumberformat::GetDateOrder() const
3940 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
3942 short const * const pType = NumFor[0].Info().nTypeArray;
3943 USHORT nAnz = NumFor[0].GetnAnz();
3944 for ( USHORT j=0; j<nAnz; j++ )
3946 switch ( pType[j] )
3948 case NF_KEY_D :
3949 case NF_KEY_DD :
3950 return DMY;
3951 case NF_KEY_M :
3952 case NF_KEY_MM :
3953 case NF_KEY_MMM :
3954 case NF_KEY_MMMM :
3955 case NF_KEY_MMMMM :
3956 return MDY;
3957 case NF_KEY_YY :
3958 case NF_KEY_YYYY :
3959 case NF_KEY_EC :
3960 case NF_KEY_EEC :
3961 case NF_KEY_R :
3962 case NF_KEY_RR :
3963 return YMD;
3967 else
3969 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
3971 return rLoc().getDateFormat();
3975 sal_uInt32 SvNumberformat::GetExactDateOrder() const
3977 sal_uInt32 nRet = 0;
3978 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
3980 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
3981 return nRet;
3983 short const * const pType = NumFor[0].Info().nTypeArray;
3984 USHORT nAnz = NumFor[0].GetnAnz();
3985 int nShift = 0;
3986 for ( USHORT j=0; j<nAnz && nShift < 3; j++ )
3988 switch ( pType[j] )
3990 case NF_KEY_D :
3991 case NF_KEY_DD :
3992 nRet = (nRet << 8) | 'D';
3993 ++nShift;
3994 break;
3995 case NF_KEY_M :
3996 case NF_KEY_MM :
3997 case NF_KEY_MMM :
3998 case NF_KEY_MMMM :
3999 case NF_KEY_MMMMM :
4000 nRet = (nRet << 8) | 'M';
4001 ++nShift;
4002 break;
4003 case NF_KEY_YY :
4004 case NF_KEY_YYYY :
4005 case NF_KEY_EC :
4006 case NF_KEY_EEC :
4007 case NF_KEY_R :
4008 case NF_KEY_RR :
4009 nRet = (nRet << 8) | 'Y';
4010 ++nShift;
4011 break;
4014 return nRet;
4018 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
4019 SvNumberformatLimitOps& rOper2, double& rVal2 ) const
4021 rOper1 = eOp1;
4022 rOper2 = eOp2;
4023 rVal1 = fLimit1;
4024 rVal2 = fLimit2;
4028 Color* SvNumberformat::GetColor( USHORT nNumFor ) const
4030 if ( nNumFor > 3 )
4031 return NULL;
4033 return NumFor[nNumFor].GetColor();
4037 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
4038 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
4040 if ( eOp != NUMBERFORMAT_OP_NO )
4042 switch ( eOp )
4044 case NUMBERFORMAT_OP_EQ :
4045 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4046 break;
4047 case NUMBERFORMAT_OP_NE :
4048 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4049 break;
4050 case NUMBERFORMAT_OP_LT :
4051 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4052 break;
4053 case NUMBERFORMAT_OP_LE :
4054 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4055 break;
4056 case NUMBERFORMAT_OP_GT :
4057 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4058 break;
4059 case NUMBERFORMAT_OP_GE :
4060 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4061 break;
4062 default:
4063 OSL_ASSERT( "unsupported number format" );
4064 break;
4066 rStr += String( ::rtl::math::doubleToUString( fLimit,
4067 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4068 rDecSep.GetChar(0), sal_True));
4069 rStr += ']';
4074 String SvNumberformat::GetMappedFormatstring(
4075 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
4076 BOOL bDontQuote ) const
4078 String aStr;
4079 BOOL bDefault[4];
4080 // 1 subformat matches all if no condition specified,
4081 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
4082 // with 2 subformats [>=0];[<0] is implied if no condition specified
4083 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
4084 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
4085 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
4086 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4087 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4088 bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
4089 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
4090 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
4091 BOOL bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
4092 // from now on bDefault[] values are used to append empty subformats at the end
4093 bDefault[3] = FALSE;
4094 if ( !bDefaults )
4095 { // conditions specified
4096 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
4097 bDefault[0] = bDefault[1] = TRUE; // [];x
4098 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
4099 NumFor[2].GetnAnz() == 0 )
4100 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = TRUE; // [];[];;
4101 // nothing to do if conditions specified for every subformat
4103 else if ( bDefault[0] )
4104 bDefault[0] = FALSE; // a single unconditional subformat is never delimited
4105 else
4107 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
4108 bDefault[3] = TRUE; // special cases x;x;; and ;x;;
4109 for ( int i=0; i<3 && !bDefault[i]; ++i )
4110 bDefault[i] = TRUE;
4112 int nSem = 0; // needed ';' delimiters
4113 int nSub = 0; // subformats delimited so far
4114 for ( int n=0; n<4; n++ )
4116 if ( n > 0 )
4117 nSem++;
4119 String aPrefix;
4121 if ( !bDefaults )
4123 switch ( n )
4125 case 0 :
4126 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
4127 fLimit1, rLocWrp.getNumDecimalSep() );
4128 break;
4129 case 1 :
4130 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
4131 fLimit2, rLocWrp.getNumDecimalSep() );
4132 break;
4136 const String& rColorName = NumFor[n].GetColorName();
4137 if ( rColorName.Len() )
4139 const String* pKey = rScan.GetKeywords() + NF_KEY_FIRSTCOLOR;
4140 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++, pKey++ )
4142 if ( *pKey == rColorName )
4144 aPrefix += '[';
4145 aPrefix += rKeywords[j];
4146 aPrefix += ']';
4147 break; // for
4152 const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
4153 // The Thai T NatNum modifier during Xcl export.
4154 if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
4155 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
4156 MsLangId::getRealLanguage( rNum.GetLang()) ==
4157 LANGUAGE_THAI)
4159 aPrefix += 't'; // must be lowercase, otherwise taken as literal
4162 USHORT nAnz = NumFor[n].GetnAnz();
4163 if ( nSem && (nAnz || aPrefix.Len()) )
4165 for ( ; nSem; --nSem )
4166 aStr += ';';
4167 for ( ; nSub <= n; ++nSub )
4168 bDefault[nSub] = FALSE;
4171 if ( aPrefix.Len() )
4172 aStr += aPrefix;
4174 if ( nAnz )
4176 const short* pType = NumFor[n].Info().nTypeArray;
4177 const String* pStr = NumFor[n].Info().sStrArray;
4178 for ( USHORT j=0; j<nAnz; j++ )
4180 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
4182 aStr += rKeywords[pType[j]];
4183 if( NF_KEY_NNNN == pType[j] )
4184 aStr += rLocWrp.getLongDateDayOfWeekSep();
4186 else
4188 switch ( pType[j] )
4190 case NF_SYMBOLTYPE_DECSEP :
4191 aStr += rLocWrp.getNumDecimalSep();
4192 break;
4193 case NF_SYMBOLTYPE_THSEP :
4194 aStr += rLocWrp.getNumThousandSep();
4195 break;
4196 case NF_SYMBOLTYPE_DATESEP :
4197 aStr += rLocWrp.getDateSep();
4198 break;
4199 case NF_SYMBOLTYPE_TIMESEP :
4200 aStr += rLocWrp.getTimeSep();
4201 break;
4202 case NF_SYMBOLTYPE_TIME100SECSEP :
4203 aStr += rLocWrp.getTime100SecSep();
4204 break;
4205 case NF_SYMBOLTYPE_STRING :
4206 if( bDontQuote )
4207 aStr += pStr[j];
4208 else if ( pStr[j].Len() == 1 )
4210 aStr += '\\';
4211 aStr += pStr[j];
4213 else
4215 aStr += '"';
4216 aStr += pStr[j];
4217 aStr += '"';
4219 break;
4220 default:
4221 aStr += pStr[j];
4228 for ( ; nSub<4 && bDefault[nSub]; ++nSub )
4229 { // append empty subformats
4230 aStr += ';';
4232 return aStr;
4236 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
4237 sal_Int32 nVal, USHORT nMinDigits ) const
4239 String aStr;
4240 if ( nMinDigits )
4242 if ( nMinDigits == 2 )
4243 { // speed up the most common case
4244 if ( 0 <= nVal && nVal < 10 )
4246 sal_Unicode* p = aStr.AllocBuffer( 2 );
4247 *p++ = '0';
4248 *p = sal_Unicode( '0' + nVal );
4250 else
4251 aStr = String::CreateFromInt32( nVal );
4253 else
4255 String aValStr( String::CreateFromInt32( nVal ) );
4256 if ( aValStr.Len() >= nMinDigits )
4257 aStr = aValStr;
4258 else
4260 aStr.Fill( nMinDigits - aValStr.Len(), '0' );
4261 aStr += aValStr;
4265 else
4266 aStr = String::CreateFromInt32( nVal );
4267 ImpTransliterate( aStr, rNum );
4268 return aStr;
4272 void SvNumberformat::ImpTransliterateImpl( String& rStr,
4273 const SvNumberNatNum& rNum ) const
4275 com::sun::star::lang::Locale aLocale(
4276 MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4277 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
4278 aLocale, rNum.GetNatNum() );
4282 void SvNumberformat::GetNatNumXml(
4283 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
4284 USHORT nNumFor ) const
4286 if ( nNumFor <= 3 )
4288 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
4289 if ( rNum.IsSet() )
4291 com::sun::star::lang::Locale aLocale(
4292 MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4293 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
4294 aLocale, rNum.GetNatNum() );
4296 else
4297 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4299 else
4300 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4303 // static
4304 BOOL SvNumberformat::HasStringNegativeSign( const String& rStr )
4306 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4307 xub_StrLen nLen = rStr.Len();
4308 if ( !nLen )
4309 return FALSE;
4310 const sal_Unicode* const pBeg = rStr.GetBuffer();
4311 const sal_Unicode* const pEnd = pBeg + nLen;
4312 register const sal_Unicode* p = pBeg;
4314 { // Anfang
4315 if ( *p == '-' )
4316 return TRUE;
4317 } while ( *p == ' ' && ++p < pEnd );
4318 p = pEnd - 1;
4320 { // Ende
4321 if ( *p == '-' )
4322 return TRUE;
4323 } while ( *p == ' ' && pBeg < --p );
4324 return FALSE;
4328 // static
4329 void SvNumberformat::SetComment( const String& rStr, String& rFormat,
4330 String& rComment )
4332 if ( rComment.Len() )
4333 { // alten Kommentar aus Formatstring loeschen
4334 //! nicht per EraseComment, der Kommentar muss matchen
4335 String aTmp( '{' );
4336 aTmp += ' ';
4337 aTmp += rComment;
4338 aTmp += ' ';
4339 aTmp += '}';
4340 xub_StrLen nCom = 0;
4343 nCom = rFormat.Search( aTmp, nCom );
4344 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
4345 if ( nCom != STRING_NOTFOUND )
4346 rFormat.Erase( nCom );
4348 if ( rStr.Len() )
4349 { // neuen Kommentar setzen
4350 rFormat += '{';
4351 rFormat += ' ';
4352 rFormat += rStr;
4353 rFormat += ' ';
4354 rFormat += '}';
4355 rComment = rStr;
4360 // static
4361 void SvNumberformat::EraseCommentBraces( String& rStr )
4363 xub_StrLen nLen = rStr.Len();
4364 if ( nLen && rStr.GetChar(0) == '{' )
4366 rStr.Erase( 0, 1 );
4367 --nLen;
4369 if ( nLen && rStr.GetChar(0) == ' ' )
4371 rStr.Erase( 0, 1 );
4372 --nLen;
4374 if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
4375 rStr.Erase( --nLen, 1 );
4376 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
4377 rStr.Erase( --nLen, 1 );
4381 // static
4382 void SvNumberformat::EraseComment( String& rStr )
4384 register const sal_Unicode* p = rStr.GetBuffer();
4385 BOOL bInString = FALSE;
4386 BOOL bEscaped = FALSE;
4387 BOOL bFound = FALSE;
4388 xub_StrLen nPos = 0;
4389 while ( !bFound && *p )
4391 switch ( *p )
4393 case '\\' :
4394 bEscaped = !bEscaped;
4395 break;
4396 case '\"' :
4397 if ( !bEscaped )
4398 bInString = !bInString;
4399 break;
4400 case '{' :
4401 if ( !bEscaped && !bInString )
4403 bFound = TRUE;
4404 nPos = sal::static_int_cast< xub_StrLen >(
4405 p - rStr.GetBuffer());
4407 break;
4409 if ( bEscaped && *p != '\\' )
4410 bEscaped = FALSE;
4411 ++p;
4413 if ( bFound )
4414 rStr.Erase( nPos );
4418 // static
4419 BOOL SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
4420 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4422 xub_StrLen nLen = rStr.Len();
4423 if ( nPos >= nLen )
4424 return FALSE;
4425 register const sal_Unicode* p0 = rStr.GetBuffer();
4426 register const sal_Unicode* p = p0;
4427 register const sal_Unicode* p1 = p0 + nPos;
4428 BOOL bQuoted = FALSE;
4429 while ( p <= p1 )
4431 if ( *p == cQuote )
4433 if ( p == p0 )
4434 bQuoted = TRUE;
4435 else if ( bQuoted )
4437 if ( *(p-1) != cEscIn )
4438 bQuoted = FALSE;
4440 else
4442 if ( *(p-1) != cEscOut )
4443 bQuoted = TRUE;
4446 p++;
4448 return bQuoted;
4452 // static
4453 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
4454 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4456 xub_StrLen nLen = rStr.Len();
4457 if ( nPos >= nLen )
4458 return STRING_NOTFOUND;
4459 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
4461 if ( rStr.GetChar( nPos ) == cQuote )
4462 return nPos; // schliessendes cQuote
4463 return STRING_NOTFOUND;
4465 register const sal_Unicode* p0 = rStr.GetBuffer();
4466 register const sal_Unicode* p = p0 + nPos;
4467 register const sal_Unicode* p1 = p0 + nLen;
4468 while ( p < p1 )
4470 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
4471 return sal::static_int_cast< xub_StrLen >(p - p0);
4472 p++;
4474 return nLen; // String Ende
4478 USHORT SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor ) const
4480 USHORT nCnt = 0;
4481 USHORT nAnz = NumFor[nNumFor].GetnAnz();
4482 short const * const pType = NumFor[nNumFor].Info().nTypeArray;
4483 for ( USHORT j=0; j<nAnz; ++j )
4485 switch ( pType[j] )
4487 case NF_SYMBOLTYPE_STRING:
4488 case NF_SYMBOLTYPE_CURRENCY:
4489 case NF_SYMBOLTYPE_DATESEP:
4490 case NF_SYMBOLTYPE_TIMESEP:
4491 case NF_SYMBOLTYPE_TIME100SECSEP:
4492 case NF_SYMBOLTYPE_PERCENT:
4493 ++nCnt;
4494 break;
4497 return nCnt;