update dev300-m58
[ooovba.git] / svtools / source / numbers / zformat.cxx
blob368fb160b002746559b14905b27ddae948377585
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::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
1920 ULONG y0, ULONG y1,
1921 ULONG& x2,ULONG& y2)
1923 x2 = ((y0+nPrec)/y1)*x1 - x0;
1924 y2 = ((y0+nPrec)/y1)*y1 - y0;
1927 ULONG SvNumberformat::ImpGGT(ULONG x, ULONG y)
1929 if (y == 0)
1930 return x;
1931 else
1933 ULONG z = x%y;
1934 while (z)
1936 x = y;
1937 y = z;
1938 z = x%y;
1940 return y;
1944 ULONG SvNumberformat::ImpGGTRound(ULONG x, ULONG y)
1946 if (y == 0)
1947 return x;
1948 else
1950 ULONG z = x%y;
1951 while ((double)z/(double)y > D_EPS)
1953 x = y;
1954 y = z;
1955 z = x%y;
1957 return y;
1961 BOOL SvNumberformat::GetOutputString(double fNumber,
1962 String& OutString,
1963 Color** ppColor)
1965 BOOL bRes = FALSE;
1966 OutString.Erase(); // alles loeschen
1967 *ppColor = NULL; // keine Farbaenderung
1968 if (eType & NUMBERFORMAT_LOGICAL)
1970 if (fNumber)
1971 OutString = rScan.GetTrueString();
1972 else
1973 OutString = rScan.GetFalseString();
1974 return FALSE;
1976 if (eType & NUMBERFORMAT_TEXT && bStandard)
1978 ImpGetOutputStandard(fNumber, OutString);
1979 return FALSE;
1981 BOOL bHadStandard = FALSE;
1982 if (bStandard) // einzelne Standardformate
1984 if (rScan.GetStandardPrec() == 300) // alle Zahlformate InputLine
1986 ImpGetOutputInputLine(fNumber, OutString);
1987 return FALSE;
1989 switch (eType)
1991 case NUMBERFORMAT_NUMBER: // Standardzahlformat
1992 ImpGetOutputStandard(fNumber, OutString);
1993 bHadStandard = TRUE;
1994 break;
1995 case NUMBERFORMAT_DATE:
1996 bRes |= ImpGetDateOutput(fNumber, 0, OutString);
1997 bHadStandard = TRUE;
1998 break;
1999 case NUMBERFORMAT_TIME:
2000 bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
2001 bHadStandard = TRUE;
2002 break;
2003 case NUMBERFORMAT_DATETIME:
2004 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
2005 bHadStandard = TRUE;
2006 break;
2009 if ( !bHadStandard )
2011 USHORT nIx; // Index des Teilformats
2012 short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
2013 if (nCheck == -1 || nCheck == 1) // nur 1 String oder True
2014 nIx = 0;
2015 else
2017 nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
2018 if (nCheck == -1 || nCheck == 1)
2019 nIx = 1;
2020 else
2021 nIx = 2;
2023 if (nIx == 1 && fNumber < 0.0 && // negatives Format
2024 IsNegativeRealNegative() ) // ohne Vorzeichen
2025 fNumber = -fNumber; // Vorzeichen eliminieren
2026 *ppColor = NumFor[nIx].GetColor();
2027 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2028 const USHORT nAnz = NumFor[nIx].GetnAnz();
2029 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
2030 return FALSE; // leer => nichts
2031 else if (nAnz == 0) // sonst Standard-Format
2033 ImpGetOutputStandard(fNumber, OutString);
2034 return FALSE;
2036 switch (rInfo.eScannedType)
2038 case NUMBERFORMAT_TEXT:
2039 case NUMBERFORMAT_DEFINED:
2041 for (USHORT i = 0; i < nAnz; i++)
2043 switch (rInfo.nTypeArray[i])
2045 case NF_SYMBOLTYPE_STAR:
2046 if( bStarFlag )
2048 OutString += (sal_Unicode) 0x1B;
2049 OutString += rInfo.sStrArray[i].GetChar(1);
2050 bRes = TRUE;
2052 break;
2053 case NF_SYMBOLTYPE_BLANK:
2054 InsertBlanks( OutString, OutString.Len(),
2055 rInfo.sStrArray[i].GetChar(1) );
2056 break;
2057 case NF_SYMBOLTYPE_STRING:
2058 case NF_SYMBOLTYPE_CURRENCY:
2059 OutString += rInfo.sStrArray[i];
2060 break;
2061 case NF_SYMBOLTYPE_THSEP:
2062 if (rInfo.nThousand == 0)
2063 OutString += rInfo.sStrArray[i];
2064 break;
2065 default:
2066 break;
2070 break;
2071 case NUMBERFORMAT_DATE:
2072 bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
2073 break;
2074 case NUMBERFORMAT_TIME:
2075 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
2076 break;
2077 case NUMBERFORMAT_DATETIME:
2078 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
2079 break;
2080 case NUMBERFORMAT_NUMBER:
2081 case NUMBERFORMAT_PERCENT:
2082 case NUMBERFORMAT_CURRENCY:
2083 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
2084 break;
2085 case NUMBERFORMAT_FRACTION:
2087 String sStr, sFrac, sDiv; // Strings, Wert fuer
2088 ULONG nFrac, nDiv; // Vorkommaanteil
2089 // Zaehler und Nenner
2090 BOOL bSign = FALSE;
2091 if (fNumber < 0)
2093 if (nIx == 0) // nicht in hinteren
2094 bSign = TRUE; // Formaten
2095 fNumber = -fNumber;
2097 double fNum = floor(fNumber); // Vorkommateil
2098 fNumber -= fNum; // Nachkommateil
2099 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
2100 // zu gross
2102 OutString = rScan.GetErrorString();
2103 return FALSE;
2105 if (rInfo.nCntExp == 0)
2107 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2108 return FALSE;
2110 ULONG nBasis = ((ULONG)floor( // 9, 99, 999 ,...
2111 pow(10.0,rInfo.nCntExp))) - 1;
2112 ULONG x0, y0, x1, y1;
2114 if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
2116 BOOL bUpperHalf;
2117 if (fNumber > 0.5)
2119 bUpperHalf = TRUE;
2120 fNumber -= (fNumber - 0.5) * 2.0;
2122 else
2123 bUpperHalf = FALSE;
2124 // Einstieg in Farey-Serie
2125 // finden:
2126 x0 = (ULONG) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
2127 if (x0 == 0) // => x0 = 2
2129 y0 = 1;
2130 x1 = 1;
2131 y1 = nBasis;
2133 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2
2134 { // geht (nBasis ungerade)
2135 y0 = nBasis;
2136 x1 = 1;
2137 y1 = 2;
2139 else if (x0 == 1)
2141 y0 = nBasis; // 1/n; 1/(n-1)
2142 x1 = 1;
2143 y1 = nBasis - 1;
2145 else
2147 y0 = nBasis; // z.B. 2/9 2/8
2148 x1 = x0;
2149 y1 = nBasis - 1;
2150 double fUg = (double) x0 / (double) y0;
2151 double fOg = (double) x1 / (double) y1;
2152 ULONG nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
2153 x0 /= nGgt;
2154 y0 /= nGgt; // Einschachteln:
2155 ULONG x2 = 0;
2156 ULONG y2 = 0;
2157 BOOL bStop = FALSE;
2158 while (!bStop)
2160 #ifdef GCC
2161 // #i21648# GCC over-optimizes something resulting
2162 // in wrong fTest values throughout the loops.
2163 volatile
2164 #endif
2165 double fTest = (double)x1/(double)y1;
2166 while (!bStop)
2168 while (fTest > fOg)
2170 x1--;
2171 fTest = (double)x1/(double)y1;
2173 while (fTest < fUg && y1 > 1)
2175 y1--;
2176 fTest = (double)x1/(double)y1;
2178 if (fTest <= fOg)
2180 fOg = fTest;
2181 bStop = TRUE;
2183 else if (y1 == 1)
2184 bStop = TRUE;
2185 } // of while
2186 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen
2187 x2 = x1 / nGgt;
2188 y2 = y1 / nGgt;
2189 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2
2190 bStop = TRUE; // naechste Farey-Zahl
2191 else
2193 y1--;
2194 bStop = FALSE;
2196 } // of while
2197 x1 = x2;
2198 y1 = y2;
2199 } // of else
2200 double fup, flow;
2201 flow = (double)x0/(double)y0;
2202 fup = (double)x1/(double)y1;
2203 while (fNumber > fup)
2205 ULONG x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
2206 ULONG y2 = ((y0+nBasis)/y1)*y1 - y0;
2207 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2208 x0 = x1;
2209 y0 = y1;
2210 x1 = x2;
2211 y1 = y2;
2212 flow = fup;
2213 fup = (double)x1/(double)y1;
2215 if (fNumber - flow < fup - fNumber)
2217 nFrac = x0;
2218 nDiv = y0;
2220 else
2222 nFrac = x1;
2223 nDiv = y1;
2225 if (bUpperHalf) // Original restaur.
2227 if (nFrac == 0 && nDiv == 1) // 1/1
2228 fNum += 1.0;
2229 else
2230 nFrac = nDiv - nFrac;
2233 else // grosse Nenner
2234 { // 0,1234->123/1000
2235 ULONG nGgt;
2237 nDiv = nBasis+1;
2238 nFrac = ((ULONG)floor(0.5 + fNumber *
2239 pow(10.0,rInfo.nCntExp)));
2241 nDiv = 10000000;
2242 nFrac = ((ULONG)floor(0.5 + fNumber * 10000000.0));
2243 nGgt = ImpGGT(nDiv, nFrac);
2244 if (nGgt > 1)
2246 nDiv /= nGgt;
2247 nFrac /= nGgt;
2249 if (nDiv > nBasis)
2251 nGgt = ImpGGTRound(nDiv, nFrac);
2252 if (nGgt > 1)
2254 nDiv /= nGgt;
2255 nFrac /= nGgt;
2258 if (nDiv > nBasis)
2260 nDiv = nBasis;
2261 nFrac = ((ULONG)floor(0.5 + fNumber *
2262 pow(10.0,rInfo.nCntExp)));
2263 nGgt = ImpGGTRound(nDiv, nFrac);
2264 if (nGgt > 1)
2266 nDiv /= nGgt;
2267 nFrac /= nGgt;
2272 if (rInfo.nCntPre == 0) // unechter Bruch
2274 double fNum1 = fNum * (double)nDiv + (double)nFrac;
2275 if (fNum1 > _D_MAX_U_LONG_)
2277 OutString = rScan.GetErrorString();
2278 return FALSE;
2280 nFrac = (ULONG) floor(fNum1);
2281 sStr.Erase();
2283 else if (fNum == 0.0 && nFrac != 0)
2284 sStr.Erase();
2285 else
2287 char aBuf[100];
2288 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
2289 sStr.AssignAscii( aBuf );
2290 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
2292 if (rInfo.nCntPre > 0 && nFrac == 0)
2294 sFrac.Erase();
2295 sDiv.Erase();
2297 else
2299 sFrac = ImpIntToString( nIx, nFrac );
2300 sDiv = ImpIntToString( nIx, nDiv );
2303 USHORT j = nAnz-1; // letztes Symbol->rueckw.
2304 xub_StrLen k; // Nenner:
2305 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
2306 BOOL bCont = TRUE;
2307 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
2309 if (rInfo.nCntPre > 0 && nFrac == 0)
2310 sDiv.Insert(' ',0);
2311 else
2312 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
2313 if ( j )
2314 j--;
2315 else
2316 bCont = FALSE;
2318 // weiter Zaehler:
2319 if ( !bCont )
2320 sFrac.Erase();
2321 else
2323 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
2324 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
2326 sFrac.Insert(rInfo.sStrArray[j],0);
2327 if ( j )
2328 j--;
2329 else
2330 bCont = FALSE;
2333 // weiter Hauptzahl
2334 if ( !bCont )
2335 sStr.Erase();
2336 else
2338 k = sStr.Len(); // hinter letzter Ziffer
2339 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
2340 rInfo.nCntPre);
2342 if (bSign && !(nFrac == 0 && fNum == 0.0))
2343 OutString.Insert('-',0); // nicht -0
2344 OutString += sStr;
2345 OutString += sFrac;
2346 OutString += sDiv;
2348 break;
2349 case NUMBERFORMAT_SCIENTIFIC:
2351 BOOL bSign = FALSE;
2352 if (fNumber < 0)
2354 if (nIx == 0) // nicht in hinteren
2355 bSign = TRUE; // Formaten
2356 fNumber = -fNumber;
2358 String sStr( ::rtl::math::doubleToUString( fNumber,
2359 rtl_math_StringFormat_E,
2360 rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
2362 String ExpStr;
2363 short nExpSign = 1;
2364 xub_StrLen nExPos = sStr.Search('E');
2365 if ( nExPos != STRING_NOTFOUND )
2367 // split into mantisse and exponent and get rid of "E+" or "E-"
2368 xub_StrLen nExpStart = nExPos + 1;
2369 switch ( sStr.GetChar( nExpStart ) )
2371 case '-' :
2372 nExpSign = -1;
2373 // fallthru
2374 case '+' :
2375 ++nExpStart;
2376 break;
2378 ExpStr = sStr.Copy( nExpStart ); // part following the "E+"
2379 sStr.Erase( nExPos );
2380 sStr.EraseAllChars('.'); // cut any decimal delimiter
2381 if ( rInfo.nCntPre != 1 ) // rescale Exp
2383 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
2384 nExp -= sal_Int32(rInfo.nCntPre)-1;
2385 if ( nExp < 0 )
2387 nExpSign = -1;
2388 nExp = -nExp;
2390 else
2391 nExpSign = 1;
2392 ExpStr = String::CreateFromInt32( nExp );
2395 USHORT j = nAnz-1; // last symbol
2396 xub_StrLen k; // position in ExpStr
2397 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
2399 xub_StrLen nZeros = 0; // erase leading zeros
2400 while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
2401 ++nZeros;
2402 if (nZeros)
2403 ExpStr.Erase( 0, nZeros);
2405 BOOL bCont = TRUE;
2406 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
2408 const String& rStr = rInfo.sStrArray[j];
2409 if (nExpSign == -1)
2410 ExpStr.Insert('-',0);
2411 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
2412 ExpStr.Insert('+',0);
2413 ExpStr.Insert(rStr.GetChar(0),0);
2414 if ( j )
2415 j--;
2416 else
2417 bCont = FALSE;
2419 // weiter Hauptzahl:
2420 if ( !bCont )
2421 sStr.Erase();
2422 else
2424 k = sStr.Len(); // hinter letzter Ziffer
2425 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
2426 rInfo.nCntPre +
2427 rInfo.nCntPost);
2429 if (bSign)
2430 sStr.Insert('-',0);
2431 OutString = sStr;
2432 OutString += ExpStr;
2434 break;
2437 return bRes;
2440 BOOL SvNumberformat::ImpGetTimeOutput(double fNumber,
2441 USHORT nIx,
2442 String& OutString)
2444 using namespace ::com::sun::star::i18n;
2445 BOOL bCalendarSet = FALSE;
2446 double fNumberOrig = fNumber;
2447 BOOL bRes = FALSE;
2448 BOOL bSign = FALSE;
2449 if (fNumber < 0.0)
2451 fNumber = -fNumber;
2452 if (nIx == 0)
2453 bSign = TRUE;
2455 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2456 if (rInfo.bThousand) // []-Format
2458 if (fNumber > 1.0E10) // zu gross
2460 OutString = rScan.GetErrorString();
2461 return FALSE;
2464 else
2465 fNumber -= floor(fNumber); // sonst Datum abtrennen
2466 BOOL bInputLine;
2467 xub_StrLen nCntPost;
2468 if ( rScan.GetStandardPrec() == 300 &&
2469 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2470 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2471 bInputLine = TRUE;
2472 nCntPost = 7;
2474 else
2476 bInputLine = FALSE;
2477 nCntPost = xub_StrLen(rInfo.nCntPost);
2479 if (bSign && !rInfo.bThousand) // kein []-Format
2480 fNumber = 1.0 - fNumber; // "Kehrwert"
2481 double fTime = fNumber * 86400.0;
2482 fTime = ::rtl::math::round( fTime, int(nCntPost) );
2483 if (bSign && fTime == 0.0)
2484 bSign = FALSE; // nicht -00:00:00
2486 if( floor( fTime ) > _D_MAX_U_LONG_ )
2488 OutString = rScan.GetErrorString();
2489 return FALSE;
2491 ULONG nSeconds = (ULONG)floor( fTime );
2493 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
2494 rtl_math_StringFormat_F, int(nCntPost), '.'));
2495 sSecStr.EraseLeadingChars('0');
2496 sSecStr.EraseLeadingChars('.');
2497 if ( bInputLine )
2499 sSecStr.EraseTrailingChars('0');
2500 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
2501 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
2502 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2503 nCntPost = sSecStr.Len();
2505 else
2506 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2508 xub_StrLen nSecPos = 0; // Zum Ziffernweisen
2509 // abarbeiten
2510 ULONG nHour, nMin, nSec;
2511 if (!rInfo.bThousand) // kein [] Format
2513 nHour = (nSeconds/3600) % 24;
2514 nMin = (nSeconds%3600) / 60;
2515 nSec = nSeconds%60;
2517 else if (rInfo.nThousand == 3) // [ss]
2519 nHour = 0;
2520 nMin = 0;
2521 nSec = nSeconds;
2523 else if (rInfo.nThousand == 2) // [mm]:ss
2525 nHour = 0;
2526 nMin = nSeconds / 60;
2527 nSec = nSeconds % 60;
2529 else if (rInfo.nThousand == 1) // [hh]:mm:ss
2531 nHour = nSeconds / 3600;
2532 nMin = (nSeconds%3600) / 60;
2533 nSec = nSeconds%60;
2535 else {
2536 // TODO What should these be set to?
2537 nHour = 0;
2538 nMin = 0;
2539 nSec = 0;
2542 sal_Unicode cAmPm = ' '; // a oder p
2543 if (rInfo.nCntExp) // AM/PM
2545 if (nHour == 0)
2547 nHour = 12;
2548 cAmPm = 'a';
2550 else if (nHour < 12)
2551 cAmPm = 'a';
2552 else
2554 cAmPm = 'p';
2555 if (nHour > 12)
2556 nHour -= 12;
2559 const USHORT nAnz = NumFor[nIx].GetnAnz();
2560 for (USHORT i = 0; i < nAnz; i++)
2562 switch (rInfo.nTypeArray[i])
2564 case NF_SYMBOLTYPE_STAR:
2565 if( bStarFlag )
2567 OutString += (sal_Unicode) 0x1B;
2568 OutString += rInfo.sStrArray[i].GetChar(1);
2569 bRes = TRUE;
2571 break;
2572 case NF_SYMBOLTYPE_BLANK:
2573 InsertBlanks( OutString, OutString.Len(),
2574 rInfo.sStrArray[i].GetChar(1) );
2575 break;
2576 case NF_SYMBOLTYPE_STRING:
2577 case NF_SYMBOLTYPE_CURRENCY:
2578 case NF_SYMBOLTYPE_DATESEP:
2579 case NF_SYMBOLTYPE_TIMESEP:
2580 case NF_SYMBOLTYPE_TIME100SECSEP:
2581 OutString += rInfo.sStrArray[i];
2582 break;
2583 case NF_SYMBOLTYPE_DIGIT:
2585 xub_StrLen nLen = ( bInputLine && i > 0 &&
2586 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
2587 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
2588 nCntPost : rInfo.sStrArray[i].Len() );
2589 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
2591 OutString += sSecStr.GetChar(nSecPos);
2592 nSecPos++;
2595 break;
2596 case NF_KEY_AMPM: // AM/PM
2598 if ( !bCalendarSet )
2600 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
2601 fDiff += fNumberOrig;
2602 GetCal().setLocalDateTime( fDiff );
2603 bCalendarSet = TRUE;
2605 if (cAmPm == 'a')
2606 OutString += GetCal().getDisplayName(
2607 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
2608 else
2609 OutString += GetCal().getDisplayName(
2610 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
2612 break;
2613 case NF_KEY_AP: // A/P
2615 if (cAmPm == 'a')
2616 OutString += 'a';
2617 else
2618 OutString += 'p';
2620 break;
2621 case NF_KEY_MI: // M
2622 OutString += ImpIntToString( nIx, nMin );
2623 break;
2624 case NF_KEY_MMI: // MM
2625 OutString += ImpIntToString( nIx, nMin, 2 );
2626 break;
2627 case NF_KEY_H: // H
2628 OutString += ImpIntToString( nIx, nHour );
2629 break;
2630 case NF_KEY_HH: // HH
2631 OutString += ImpIntToString( nIx, nHour, 2 );
2632 break;
2633 case NF_KEY_S: // S
2634 OutString += ImpIntToString( nIx, nSec );
2635 break;
2636 case NF_KEY_SS: // SS
2637 OutString += ImpIntToString( nIx, nSec, 2 );
2638 break;
2639 default:
2640 break;
2643 if (bSign && rInfo.bThousand)
2644 OutString.Insert('-',0);
2645 return bRes;
2649 BOOL SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
2651 if ( GetCal().getUniqueID() != Gregorian::get() )
2652 return FALSE;
2653 const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2654 const USHORT nAnz = rNumFor.GetnAnz();
2655 USHORT i;
2656 for ( i = 0; i < nAnz; i++ )
2658 switch ( rInfo.nTypeArray[i] )
2660 case NF_SYMBOLTYPE_CALENDAR :
2661 return FALSE;
2662 case NF_KEY_EC :
2663 case NF_KEY_EEC :
2664 case NF_KEY_R :
2665 case NF_KEY_RR :
2666 case NF_KEY_AAA :
2667 case NF_KEY_AAAA :
2668 return TRUE;
2671 return FALSE;
2675 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
2676 double& fOrgDateTime ) const
2678 CalendarWrapper& rCal = GetCal();
2679 const rtl::OUString &rGregorian = Gregorian::get();
2680 if ( rCal.getUniqueID() == rGregorian )
2682 using namespace ::com::sun::star::i18n;
2683 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
2684 = rCal.getAllCalendars( rLoc().getLocale() );
2685 sal_Int32 nCnt = xCals.getLength();
2686 if ( nCnt > 1 )
2688 for ( sal_Int32 j=0; j < nCnt; j++ )
2690 if ( xCals[j] != rGregorian )
2692 if ( !rOrgCalendar.Len() )
2694 rOrgCalendar = rCal.getUniqueID();
2695 fOrgDateTime = rCal.getDateTime();
2697 rCal.loadCalendar( xCals[j], rLoc().getLocale() );
2698 rCal.setDateTime( fOrgDateTime );
2699 break; // for
2707 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
2708 double fOrgDateTime ) const
2710 CalendarWrapper& rCal = GetCal();
2711 const rtl::OUString &rGregorian = Gregorian::get();
2712 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
2714 rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2715 rCal.setDateTime( fOrgDateTime );
2720 BOOL SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
2722 using namespace ::com::sun::star::i18n;
2723 CalendarWrapper& rCal = GetCal();
2724 const rtl::OUString &rGregorian = Gregorian::get();
2725 if ( rCal.getUniqueID() != rGregorian )
2727 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2728 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
2729 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2731 if ( !rOrgCalendar.Len() )
2733 rOrgCalendar = rCal.getUniqueID();
2734 fOrgDateTime = rCal.getDateTime();
2736 else if ( rOrgCalendar == String(rGregorian) )
2737 rOrgCalendar.Erase();
2738 rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2739 rCal.setDateTime( fOrgDateTime );
2740 return TRUE;
2743 return FALSE;
2747 BOOL SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
2748 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
2750 const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2751 const USHORT nAnz = rNumFor.GetnAnz();
2752 for ( USHORT i = 0; i < nAnz; i++ )
2754 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
2756 CalendarWrapper& rCal = GetCal();
2757 if ( !rOrgCalendar.Len() )
2759 rOrgCalendar = rCal.getUniqueID();
2760 fOrgDateTime = rCal.getDateTime();
2762 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2763 rCal.setDateTime( fOrgDateTime );
2764 return TRUE;
2767 return FALSE;
2771 // static
2772 void SvNumberformat::ImpAppendEraG( String& OutString,
2773 const CalendarWrapper& rCal, sal_Int16 nNatNum )
2775 using namespace ::com::sun::star::i18n;
2776 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2778 sal_Unicode cEra;
2779 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2780 switch ( nVal )
2782 case 1 : cEra = 'M'; break;
2783 case 2 : cEra = 'T'; break;
2784 case 3 : cEra = 'S'; break;
2785 case 4 : cEra = 'H'; break;
2786 default:
2787 cEra = '?';
2789 OutString += cEra;
2791 else
2792 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
2796 BOOL SvNumberformat::ImpGetDateOutput(double fNumber,
2797 USHORT nIx,
2798 String& OutString)
2800 using namespace ::com::sun::star::i18n;
2801 BOOL bRes = FALSE;
2802 CalendarWrapper& rCal = GetCal();
2803 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
2804 fNumber += fDiff;
2805 rCal.setLocalDateTime( fNumber );
2806 String aOrgCalendar; // empty => not changed yet
2807 double fOrgDateTime;
2808 BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
2809 if ( bOtherCalendar )
2810 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2811 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
2812 bOtherCalendar = FALSE;
2813 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2814 const USHORT nAnz = NumFor[nIx].GetnAnz();
2815 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
2816 for (USHORT i = 0; i < nAnz; i++)
2818 switch (rInfo.nTypeArray[i])
2820 case NF_SYMBOLTYPE_CALENDAR :
2821 if ( !aOrgCalendar.Len() )
2823 aOrgCalendar = rCal.getUniqueID();
2824 fOrgDateTime = rCal.getDateTime();
2826 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2827 rCal.setDateTime( fOrgDateTime );
2828 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2829 break;
2830 case NF_SYMBOLTYPE_STAR:
2831 if( bStarFlag )
2833 OutString += (sal_Unicode) 0x1B;
2834 OutString += rInfo.sStrArray[i].GetChar(1);
2835 bRes = TRUE;
2837 break;
2838 case NF_SYMBOLTYPE_BLANK:
2839 InsertBlanks( OutString, OutString.Len(),
2840 rInfo.sStrArray[i].GetChar(1) );
2841 break;
2842 case NF_SYMBOLTYPE_STRING:
2843 case NF_SYMBOLTYPE_CURRENCY:
2844 case NF_SYMBOLTYPE_DATESEP:
2845 case NF_SYMBOLTYPE_TIMESEP:
2846 case NF_SYMBOLTYPE_TIME100SECSEP:
2847 OutString += rInfo.sStrArray[i];
2848 break;
2849 case NF_KEY_M: // M
2850 OutString += rCal.getDisplayString(
2851 CalendarDisplayCode::SHORT_MONTH, nNatNum );
2852 break;
2853 case NF_KEY_MM: // MM
2854 OutString += rCal.getDisplayString(
2855 CalendarDisplayCode::LONG_MONTH, nNatNum );
2856 break;
2857 case NF_KEY_MMM: // MMM
2858 OutString += rCal.getDisplayString(
2859 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
2860 break;
2861 case NF_KEY_MMMM: // MMMM
2862 OutString += rCal.getDisplayString(
2863 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
2864 break;
2865 case NF_KEY_MMMMM: // MMMMM
2866 OutString += rCal.getDisplayString(
2867 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
2868 break;
2869 case NF_KEY_Q: // Q
2870 OutString += rCal.getDisplayString(
2871 CalendarDisplayCode::SHORT_QUARTER, nNatNum );
2872 break;
2873 case NF_KEY_QQ: // QQ
2874 OutString += rCal.getDisplayString(
2875 CalendarDisplayCode::LONG_QUARTER, nNatNum );
2876 break;
2877 case NF_KEY_D: // D
2878 OutString += rCal.getDisplayString(
2879 CalendarDisplayCode::SHORT_DAY, nNatNum );
2880 break;
2881 case NF_KEY_DD: // DD
2882 OutString += rCal.getDisplayString(
2883 CalendarDisplayCode::LONG_DAY, nNatNum );
2884 break;
2885 case NF_KEY_DDD: // DDD
2887 if ( bOtherCalendar )
2888 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2889 OutString += rCal.getDisplayString(
2890 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
2891 if ( bOtherCalendar )
2892 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2894 break;
2895 case NF_KEY_DDDD: // DDDD
2897 if ( bOtherCalendar )
2898 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2899 OutString += rCal.getDisplayString(
2900 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2901 if ( bOtherCalendar )
2902 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2904 break;
2905 case NF_KEY_YY: // YY
2907 if ( bOtherCalendar )
2908 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2909 OutString += rCal.getDisplayString(
2910 CalendarDisplayCode::SHORT_YEAR, nNatNum );
2911 if ( bOtherCalendar )
2912 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2914 break;
2915 case NF_KEY_YYYY: // YYYY
2917 if ( bOtherCalendar )
2918 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2919 OutString += rCal.getDisplayString(
2920 CalendarDisplayCode::LONG_YEAR, nNatNum );
2921 if ( bOtherCalendar )
2922 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2924 break;
2925 case NF_KEY_EC: // E
2926 OutString += rCal.getDisplayString(
2927 CalendarDisplayCode::SHORT_YEAR, nNatNum );
2928 break;
2929 case NF_KEY_EEC: // EE
2930 case NF_KEY_R: // R
2931 OutString += rCal.getDisplayString(
2932 CalendarDisplayCode::LONG_YEAR, nNatNum );
2933 break;
2934 case NF_KEY_NN: // NN
2935 case NF_KEY_AAA: // AAA
2936 OutString += rCal.getDisplayString(
2937 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
2938 break;
2939 case NF_KEY_NNN: // NNN
2940 case NF_KEY_AAAA: // AAAA
2941 OutString += rCal.getDisplayString(
2942 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2943 break;
2944 case NF_KEY_NNNN: // NNNN
2946 OutString += rCal.getDisplayString(
2947 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
2948 OutString += rLoc().getLongDateDayOfWeekSep();
2950 break;
2951 case NF_KEY_WW : // WW
2953 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
2954 OutString += ImpIntToString( nIx, nVal );
2956 break;
2957 case NF_KEY_G: // G
2958 ImpAppendEraG( OutString, rCal, nNatNum );
2959 break;
2960 case NF_KEY_GG: // GG
2961 OutString += rCal.getDisplayString(
2962 CalendarDisplayCode::SHORT_ERA, nNatNum );
2963 break;
2964 case NF_KEY_GGG: // GGG
2965 OutString += rCal.getDisplayString(
2966 CalendarDisplayCode::LONG_ERA, nNatNum );
2967 break;
2968 case NF_KEY_RR: // RR => GGGEE
2969 OutString += rCal.getDisplayString(
2970 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
2971 break;
2974 if ( aOrgCalendar.Len() )
2975 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
2976 return bRes;
2979 BOOL SvNumberformat::ImpGetDateTimeOutput(double fNumber,
2980 USHORT nIx,
2981 String& OutString)
2983 using namespace ::com::sun::star::i18n;
2984 BOOL bRes = FALSE;
2986 CalendarWrapper& rCal = GetCal();
2987 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
2988 fNumber += fDiff;
2990 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2991 BOOL bInputLine;
2992 xub_StrLen nCntPost;
2993 if ( rScan.GetStandardPrec() == 300 &&
2994 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2995 { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2996 bInputLine = TRUE;
2997 nCntPost = 7;
2999 else
3001 bInputLine = FALSE;
3002 nCntPost = xub_StrLen(rInfo.nCntPost);
3004 double fTime = (fNumber - floor( fNumber )) * 86400.0;
3005 fTime = ::rtl::math::round( fTime, int(nCntPost) );
3006 if (fTime >= 86400.0)
3008 // result of fNumber==x.999999999... rounded up, use correct date/time
3009 fTime -= 86400.0;
3010 fNumber = floor( fNumber + 0.5) + fTime;
3012 rCal.setLocalDateTime( fNumber );
3014 String aOrgCalendar; // empty => not changed yet
3015 double fOrgDateTime;
3016 BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3017 if ( bOtherCalendar )
3018 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3019 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3020 bOtherCalendar = FALSE;
3021 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3023 ULONG nSeconds = (ULONG)floor( fTime );
3024 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
3025 rtl_math_StringFormat_F, int(nCntPost), '.'));
3026 sSecStr.EraseLeadingChars('0');
3027 sSecStr.EraseLeadingChars('.');
3028 if ( bInputLine )
3030 sSecStr.EraseTrailingChars('0');
3031 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
3032 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
3033 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3034 nCntPost = sSecStr.Len();
3036 else
3037 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3039 xub_StrLen nSecPos = 0; // Zum Ziffernweisen
3040 // abarbeiten
3041 ULONG nHour, nMin, nSec;
3042 if (!rInfo.bThousand) // [] Format
3044 nHour = (nSeconds/3600) % 24;
3045 nMin = (nSeconds%3600) / 60;
3046 nSec = nSeconds%60;
3048 else if (rInfo.nThousand == 3) // [ss]
3050 nHour = 0;
3051 nMin = 0;
3052 nSec = nSeconds;
3054 else if (rInfo.nThousand == 2) // [mm]:ss
3056 nHour = 0;
3057 nMin = nSeconds / 60;
3058 nSec = nSeconds % 60;
3060 else if (rInfo.nThousand == 1) // [hh]:mm:ss
3062 nHour = nSeconds / 3600;
3063 nMin = (nSeconds%3600) / 60;
3064 nSec = nSeconds%60;
3066 else {
3067 nHour = 0; // TODO What should these values be?
3068 nMin = 0;
3069 nSec = 0;
3071 sal_Unicode cAmPm = ' '; // a oder p
3072 if (rInfo.nCntExp) // AM/PM
3074 if (nHour == 0)
3076 nHour = 12;
3077 cAmPm = 'a';
3079 else if (nHour < 12)
3080 cAmPm = 'a';
3081 else
3083 cAmPm = 'p';
3084 if (nHour > 12)
3085 nHour -= 12;
3088 const USHORT nAnz = NumFor[nIx].GetnAnz();
3089 for (USHORT i = 0; i < nAnz; i++)
3091 switch (rInfo.nTypeArray[i])
3093 case NF_SYMBOLTYPE_CALENDAR :
3094 if ( !aOrgCalendar.Len() )
3096 aOrgCalendar = rCal.getUniqueID();
3097 fOrgDateTime = rCal.getDateTime();
3099 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
3100 rCal.setDateTime( fOrgDateTime );
3101 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3102 break;
3103 case NF_SYMBOLTYPE_STAR:
3104 if( bStarFlag )
3106 OutString += (sal_Unicode) 0x1B;
3107 OutString += rInfo.sStrArray[i].GetChar(1);
3108 bRes = TRUE;
3110 break;
3111 case NF_SYMBOLTYPE_BLANK:
3112 InsertBlanks( OutString, OutString.Len(),
3113 rInfo.sStrArray[i].GetChar(1) );
3114 break;
3115 case NF_SYMBOLTYPE_STRING:
3116 case NF_SYMBOLTYPE_CURRENCY:
3117 case NF_SYMBOLTYPE_DATESEP:
3118 case NF_SYMBOLTYPE_TIMESEP:
3119 case NF_SYMBOLTYPE_TIME100SECSEP:
3120 OutString += rInfo.sStrArray[i];
3121 break;
3122 case NF_SYMBOLTYPE_DIGIT:
3124 xub_StrLen nLen = ( bInputLine && i > 0 &&
3125 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
3126 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
3127 nCntPost : rInfo.sStrArray[i].Len() );
3128 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
3130 OutString += sSecStr.GetChar(nSecPos);
3131 nSecPos++;
3134 break;
3135 case NF_KEY_AMPM: // AM/PM
3137 if (cAmPm == 'a')
3138 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3139 AmPmValue::AM, 0 );
3140 else
3141 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3142 AmPmValue::PM, 0 );
3144 break;
3145 case NF_KEY_AP: // A/P
3147 if (cAmPm == 'a')
3148 OutString += 'a';
3149 else
3150 OutString += 'p';
3152 break;
3153 case NF_KEY_MI: // M
3154 OutString += ImpIntToString( nIx, nMin );
3155 break;
3156 case NF_KEY_MMI: // MM
3157 OutString += ImpIntToString( nIx, nMin, 2 );
3158 break;
3159 case NF_KEY_H: // H
3160 OutString += ImpIntToString( nIx, nHour );
3161 break;
3162 case NF_KEY_HH: // HH
3163 OutString += ImpIntToString( nIx, nHour, 2 );
3164 break;
3165 case NF_KEY_S: // S
3166 OutString += ImpIntToString( nIx, nSec );
3167 break;
3168 case NF_KEY_SS: // SS
3169 OutString += ImpIntToString( nIx, nSec, 2 );
3170 break;
3171 case NF_KEY_M: // M
3172 OutString += rCal.getDisplayString(
3173 CalendarDisplayCode::SHORT_MONTH, nNatNum );
3174 break;
3175 case NF_KEY_MM: // MM
3176 OutString += rCal.getDisplayString(
3177 CalendarDisplayCode::LONG_MONTH, nNatNum );
3178 break;
3179 case NF_KEY_MMM: // MMM
3180 OutString += rCal.getDisplayString(
3181 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
3182 break;
3183 case NF_KEY_MMMM: // MMMM
3184 OutString += rCal.getDisplayString(
3185 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
3186 break;
3187 case NF_KEY_MMMMM: // MMMMM
3188 OutString += rCal.getDisplayString(
3189 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
3190 break;
3191 case NF_KEY_Q: // Q
3192 OutString += rCal.getDisplayString(
3193 CalendarDisplayCode::SHORT_QUARTER, nNatNum );
3194 break;
3195 case NF_KEY_QQ: // QQ
3196 OutString += rCal.getDisplayString(
3197 CalendarDisplayCode::LONG_QUARTER, nNatNum );
3198 break;
3199 case NF_KEY_D: // D
3200 OutString += rCal.getDisplayString(
3201 CalendarDisplayCode::SHORT_DAY, nNatNum );
3202 break;
3203 case NF_KEY_DD: // DD
3204 OutString += rCal.getDisplayString(
3205 CalendarDisplayCode::LONG_DAY, nNatNum );
3206 break;
3207 case NF_KEY_DDD: // DDD
3209 if ( bOtherCalendar )
3210 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3211 OutString += rCal.getDisplayString(
3212 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3213 if ( bOtherCalendar )
3214 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3216 break;
3217 case NF_KEY_DDDD: // DDDD
3219 if ( bOtherCalendar )
3220 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3221 OutString += rCal.getDisplayString(
3222 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3223 if ( bOtherCalendar )
3224 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3226 break;
3227 case NF_KEY_YY: // YY
3229 if ( bOtherCalendar )
3230 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3231 OutString += rCal.getDisplayString(
3232 CalendarDisplayCode::SHORT_YEAR, nNatNum );
3233 if ( bOtherCalendar )
3234 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3236 break;
3237 case NF_KEY_YYYY: // YYYY
3239 if ( bOtherCalendar )
3240 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3241 OutString += rCal.getDisplayString(
3242 CalendarDisplayCode::LONG_YEAR, nNatNum );
3243 if ( bOtherCalendar )
3244 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3246 break;
3247 case NF_KEY_EC: // E
3248 OutString += rCal.getDisplayString(
3249 CalendarDisplayCode::SHORT_YEAR, nNatNum );
3250 break;
3251 case NF_KEY_EEC: // EE
3252 case NF_KEY_R: // R
3253 OutString += rCal.getDisplayString(
3254 CalendarDisplayCode::LONG_YEAR, nNatNum );
3255 break;
3256 case NF_KEY_NN: // NN
3257 case NF_KEY_AAA: // AAA
3258 OutString += rCal.getDisplayString(
3259 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3260 break;
3261 case NF_KEY_NNN: // NNN
3262 case NF_KEY_AAAA: // AAAA
3263 OutString += rCal.getDisplayString(
3264 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3265 break;
3266 case NF_KEY_NNNN: // NNNN
3268 OutString += rCal.getDisplayString(
3269 CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3270 OutString += rLoc().getLongDateDayOfWeekSep();
3272 break;
3273 case NF_KEY_WW : // WW
3275 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3276 OutString += ImpIntToString( nIx, nVal );
3278 break;
3279 case NF_KEY_G: // G
3280 ImpAppendEraG( OutString, rCal, nNatNum );
3281 break;
3282 case NF_KEY_GG: // GG
3283 OutString += rCal.getDisplayString(
3284 CalendarDisplayCode::SHORT_ERA, nNatNum );
3285 break;
3286 case NF_KEY_GGG: // GGG
3287 OutString += rCal.getDisplayString(
3288 CalendarDisplayCode::LONG_ERA, nNatNum );
3289 break;
3290 case NF_KEY_RR: // RR => GGGEE
3291 OutString += rCal.getDisplayString(
3292 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3293 break;
3296 if ( aOrgCalendar.Len() )
3297 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
3298 return bRes;
3301 BOOL SvNumberformat::ImpGetNumberOutput(double fNumber,
3302 USHORT nIx,
3303 String& OutString)
3305 BOOL bRes = FALSE;
3306 BOOL bSign;
3307 if (fNumber < 0.0)
3309 if (nIx == 0) // nicht in hinteren
3310 bSign = TRUE; // Formaten
3311 else
3312 bSign = FALSE;
3313 fNumber = -fNumber;
3315 else
3317 bSign = FALSE;
3318 if ( ::rtl::math::isSignBitSet( fNumber ) )
3319 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
3321 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3322 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
3324 if (fNumber < _D_MAX_D_BY_100)
3325 fNumber *= 100.0;
3326 else
3328 OutString = rScan.GetErrorString();
3329 return FALSE;
3332 USHORT i, j;
3333 xub_StrLen k;
3334 String sStr;
3335 long nPrecExp;
3336 BOOL bInteger = FALSE;
3337 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
3338 { // special formatting only if no GENERAL keyword in format code
3339 const USHORT nThousand = rInfo.nThousand;
3340 for (i = 0; i < nThousand; i++)
3342 if (fNumber > _D_MIN_M_BY_1000)
3343 fNumber /= 1000.0;
3344 else
3345 fNumber = 0.0;
3347 if (fNumber > 0.0)
3348 nPrecExp = GetPrecExp( fNumber );
3349 else
3350 nPrecExp = 0;
3351 if (rInfo.nCntPost) // NachkommaStellen
3353 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
3355 sStr = ::rtl::math::doubleToUString( fNumber,
3356 rtl_math_StringFormat_F, 15-nPrecExp, '.');
3357 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
3358 sStr += '0';
3360 else
3361 sStr = ::rtl::math::doubleToUString( fNumber,
3362 rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
3363 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
3365 else if (fNumber == 0.0) // Null
3367 // nothing to be done here, keep empty string sStr,
3368 // ImpNumberFillWithThousands does the rest
3370 else // Integer
3372 sStr = ::rtl::math::doubleToUString( fNumber,
3373 rtl_math_StringFormat_F, 0, '.');
3374 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
3376 xub_StrLen nPoint = sStr.Search( '.' );
3377 if ( nPoint != STRING_NOTFOUND )
3379 register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
3380 while ( *++p == '0' )
3382 if ( !*p )
3383 bInteger = TRUE;
3384 sStr.Erase( nPoint, 1 ); // . herausnehmen
3386 if (bSign &&
3387 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000
3388 bSign = FALSE; // nicht -0.00
3389 } // End of != FLAG_STANDARD_IN_FORMAT
3391 // von hinten nach vorn
3392 // editieren:
3393 k = sStr.Len(); // hinter letzter Ziffer
3394 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol
3395 // Nachkommastellen:
3396 if (rInfo.nCntPost > 0)
3398 BOOL bTrailing = TRUE; // ob Endnullen?
3399 BOOL bFilled = FALSE; // ob aufgefuellt wurde ?
3400 short nType;
3401 while (j > 0 && // rueckwaerts
3402 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
3404 switch ( nType )
3406 case NF_SYMBOLTYPE_STAR:
3407 if( bStarFlag )
3409 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
3410 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3411 bRes = TRUE;
3413 break;
3414 case NF_SYMBOLTYPE_BLANK:
3415 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3416 break;
3417 case NF_SYMBOLTYPE_STRING:
3418 case NF_SYMBOLTYPE_CURRENCY:
3419 case NF_SYMBOLTYPE_PERCENT:
3420 sStr.Insert(rInfo.sStrArray[j],k);
3421 break;
3422 case NF_SYMBOLTYPE_THSEP:
3423 if (rInfo.nThousand == 0)
3424 sStr.Insert(rInfo.sStrArray[j],k);
3425 break;
3426 case NF_SYMBOLTYPE_DIGIT:
3428 const String& rStr = rInfo.sStrArray[j];
3429 const sal_Unicode* p1 = rStr.GetBuffer();
3430 register const sal_Unicode* p = p1 + rStr.Len();
3431 while ( p1 < p-- )
3433 const sal_Unicode c = *p;
3434 k--;
3435 if ( sStr.GetChar(k) != '0' )
3436 bTrailing = FALSE;
3437 if (bTrailing)
3439 if ( c == '0' )
3440 bFilled = TRUE;
3441 else if ( c == '-' )
3443 if ( bInteger )
3444 sStr.SetChar( k, '-' );
3445 bFilled = TRUE;
3447 else if ( c == '?' )
3449 sStr.SetChar( k, ' ' );
3450 bFilled = TRUE;
3452 else if ( !bFilled ) // #
3453 sStr.Erase(k,1);
3455 } // of for
3456 } // of case digi
3457 break;
3458 case NF_KEY_CCC: // CCC-Waehrung
3459 sStr.Insert(rScan.GetCurAbbrev(), k);
3460 break;
3461 case NF_KEY_GENERAL: // Standard im String
3463 String sNum;
3464 ImpGetOutputStandard(fNumber, sNum);
3465 sNum.EraseLeadingChars('-');
3466 sStr.Insert(sNum, k);
3468 break;
3469 default:
3470 break;
3471 } // of switch
3472 j--;
3473 } // of while
3474 } // of Nachkomma
3476 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
3477 rInfo.nCntPre);
3478 if ( rInfo.nCntPost > 0 )
3480 const String& rDecSep = GetFormatter().GetNumDecimalSep();
3481 xub_StrLen nLen = rDecSep.Len();
3482 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
3483 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep
3485 if (bSign)
3486 sStr.Insert('-',0);
3487 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
3488 OutString = sStr;
3489 return bRes;
3492 BOOL SvNumberformat::ImpNumberFillWithThousands(
3493 String& sStr, // number string
3494 double& rNumber, // number
3495 xub_StrLen k, // position within string
3496 USHORT j, // symbol index within format code
3497 USHORT nIx, // subformat index
3498 USHORT nDigCnt) // count of integer digits in format
3500 BOOL bRes = FALSE;
3501 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
3502 xub_StrLen nDigitCount = 0; // count of integer digits from the right
3503 BOOL bStop = FALSE;
3504 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3505 // no normal thousands separators if number divided by thousands
3506 BOOL bDoThousands = (rInfo.nThousand == 0);
3507 utl::DigitGroupingIterator aGrouping(
3508 GetFormatter().GetLocaleData()->getDigitGrouping());
3509 while (!bStop) // backwards
3511 if (j == 0)
3512 bStop = TRUE;
3513 switch (rInfo.nTypeArray[j])
3515 case NF_SYMBOLTYPE_DECSEP:
3516 aGrouping.reset();
3517 // fall thru
3518 case NF_SYMBOLTYPE_STRING:
3519 case NF_SYMBOLTYPE_CURRENCY:
3520 case NF_SYMBOLTYPE_PERCENT:
3521 sStr.Insert(rInfo.sStrArray[j],k);
3522 if ( k == 0 )
3523 nLeadingStringChars =
3524 nLeadingStringChars + rInfo.sStrArray[j].Len();
3525 break;
3526 case NF_SYMBOLTYPE_STAR:
3527 if( bStarFlag )
3529 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
3530 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3531 bRes = TRUE;
3533 break;
3534 case NF_SYMBOLTYPE_BLANK:
3535 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3536 break;
3537 case NF_SYMBOLTYPE_THSEP:
3539 // #i7284# #102685# Insert separator also if number is divided
3540 // by thousands and the separator is specified somewhere in
3541 // between and not only at the end.
3542 // #i12596# But do not insert if it's a parenthesized negative
3543 // format like (#,)
3544 // In fact, do not insert if divided and regex [0#,],[^0#] and
3545 // no other digit symbol follows (which was already detected
3546 // during scan of format code, otherwise there would be no
3547 // division), else do insert. Same in ImpNumberFill() below.
3548 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3549 bDoThousands = ((j == 0) ||
3550 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3551 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3552 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3553 if ( bDoThousands )
3555 if (k > 0)
3556 sStr.Insert(rInfo.sStrArray[j],k);
3557 else if (nDigitCount < nDigCnt)
3559 // Leading '#' displays nothing (e.g. no leading
3560 // separator for numbers <1000 with #,##0 format).
3561 // Leading '?' displays blank.
3562 // Everything else, including nothing, displays the
3563 // separator.
3564 sal_Unicode cLeader = 0;
3565 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
3567 const String& rStr = rInfo.sStrArray[j-1];
3568 xub_StrLen nLen = rStr.Len();
3569 if (nLen)
3570 cLeader = rStr.GetChar(nLen-1);
3572 switch (cLeader)
3574 case '#':
3575 ; // nothing
3576 break;
3577 case '?':
3578 // erAck: 2008-04-03T16:24+0200
3579 // Actually this currently isn't executed
3580 // because the format scanner in the context of
3581 // "?," doesn't generate a group separator but
3582 // a literal ',' character instead that is
3583 // inserted unconditionally. Should be changed
3584 // on some occasion.
3585 sStr.Insert(' ',k);
3586 break;
3587 default:
3588 sStr.Insert(rInfo.sStrArray[j],k);
3591 aGrouping.advance();
3594 break;
3595 case NF_SYMBOLTYPE_DIGIT:
3597 const String& rStr = rInfo.sStrArray[j];
3598 const sal_Unicode* p1 = rStr.GetBuffer();
3599 register const sal_Unicode* p = p1 + rStr.Len();
3600 while ( p1 < p-- )
3602 nDigitCount++;
3603 if (k > 0)
3604 k--;
3605 else
3607 switch (*p)
3609 case '0':
3610 sStr.Insert('0',0);
3611 break;
3612 case '?':
3613 sStr.Insert(' ',0);
3614 break;
3617 if (nDigitCount == nDigCnt && k > 0)
3618 { // more digits than specified
3619 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
3623 break;
3624 case NF_KEY_CCC: // CCC currency
3625 sStr.Insert(rScan.GetCurAbbrev(), k);
3626 break;
3627 case NF_KEY_GENERAL: // "General" in string
3629 String sNum;
3630 ImpGetOutputStandard(rNumber, sNum);
3631 sNum.EraseLeadingChars('-');
3632 sStr.Insert(sNum, k);
3634 break;
3636 default:
3637 break;
3638 } // switch
3639 j--; // next format code string
3640 } // while
3641 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ...
3642 if (k > nLeadingStringChars)
3643 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
3644 return bRes;
3647 void SvNumberformat::ImpDigitFill(
3648 String& sStr, // number string
3649 xub_StrLen nStart, // start of digits
3650 xub_StrLen& k, // position within string
3651 USHORT nIx, // subformat index
3652 xub_StrLen & nDigitCount, // count of integer digits from the right so far
3653 utl::DigitGroupingIterator & rGrouping ) // current grouping
3655 if (NumFor[nIx].Info().bThousand) // only if grouping
3656 { // fill in separators
3657 const String& rThousandSep = GetFormatter().GetNumThousandSep();
3658 while (k > nStart)
3660 if (nDigitCount == rGrouping.getPos())
3662 sStr.Insert( rThousandSep, k );
3663 rGrouping.advance();
3665 nDigitCount++;
3666 k--;
3669 else // simply skip
3670 k = nStart;
3673 BOOL SvNumberformat::ImpNumberFill( String& sStr, // number string
3674 double& rNumber, // number for "General" format
3675 xub_StrLen& k, // position within string
3676 USHORT& j, // symbol index within format code
3677 USHORT nIx, // subformat index
3678 short eSymbolType ) // type of stop condition
3680 BOOL bRes = FALSE;
3681 k = sStr.Len(); // behind last digit
3682 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3683 // no normal thousands separators if number divided by thousands
3684 BOOL bDoThousands = (rInfo.nThousand == 0);
3685 short nType;
3686 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
3687 { // rueckwaerts:
3688 switch ( nType )
3690 case NF_SYMBOLTYPE_STAR:
3691 if( bStarFlag )
3693 sStr.Insert( sal_Unicode(0x1B), k++ );
3694 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3695 bRes = TRUE;
3697 break;
3698 case NF_SYMBOLTYPE_BLANK:
3699 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3700 break;
3701 case NF_SYMBOLTYPE_THSEP:
3703 // Same as in ImpNumberFillWithThousands() above, do not insert
3704 // if divided and regex [0#,],[^0#] and no other digit symbol
3705 // follows (which was already detected during scan of format
3706 // code, otherwise there would be no division), else do insert.
3707 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3708 bDoThousands = ((j == 0) ||
3709 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3710 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3711 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3712 if ( bDoThousands && k > 0 )
3714 sStr.Insert(rInfo.sStrArray[j],k);
3717 break;
3718 case NF_SYMBOLTYPE_DIGIT:
3720 const String& rStr = rInfo.sStrArray[j];
3721 const sal_Unicode* p1 = rStr.GetBuffer();
3722 register const sal_Unicode* p = p1 + rStr.Len();
3723 while ( p1 < p-- )
3725 if (k > 0)
3726 k--;
3727 else
3729 switch (*p)
3731 case '0':
3732 sStr.Insert('0',0);
3733 break;
3734 case '?':
3735 sStr.Insert(' ',0);
3736 break;
3741 break;
3742 case NF_KEY_CCC: // CCC-Waehrung
3743 sStr.Insert(rScan.GetCurAbbrev(), k);
3744 break;
3745 case NF_KEY_GENERAL: // Standard im String
3747 String sNum;
3748 ImpGetOutputStandard(rNumber, sNum);
3749 sNum.EraseLeadingChars('-'); // Vorzeichen weg!!
3750 sStr.Insert(sNum, k);
3752 break;
3754 default:
3755 sStr.Insert(rInfo.sStrArray[j],k);
3756 break;
3757 } // of switch
3758 j--; // naechster String
3759 } // of while
3760 return bRes;
3763 void SvNumberformat::GetFormatSpecialInfo(BOOL& bThousand,
3764 BOOL& IsRed,
3765 USHORT& nPrecision,
3766 USHORT& nAnzLeading) const
3768 // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3770 short nDummyType;
3771 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
3773 // "negative in red" is only useful for the whole format
3775 const Color* pColor = NumFor[1].GetColor();
3776 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
3777 && (*pColor == rScan.GetRedColor()))
3778 IsRed = TRUE;
3779 else
3780 IsRed = FALSE;
3783 void SvNumberformat::GetNumForInfo( USHORT nNumFor, short& rScannedType,
3784 BOOL& bThousand, USHORT& nPrecision, USHORT& nAnzLeading ) const
3786 // take info from a specified sub-format (for XML export)
3788 if ( nNumFor > 3 )
3789 return; // invalid
3791 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
3792 rScannedType = rInfo.eScannedType;
3793 bThousand = rInfo.bThousand;
3794 nPrecision = rInfo.nCntPost;
3795 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
3796 // StandardFormat
3797 nAnzLeading = 1;
3798 else
3800 nAnzLeading = 0;
3801 BOOL bStop = FALSE;
3802 USHORT i = 0;
3803 const USHORT nAnz = NumFor[nNumFor].GetnAnz();
3804 while (!bStop && i < nAnz)
3806 short nType = rInfo.nTypeArray[i];
3807 if ( nType == NF_SYMBOLTYPE_DIGIT)
3809 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
3810 while ( *p == '#' )
3811 p++;
3812 while ( *p++ == '0' )
3813 nAnzLeading++;
3815 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
3816 bStop = TRUE;
3817 i++;
3822 const String* SvNumberformat::GetNumForString( USHORT nNumFor, USHORT nPos,
3823 BOOL bString /* = FALSE */ ) const
3825 if ( nNumFor > 3 )
3826 return NULL;
3827 USHORT nAnz = NumFor[nNumFor].GetnAnz();
3828 if ( !nAnz )
3829 return NULL;
3830 if ( nPos == 0xFFFF )
3832 nPos = nAnz - 1;
3833 if ( bString )
3834 { // rueckwaerts
3835 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3836 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3837 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3839 pType--;
3840 nPos--;
3842 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3843 return NULL;
3846 else if ( nPos > nAnz - 1 )
3847 return NULL;
3848 else if ( bString )
3849 { // vorwaerts
3850 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3851 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3852 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3854 pType++;
3855 nPos++;
3857 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
3858 (*pType != NF_SYMBOLTYPE_CURRENCY)) )
3859 return NULL;
3861 return &NumFor[nNumFor].Info().sStrArray[nPos];
3865 short SvNumberformat::GetNumForType( USHORT nNumFor, USHORT nPos,
3866 BOOL bString /* = FALSE */ ) const
3868 if ( nNumFor > 3 )
3869 return 0;
3870 USHORT nAnz = NumFor[nNumFor].GetnAnz();
3871 if ( !nAnz )
3872 return 0;
3873 if ( nPos == 0xFFFF )
3875 nPos = nAnz - 1;
3876 if ( bString )
3877 { // rueckwaerts
3878 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3879 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3880 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3882 pType--;
3883 nPos--;
3885 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3886 return 0;
3889 else if ( nPos > nAnz - 1 )
3890 return 0;
3891 else if ( bString )
3892 { // vorwaerts
3893 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3894 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3895 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3897 pType++;
3898 nPos++;
3900 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3901 return 0;
3903 return NumFor[nNumFor].Info().nTypeArray[nPos];
3907 BOOL SvNumberformat::IsNegativeWithoutSign() const
3909 if ( IsNegativeRealNegative() )
3911 const String* pStr = GetNumForString( 1, 0, TRUE );
3912 if ( pStr )
3913 return !HasStringNegativeSign( *pStr );
3915 return FALSE;
3919 DateFormat SvNumberformat::GetDateOrder() const
3921 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
3923 short const * const pType = NumFor[0].Info().nTypeArray;
3924 USHORT nAnz = NumFor[0].GetnAnz();
3925 for ( USHORT j=0; j<nAnz; j++ )
3927 switch ( pType[j] )
3929 case NF_KEY_D :
3930 case NF_KEY_DD :
3931 return DMY;
3932 case NF_KEY_M :
3933 case NF_KEY_MM :
3934 case NF_KEY_MMM :
3935 case NF_KEY_MMMM :
3936 case NF_KEY_MMMMM :
3937 return MDY;
3938 case NF_KEY_YY :
3939 case NF_KEY_YYYY :
3940 case NF_KEY_EC :
3941 case NF_KEY_EEC :
3942 case NF_KEY_R :
3943 case NF_KEY_RR :
3944 return YMD;
3948 else
3950 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
3952 return rLoc().getDateFormat();
3956 sal_uInt32 SvNumberformat::GetExactDateOrder() const
3958 sal_uInt32 nRet = 0;
3959 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
3961 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
3962 return nRet;
3964 short const * const pType = NumFor[0].Info().nTypeArray;
3965 USHORT nAnz = NumFor[0].GetnAnz();
3966 int nShift = 0;
3967 for ( USHORT j=0; j<nAnz && nShift < 3; j++ )
3969 switch ( pType[j] )
3971 case NF_KEY_D :
3972 case NF_KEY_DD :
3973 nRet = (nRet << 8) | 'D';
3974 ++nShift;
3975 break;
3976 case NF_KEY_M :
3977 case NF_KEY_MM :
3978 case NF_KEY_MMM :
3979 case NF_KEY_MMMM :
3980 case NF_KEY_MMMMM :
3981 nRet = (nRet << 8) | 'M';
3982 ++nShift;
3983 break;
3984 case NF_KEY_YY :
3985 case NF_KEY_YYYY :
3986 case NF_KEY_EC :
3987 case NF_KEY_EEC :
3988 case NF_KEY_R :
3989 case NF_KEY_RR :
3990 nRet = (nRet << 8) | 'Y';
3991 ++nShift;
3992 break;
3995 return nRet;
3999 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
4000 SvNumberformatLimitOps& rOper2, double& rVal2 ) const
4002 rOper1 = eOp1;
4003 rOper2 = eOp2;
4004 rVal1 = fLimit1;
4005 rVal2 = fLimit2;
4009 Color* SvNumberformat::GetColor( USHORT nNumFor ) const
4011 if ( nNumFor > 3 )
4012 return NULL;
4014 return NumFor[nNumFor].GetColor();
4018 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
4019 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
4021 if ( eOp != NUMBERFORMAT_OP_NO )
4023 switch ( eOp )
4025 case NUMBERFORMAT_OP_EQ :
4026 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4027 break;
4028 case NUMBERFORMAT_OP_NE :
4029 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4030 break;
4031 case NUMBERFORMAT_OP_LT :
4032 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4033 break;
4034 case NUMBERFORMAT_OP_LE :
4035 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4036 break;
4037 case NUMBERFORMAT_OP_GT :
4038 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4039 break;
4040 case NUMBERFORMAT_OP_GE :
4041 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4042 break;
4043 default:
4044 OSL_ASSERT( "unsupported number format" );
4045 break;
4047 rStr += String( ::rtl::math::doubleToUString( fLimit,
4048 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4049 rDecSep.GetChar(0), sal_True));
4050 rStr += ']';
4055 String SvNumberformat::GetMappedFormatstring(
4056 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
4057 BOOL bDontQuote ) const
4059 String aStr;
4060 BOOL bDefault[4];
4061 // 1 subformat matches all if no condition specified,
4062 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
4063 // with 2 subformats [>=0];[<0] is implied if no condition specified
4064 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
4065 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
4066 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
4067 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4068 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4069 bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
4070 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
4071 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
4072 BOOL bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
4073 // from now on bDefault[] values are used to append empty subformats at the end
4074 bDefault[3] = FALSE;
4075 if ( !bDefaults )
4076 { // conditions specified
4077 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
4078 bDefault[0] = bDefault[1] = TRUE; // [];x
4079 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
4080 NumFor[2].GetnAnz() == 0 )
4081 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = TRUE; // [];[];;
4082 // nothing to do if conditions specified for every subformat
4084 else if ( bDefault[0] )
4085 bDefault[0] = FALSE; // a single unconditional subformat is never delimited
4086 else
4088 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
4089 bDefault[3] = TRUE; // special cases x;x;; and ;x;;
4090 for ( int i=0; i<3 && !bDefault[i]; ++i )
4091 bDefault[i] = TRUE;
4093 int nSem = 0; // needed ';' delimiters
4094 int nSub = 0; // subformats delimited so far
4095 for ( int n=0; n<4; n++ )
4097 if ( n > 0 )
4098 nSem++;
4100 String aPrefix;
4102 if ( !bDefaults )
4104 switch ( n )
4106 case 0 :
4107 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
4108 fLimit1, rLocWrp.getNumDecimalSep() );
4109 break;
4110 case 1 :
4111 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
4112 fLimit2, rLocWrp.getNumDecimalSep() );
4113 break;
4117 const String& rColorName = NumFor[n].GetColorName();
4118 if ( rColorName.Len() )
4120 const String* pKey = rScan.GetKeywords() + NF_KEY_FIRSTCOLOR;
4121 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++, pKey++ )
4123 if ( *pKey == rColorName )
4125 aPrefix += '[';
4126 aPrefix += rKeywords[j];
4127 aPrefix += ']';
4128 break; // for
4133 const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
4134 // The Thai T NatNum modifier during Xcl export.
4135 if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
4136 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
4137 MsLangId::getRealLanguage( rNum.GetLang()) ==
4138 LANGUAGE_THAI)
4140 aPrefix += 't'; // must be lowercase, otherwise taken as literal
4143 USHORT nAnz = NumFor[n].GetnAnz();
4144 if ( nSem && (nAnz || aPrefix.Len()) )
4146 for ( ; nSem; --nSem )
4147 aStr += ';';
4148 for ( ; nSub <= n; ++nSub )
4149 bDefault[nSub] = FALSE;
4152 if ( aPrefix.Len() )
4153 aStr += aPrefix;
4155 if ( nAnz )
4157 const short* pType = NumFor[n].Info().nTypeArray;
4158 const String* pStr = NumFor[n].Info().sStrArray;
4159 for ( USHORT j=0; j<nAnz; j++ )
4161 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
4163 aStr += rKeywords[pType[j]];
4164 if( NF_KEY_NNNN == pType[j] )
4165 aStr += rLocWrp.getLongDateDayOfWeekSep();
4167 else
4169 switch ( pType[j] )
4171 case NF_SYMBOLTYPE_DECSEP :
4172 aStr += rLocWrp.getNumDecimalSep();
4173 break;
4174 case NF_SYMBOLTYPE_THSEP :
4175 aStr += rLocWrp.getNumThousandSep();
4176 break;
4177 case NF_SYMBOLTYPE_DATESEP :
4178 aStr += rLocWrp.getDateSep();
4179 break;
4180 case NF_SYMBOLTYPE_TIMESEP :
4181 aStr += rLocWrp.getTimeSep();
4182 break;
4183 case NF_SYMBOLTYPE_TIME100SECSEP :
4184 aStr += rLocWrp.getTime100SecSep();
4185 break;
4186 case NF_SYMBOLTYPE_STRING :
4187 if( bDontQuote )
4188 aStr += pStr[j];
4189 else if ( pStr[j].Len() == 1 )
4191 aStr += '\\';
4192 aStr += pStr[j];
4194 else
4196 aStr += '"';
4197 aStr += pStr[j];
4198 aStr += '"';
4200 break;
4201 default:
4202 aStr += pStr[j];
4209 for ( ; nSub<4 && bDefault[nSub]; ++nSub )
4210 { // append empty subformats
4211 aStr += ';';
4213 return aStr;
4217 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
4218 sal_Int32 nVal, USHORT nMinDigits ) const
4220 String aStr;
4221 if ( nMinDigits )
4223 if ( nMinDigits == 2 )
4224 { // speed up the most common case
4225 if ( 0 <= nVal && nVal < 10 )
4227 sal_Unicode* p = aStr.AllocBuffer( 2 );
4228 *p++ = '0';
4229 *p = sal_Unicode( '0' + nVal );
4231 else
4232 aStr = String::CreateFromInt32( nVal );
4234 else
4236 String aValStr( String::CreateFromInt32( nVal ) );
4237 if ( aValStr.Len() >= nMinDigits )
4238 aStr = aValStr;
4239 else
4241 aStr.Fill( nMinDigits - aValStr.Len(), '0' );
4242 aStr += aValStr;
4246 else
4247 aStr = String::CreateFromInt32( nVal );
4248 ImpTransliterate( aStr, rNum );
4249 return aStr;
4253 void SvNumberformat::ImpTransliterateImpl( String& rStr,
4254 const SvNumberNatNum& rNum ) const
4256 com::sun::star::lang::Locale aLocale(
4257 MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4258 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
4259 aLocale, rNum.GetNatNum() );
4263 void SvNumberformat::GetNatNumXml(
4264 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
4265 USHORT nNumFor ) const
4267 if ( nNumFor <= 3 )
4269 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
4270 if ( rNum.IsSet() )
4272 com::sun::star::lang::Locale aLocale(
4273 MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4274 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
4275 aLocale, rNum.GetNatNum() );
4277 else
4278 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4280 else
4281 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4284 // static
4285 BOOL SvNumberformat::HasStringNegativeSign( const String& rStr )
4287 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4288 xub_StrLen nLen = rStr.Len();
4289 if ( !nLen )
4290 return FALSE;
4291 const sal_Unicode* const pBeg = rStr.GetBuffer();
4292 const sal_Unicode* const pEnd = pBeg + nLen;
4293 register const sal_Unicode* p = pBeg;
4295 { // Anfang
4296 if ( *p == '-' )
4297 return TRUE;
4298 } while ( *p == ' ' && ++p < pEnd );
4299 p = pEnd - 1;
4301 { // Ende
4302 if ( *p == '-' )
4303 return TRUE;
4304 } while ( *p == ' ' && pBeg < --p );
4305 return FALSE;
4309 // static
4310 void SvNumberformat::SetComment( const String& rStr, String& rFormat,
4311 String& rComment )
4313 if ( rComment.Len() )
4314 { // alten Kommentar aus Formatstring loeschen
4315 //! nicht per EraseComment, der Kommentar muss matchen
4316 String aTmp( '{' );
4317 aTmp += ' ';
4318 aTmp += rComment;
4319 aTmp += ' ';
4320 aTmp += '}';
4321 xub_StrLen nCom = 0;
4324 nCom = rFormat.Search( aTmp, nCom );
4325 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
4326 if ( nCom != STRING_NOTFOUND )
4327 rFormat.Erase( nCom );
4329 if ( rStr.Len() )
4330 { // neuen Kommentar setzen
4331 rFormat += '{';
4332 rFormat += ' ';
4333 rFormat += rStr;
4334 rFormat += ' ';
4335 rFormat += '}';
4336 rComment = rStr;
4341 // static
4342 void SvNumberformat::EraseCommentBraces( String& rStr )
4344 xub_StrLen nLen = rStr.Len();
4345 if ( nLen && rStr.GetChar(0) == '{' )
4347 rStr.Erase( 0, 1 );
4348 --nLen;
4350 if ( nLen && rStr.GetChar(0) == ' ' )
4352 rStr.Erase( 0, 1 );
4353 --nLen;
4355 if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
4356 rStr.Erase( --nLen, 1 );
4357 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
4358 rStr.Erase( --nLen, 1 );
4362 // static
4363 void SvNumberformat::EraseComment( String& rStr )
4365 register const sal_Unicode* p = rStr.GetBuffer();
4366 BOOL bInString = FALSE;
4367 BOOL bEscaped = FALSE;
4368 BOOL bFound = FALSE;
4369 xub_StrLen nPos = 0;
4370 while ( !bFound && *p )
4372 switch ( *p )
4374 case '\\' :
4375 bEscaped = !bEscaped;
4376 break;
4377 case '\"' :
4378 if ( !bEscaped )
4379 bInString = !bInString;
4380 break;
4381 case '{' :
4382 if ( !bEscaped && !bInString )
4384 bFound = TRUE;
4385 nPos = sal::static_int_cast< xub_StrLen >(
4386 p - rStr.GetBuffer());
4388 break;
4390 if ( bEscaped && *p != '\\' )
4391 bEscaped = FALSE;
4392 ++p;
4394 if ( bFound )
4395 rStr.Erase( nPos );
4399 // static
4400 BOOL SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
4401 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4403 xub_StrLen nLen = rStr.Len();
4404 if ( nPos >= nLen )
4405 return FALSE;
4406 register const sal_Unicode* p0 = rStr.GetBuffer();
4407 register const sal_Unicode* p = p0;
4408 register const sal_Unicode* p1 = p0 + nPos;
4409 BOOL bQuoted = FALSE;
4410 while ( p <= p1 )
4412 if ( *p == cQuote )
4414 if ( p == p0 )
4415 bQuoted = TRUE;
4416 else if ( bQuoted )
4418 if ( *(p-1) != cEscIn )
4419 bQuoted = FALSE;
4421 else
4423 if ( *(p-1) != cEscOut )
4424 bQuoted = TRUE;
4427 p++;
4429 return bQuoted;
4433 // static
4434 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
4435 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4437 xub_StrLen nLen = rStr.Len();
4438 if ( nPos >= nLen )
4439 return STRING_NOTFOUND;
4440 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
4442 if ( rStr.GetChar( nPos ) == cQuote )
4443 return nPos; // schliessendes cQuote
4444 return STRING_NOTFOUND;
4446 register const sal_Unicode* p0 = rStr.GetBuffer();
4447 register const sal_Unicode* p = p0 + nPos;
4448 register const sal_Unicode* p1 = p0 + nLen;
4449 while ( p < p1 )
4451 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
4452 return sal::static_int_cast< xub_StrLen >(p - p0);
4453 p++;
4455 return nLen; // String Ende
4459 USHORT SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor ) const
4461 USHORT nCnt = 0;
4462 USHORT nAnz = NumFor[nNumFor].GetnAnz();
4463 short const * const pType = NumFor[nNumFor].Info().nTypeArray;
4464 for ( USHORT j=0; j<nAnz; ++j )
4466 switch ( pType[j] )
4468 case NF_SYMBOLTYPE_STRING:
4469 case NF_SYMBOLTYPE_CURRENCY:
4470 case NF_SYMBOLTYPE_DATESEP:
4471 case NF_SYMBOLTYPE_TIMESEP:
4472 case NF_SYMBOLTYPE_TIME100SECSEP:
4473 case NF_SYMBOLTYPE_PERCENT:
4474 ++nCnt;
4475 break;
4478 return nCnt;