API 0.9.5
Foundation/CPNumberFormatter.j
Go to the documentation of this file.
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
 All Classes Files Functions Variables Defines