![]() |
API 0.9.5
|
00001 /* 00002 * CPNumberFormatter.j 00003 * Foundation 00004 * 00005 * Created by Alexander Ljungberg. 00006 * Copyright 2011, WireLoad Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #import "Ref.h" 00024 00025 00026 #define UPDATE_NUMBER_HANDLER_IF_NECESSARY() if (!_numberHandler) \ 00027 _numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:_roundingMode scale:_maximumFractionalDigits raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; 00028 #define SET_NEEDS_NUMBER_HANDLER_UPDATE() _numberHandler = nil; 00029 00030 CPNumberFormatterNoStyle = 0; 00031 CPNumberFormatterDecimalStyle = 1; 00032 CPNumberFormatterCurrencyStyle = 2; 00033 CPNumberFormatterPercentStyle = 3; 00034 CPNumberFormatterScientificStyle = 4; 00035 CPNumberFormatterSpellOutStyle = 5; 00036 00037 CPNumberFormatterRoundCeiling = CPRoundUp; 00038 CPNumberFormatterRoundFloor = CPRoundDown; 00039 CPNumberFormatterRoundDown = CPRoundDown; 00040 CPNumberFormatterRoundUp = CPRoundUp; 00041 CPNumberFormatterRoundHalfEven = CPRoundBankers; 00042 CPNumberFormatterRoundHalfDown = _CPRoundHalfDown; 00043 CPNumberFormatterRoundHalfUp = CPRoundPlain; 00044 00053 @implementation CPNumberFormatter : CPFormatter 00054 { 00055 CPNumberFormatterStyle _numberStyle; 00056 CPString _perMillSymbol; 00057 CPNumberFormatterRoundingMode _roundingMode; 00058 CPUInteger _maximumFractionalDigits; 00059 00060 CPDecimalNumberHandler _numberHandler; 00061 } 00062 00063 - (id)init 00064 { 00065 if (self = [super init]) 00066 { 00067 _roundingMode = CPNumberFormatterRoundHalfUp; 00068 _maximumFractionalDigits = 3; 00069 } 00070 00071 return self; 00072 } 00073 00074 - (CPString)stringFromNumber:(CPNumber)number 00075 { 00076 // TODO Add locale support. 00077 switch(_numberStyle) 00078 { 00079 case CPNumberFormatterDecimalStyle: 00080 UPDATE_NUMBER_HANDLER_IF_NECESSARY(); 00081 00082 var dcmn = [CPDecimalNumber numberWithFloat:number]; 00083 dcmn = [dcmn decimalNumberByRoundingAccordingToBehavior:_numberHandler]; 00084 00085 var output = [dcmn descriptionWithLocale:nil], 00086 parts = [output componentsSeparatedByString:"."], // FIXME Locale specific. 00087 preFraction = parts[0], 00088 fraction = parts.length > 1 ? parts[1] : "", 00089 preFractionLength = [preFraction length], 00090 commaPosition = 3, 00091 perMillSymbol = [self _effectivePerMillSymbol]; 00092 00093 // TODO This is just a temporary solution. Should be generalised. 00094 // Add in thousands separators. 00095 if (perMillSymbol) 00096 while(commaPosition < [preFraction length]) 00097 { 00098 preFraction = [preFraction stringByReplacingCharactersInRange:CPMakeRange(commaPosition, 0) withString:perMillSymbol]; 00099 commaPosition += 4; 00100 } 00101 00102 if (fraction) 00103 return preFraction + "." + fraction; 00104 else 00105 return preFraction; 00106 default: 00107 return [number description]; 00108 } 00109 } 00110 00111 - (CPNumber)numberFromString:(CPString)string 00112 { 00113 // TODO 00114 return parseFloat(string); 00115 } 00116 00117 - (CPString)stringForObjectValue:(id)anObject 00118 { 00119 if ([anObject isKindOfClass:[CPNumber class]]) 00120 return [self stringFromNumber:anObject]; 00121 else 00122 return [anObject description]; 00123 } 00124 00125 - (CPString)editingStringForObjectValue:(id)anObject 00126 { 00127 return [self stringForObjectValue:anObject]; 00128 } 00129 00130 - (BOOL)getObjectValue:(id)anObject forString:(CPString)aString errorDescription:(CPString)anError 00131 { 00132 // TODO Error handling. 00133 var value = [self numberFromString:aString]; 00134 AT_DEREF(anObject, value); 00135 00136 return YES; 00137 } 00138 00143 - (CPString)_effectivePerMillSymbol 00144 { 00145 if (_perMillSymbol === nil || _perMillSymbol === undefined) 00146 return ","; // (FIXME US Locale specific.) 00147 return _perMillSymbol; 00148 } 00149 00150 - (void)setRoundingMode:(CPNumberFormatterRoundingMode)aRoundingMode 00151 { 00152 _roundingMode = aRoundingMode; 00153 SET_NEEDS_NUMBER_HANDLER_UPDATE(); 00154 } 00155 00156 - (void)setMaximumFractionDigits:(CPUInteger)aNumber 00157 { 00158 _maximumFractionalDigits = aNumber; 00159 SET_NEEDS_NUMBER_HANDLER_UPDATE(); 00160 } 00161 00162 @end 00163 00164 var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey"; 00165 00166 @implementation CPNumberFormatter (CPCoding) 00167 00168 - (id)initWithCoder:(CPCoder)aCoder 00169 { 00170 self = [super initWithCoder:aCoder]; 00171 00172 if (self) 00173 { 00174 _numberStyle = [aCoder decodeIntForKey:CPNumberFormatterStyleKey]; 00175 } 00176 00177 return self; 00178 } 00179 00180 - (void)encodeWithCoder:(CPCoder)aCoder 00181 { 00182 [super encodeWithCoder:aCoder]; 00183 00184 [aCoder encodeInt:_numberStyle forKey:CPNumberFormatterStyleKey]; 00185 } 00186 00187 @end 00188 00189 @implementation CPNumberFormatter (CPSynthesizedAccessors) 00190 00194 - (CPNumberFormatterStyle)numberStyle 00195 { 00196 return _numberStyle; 00197 } 00198 00202 - (void)setNumberStyle:(CPNumberFormatterStyle)aValue 00203 { 00204 _numberStyle = aValue; 00205 } 00206 00210 - (CPString)perMillSymbol 00211 { 00212 return _perMillSymbol; 00213 } 00214 00218 - (void)setPerMillSymbol:(CPString)aValue 00219 { 00220 _perMillSymbol = aValue; 00221 } 00222 00226 - (CPNumberFormatterRoundingMode)roundingMode 00227 { 00228 return _roundingMode; 00229 } 00230 00234 - (void)setRoundingMode:(CPNumberFormatterRoundingMode)aValue 00235 { 00236 _roundingMode = aValue; 00237 } 00238 00242 - (CPUInteger)maximalFractionalDigits 00243 { 00244 return _maximumFractionalDigits; 00245 } 00246 00250 - (void)setMaximalFractionalDigits:(CPUInteger)aValue 00251 { 00252 _maximumFractionalDigits = aValue; 00253 } 00254 00255 @end