Better formatter support

This commit is contained in:
Airy ANDRE 2013-03-27 20:19:14 +01:00
parent a3b0347f2d
commit f63e1bdb24
11 changed files with 429 additions and 91 deletions

View File

@ -7,8 +7,10 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import <AppKit/NSActionCell.h>
#import <Foundation/NSKeyedArchiver.h>
#import <AppKit/NSControl.h>
@implementation NSActionCell
@class NSControl;
-(void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
@ -62,4 +64,76 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_tag=tag;
}
- (void)_validateEditing
{
if ([_controlView isKindOfClass: [NSControl class]]) {
[(NSControl *)_controlView validateEditing];
}
}
// Cocoa is validating the editing everytime the ask is being asked - let's do the same
// That's what will ensure the values are always properly formatted by the current formatter (if any)
/**
* Retrieve the value of the receiver
*/
- (id) objectValue
{
[self _validateEditing];
return [super objectValue];
}
/**
* Retrieve the value of the receiver as an NSAttributedString.
*/
- (NSAttributedString*) attributedStringValue
{
[self _validateEditing];
return [super attributedStringValue];
}
/**
* Retrieve the value of the receiver as an NSString.
*/
- (NSString *) stringValue
{
[self _validateEditing];
return [super stringValue];
}
/**
* Retrieve the value of the receiver as a double.
*/
- (double) doubleValue
{
[self _validateEditing];
return [super doubleValue];
}
/**
* Retrieve the value of the receiver as a float.
*/
- (float) floatValue
{
[self _validateEditing];
return [super floatValue];
}
/**
* Retrieve the value of the receiver as an int.
*/
- (int) intValue
{
[self _validateEditing];
return [super intValue];
}
/**
* Retrieve the value of the receiver as an NSInteger.
*/
- (NSInteger) integerValue
{
[self _validateEditing];
return [super integerValue];
}
@end

View File

@ -109,6 +109,7 @@ enum {
BOOL _isContinuous;
BOOL _allowsMixedState;
BOOL _sendsActionOnEndEditing;
BOOL _hasValidObjectValue;
}
#pragma mark -
@ -151,6 +152,7 @@ enum {
-(BOOL)refusesFirstResponder;
-(BOOL)isHighlighted;
-(BOOL)hasValidObjectValue;
-objectValue;
-(NSString *)stringValue;
-(int)intValue;

View File

@ -68,6 +68,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_isSelectable=(flags&0x00200000)?YES:NO;
_isScrollable=(flags&0x00100000)?YES:NO;
_refusesFirstResponder=(flags2&0x2000000)?YES:NO;
_hasValidObjectValue = YES;
// _wraps=(flags&0x00100000)?NO:YES; // ! scrollable, use lineBreakMode ?
_allowsMixedState=(flags2&0x1000000)?YES:NO;
// 0x00080000 = continuous
@ -116,6 +118,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_isHighlighted=NO;
_refusesFirstResponder=NO;
_lineBreakMode=NSLineBreakByWordWrapping;
_hasValidObjectValue = YES;
return self;
}
@ -134,6 +137,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_isHighlighted=NO;
_refusesFirstResponder=NO;
_lineBreakMode=NSLineBreakByWordWrapping;
_hasValidObjectValue = YES;
return self;
}
@ -271,17 +275,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
return _isHighlighted;
}
-(BOOL)hasValidObjectValue
{
return _hasValidObjectValue;
}
/*
"Returns the receiver's object value, or nil if a valid object has not been associated with the receiver."
*/
-objectValue {
return _objectValue;
if (_hasValidObjectValue) {
return _objectValue;
} else {
return nil;
}
}
-(NSString *)stringValue {
NSString *formatted;
if (_formatter != nil)
if ((formatted = [_formatter stringForObjectValue:_objectValue])!=nil)
return formatted;
if([_objectValue isKindOfClass:[NSAttributedString class]])
return [_objectValue string];
else if([_objectValue isKindOfClass:[NSString class]])
@ -319,8 +333,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[[NSScanner localizedScannerWithString:objString] scanFloat:&f];
return f;
}
else
else {
return [_objectValue floatValue];
}
}
-(double)doubleValue {
@ -585,10 +600,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
-(void)setObjectValue:(id <NSCopying>)value {
value=[value copyWithZone:NULL];
[_objectValue release];
_objectValue=value;
[(NSControl *)[self controlView] updateCell:self];
value=[value copyWithZone:NULL];
[_objectValue release];
_objectValue=value;
_hasValidObjectValue = YES;
[(NSControl *)[self controlView] updateCell:self];
}
-(void)setStringValue:(NSString *)value {
@ -600,12 +616,15 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[self setType:NSTextCellType];
if (_formatter != nil) {
id formattedValue;
if ([_formatter getObjectValue:&formattedValue forString:value errorDescription:NULL])
id formattedValue = nil;
if ([_formatter getObjectValue:&formattedValue forString:value errorDescription:NULL]) {
value=formattedValue;
} else {
// Invalid format
_hasValidObjectValue = NO;
return;
}
}
[self setObjectValue:value];
}
@ -857,7 +876,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
return;
[self _setupFieldEditorWithFrame:frame controlView:view editor:editor delegate:delegate];
[editor mouseDown:event];
[editor mouseDown:event];
}
-(void)selectWithFrame:(NSRect)frame inView:(NSView *)view editor:(NSText *)editor delegate:(id)delegate start:(int)location length:(int)length {
@ -868,11 +887,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
return;
[self _setupFieldEditorWithFrame:frame controlView:view editor:editor delegate:delegate];
[editor setSelectedRange:NSMakeRange(location,length)];
NSRange range = NSMakeRange(location, length);
NSRange maxRange = NSMakeRange(0, [[editor string] length]);
[editor setSelectedRange:NSIntersectionRange(range, maxRange)];
}
-(void)endEditing:(NSText *)editor {
[self setStringValue:[editor string]];
}
-(void)resetCursorRect:(NSRect)rect inView:(NSView *)view {

View File

@ -109,18 +109,18 @@ APPKIT_EXPORT NSString * const NSControlTextDidEndEditingNotification;
@end
@interface NSObject(NSControl_delegate)
-(BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;
-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;
-(void)controlTextDidBeginEditing:(NSNotification *)note;
-(void)controlTextDidChange:(NSNotification *)note;
-(void)controlTextDidEndEditing:(NSNotification *)note;
@end
@protocol NSControlTextEditingDelegate <NSObject>
// FIXME: this causes a compiler fault with ObjC++, fix compiler
//@optional
@optional
-(BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)selector;
-(BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;
-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;
-(BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string errorDescription:(NSString *)error;
-(void)control:(NSControl *)control didFailToValidatePartialString:(NSString *)string errorDescription:(NSString *)error;
-(BOOL)control:(NSControl *)control isValidObject:(id)obj;
@end

View File

@ -13,6 +13,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#import <AppKit/NSApplication.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSClipView.h>
#import <AppKit/NSTextView.h>
#import <AppKit/NSTextStorage.h>
#import <Foundation/NSKeyedArchiver.h>
#import <AppKit/NSRaise.h>
#import <AppKit/NSObject+BindingSupport.h>
@ -255,60 +257,81 @@ static NSMutableDictionary *cellClassDictionary = nil;
}
-(void)setObjectValue:(id <NSCopying>)object {
// FIX protocol does not implement isEqual
if(![(id)object isEqual:[[self selectedCell] objectValue]]){
[self abortEditing];
[(NSCell *)[self selectedCell] setObjectValue:object];
[self setNeedsDisplay:YES];
}
}
-(void)setStringValue:(NSString *)value {
[self setObjectValue:value];
[self abortEditing];
[[self selectedCell] setStringValue:value];
[self setNeedsDisplay:YES];
}
-(void)setIntValue:(int)value {
[self setObjectValue:[NSNumber numberWithInt:value]];
[self abortEditing];
[[self selectedCell] setIntValue:value];
[self setNeedsDisplay:YES];
}
-(void)setFloatValue:(float)value {
[self setObjectValue:[NSNumber numberWithFloat:value]];
[self abortEditing];
[[self selectedCell] setFloatValue:value];
[self setNeedsDisplay:YES];
}
-(void)setDoubleValue:(double)value {
[self setObjectValue:[NSNumber numberWithDouble:value]];
[self abortEditing];
[[self selectedCell] setDoubleValue:value];
[self setNeedsDisplay:YES];
}
-(void)setIntegerValue:(NSInteger)value {
[self setObjectValue:[NSNumber numberWithInteger:value]];
[self abortEditing];
[[self selectedCell] setIntegerValue:value];
[self setNeedsDisplay:YES];
}
-(void)setAttributedStringValue:(NSAttributedString *)value {
[self setObjectValue:value];
[self abortEditing];
[[self selectedCell] setAttributedStringValue:value];
[self setNeedsDisplay:YES];
}
-(void)takeObjectValueFrom:sender {
[self setObjectValue:[sender objectValue]];
[self abortEditing];
[[self selectedCell] takeObjectValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)takeStringValueFrom:sender {
[self setStringValue:[sender stringValue]];
[self abortEditing];
[[self selectedCell] takeStringValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)takeIntValueFrom:sender {
[self setIntValue:[sender intValue]];
[self abortEditing];
[[self selectedCell] takeIntValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)takeFloatValueFrom:sender {
[self setFloatValue:[sender floatValue]];
[self abortEditing];
[[self selectedCell] takeFloatValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)takeDoubleValueFrom:sender {
[self setDoubleValue:[sender doubleValue]];
[self abortEditing];
[[self selectedCell] takeDoubleValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)takeIntegerValueFrom:sender {
[self setIntegerValue:[sender integerValue]];
[self abortEditing];
[[self selectedCell] takeIntegerValueFrom:sender];
[self setNeedsDisplay:YES];
}
-(void)selectCell:(NSCell *)cell {
@ -358,8 +381,38 @@ static NSMutableDictionary *cellClassDictionary = nil;
return _currentEditor;
}
-(void)validateEditing {
NSUnimplementedMethod();
-(void)validateEditing
{
if (_currentEditor) {
NSString *string = [_currentEditor string];
BOOL acceptsString = YES;
NSFormatter *formatter = [self formatter];
if (formatter) {
acceptsString = NO;
id objectValue = nil;
NSString *error = nil;
if ([formatter getObjectValue: &objectValue
forString: string
errorDescription: &error] == YES) {
[[self selectedCell] setObjectValue:objectValue];
}
}
if (acceptsString) {
if ([_currentEditor isRichText]) {
if ([_currentEditor isKindOfClass:[NSTextView class]]) {
NSTextView *textview = (NSTextView *)_currentEditor;
NSAttributedString *text = [textview textStorage];
NSAttributedString *string = [[[NSAttributedString alloc] initWithAttributedString:text] autorelease];
[[self selectedCell] setAttributedStringValue:string];
} else {
[[self selectedCell] setStringValue:string];
}
} else {
[[self selectedCell] setStringValue:string];
}
}
}
}
-(BOOL)abortEditing {
@ -399,6 +452,13 @@ static NSMutableDictionary *cellClassDictionary = nil;
return ![self refusesFirstResponder];
}
-(BOOL)resignFirstResponder {
if (_currentEditor) {
return [[self selectedCell] hasValidObjectValue];
}
return YES;
}
-(void)lockFocus {
[self calcSize];
[super lockFocus];
@ -437,8 +497,8 @@ static NSMutableDictionary *cellClassDictionary = nil;
if([note object]!=_currentEditor)
return;
[[self selectedCell] endEditing:_currentEditor];
[self abortEditing];
[self validateEditing];
[self abortEditing];
[[NSNotificationCenter defaultCenter] postNotificationName:NSControlTextDidEndEditingNotification
object:self userInfo:[NSDictionary dictionaryWithObject:[note object] forKey:@"NSFieldEditor"]];

View File

@ -53,7 +53,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
_cellBackgroundColor=[[keyed decodeObjectForKey:@"NSCellBackgroundColor"] retain];
name=[keyed decodeObjectForKey:@"NSCellClass"];
if((_cellClass=NSClassFromString(name))==Nil){
NSLog(@"Unknown cell class %@ in NSMatrix, using NSCell",name);
if (name) {
NSLog(@"Unknown cell class '%@' in NSMatrix, using NSCell",name);
}
_cellClass=[NSCell class];
}
_prototype=[[keyed decodeObjectForKey:@"NSProtoCell"] retain];

View File

@ -7,6 +7,8 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import <AppKit/NSTextField.h>
#import <AppKit/NSTextFieldCell.h>
#import <AppKit/NSTextView.h>
#import <AppKit/NSTextStorage.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSCursor.h>
@ -150,8 +152,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
if([cell isEditable] || [cell isSelectable]){
if(_currentEditor==nil){
NSText* editor =[[self window] fieldEditor:YES forObject:self];
_currentEditor=[[cell setUpFieldEditorAttributes: editor] retain];
NSText* editor =[[self window] fieldEditor:YES forObject:self];
_currentEditor = [[cell setUpFieldEditorAttributes: editor] retain];
}
[cell selectWithFrame:[self bounds] inView:self editor:_currentEditor delegate:self start:range.location length:range.length];
@ -159,7 +161,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
}
-(void)selectText:sender {
[self _selectTextWithRange:NSMakeRange(0,[[self stringValue] length])];
[self _selectTextWithRange:NSMakeRange(0,[[self stringValue] length])];
}
@ -180,7 +182,50 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
return [self nextKeyView];
}
-(void)validateEditing
{
if (_currentEditor) {
NSString *string = [_currentEditor string];
BOOL acceptsString = YES;
NSFormatter *formatter = [self formatter];
if (formatter) {
acceptsString = NO;
id objectValue = nil;
NSString *error = nil;
if ([formatter getObjectValue: &objectValue
forString: string
errorDescription: &error] == YES) {
[[self selectedCell] setObjectValue:objectValue];
} else {
// Ask the delegate what to do
SEL sel = @selector(control:didFailToFormatString:errorDescription:);
if ([_delegate respondsToSelector: sel]) {
acceptsString = [_delegate control: self
didFailToFormatString: string
errorDescription: error];
}
}
}
if (acceptsString) {
if ([_currentEditor isRichText]) {
if ([_currentEditor isKindOfClass:[NSTextView class]]) {
NSTextView *textview = (NSTextView *)_currentEditor;
NSAttributedString *text = [textview textStorage];
NSAttributedString *string = [[[NSAttributedString alloc] initWithAttributedString:text] autorelease];
[[self selectedCell] setAttributedStringValue:string];
} else {
[[self selectedCell] setStringValue:string];
}
} else {
[[self selectedCell] setStringValue:string];
}
}
}
}
-(void)textDidEndEditing:(NSNotification *)note {
int movement=[[[note userInfo] objectForKey:@"NSTextMovement"] intValue];
[super textDidEndEditing:note];
@ -205,18 +250,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
NSPoint point=[self convertPoint:[event locationInWindow] fromView:nil];
NSRect editingFrame=[cell titleRectForBounds:[self bounds]];
if(!NSMouseInRect(point,editingFrame,[self isFlipped]))
[super mouseDown:event];
else {
if([cell isEditable] || [cell isSelectable]){
if(_currentEditor==nil){
NSText* editor =[[self window] fieldEditor:YES forObject:self];
_currentEditor=[[cell setUpFieldEditorAttributes: editor] retain];
if(!NSMouseInRect(point,editingFrame,[self isFlipped])) {
[super mouseDown:event];
}
[cell editWithFrame:[self bounds] inView:self editor:_currentEditor delegate:self event:event];
}
}
}
-(BOOL)textShouldBeginEditing:(NSText *)text {
@ -234,7 +270,40 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
NSBeep();
return NO;
}
return YES;
NSFormatter *formatter = [[self selectedCell] formatter];
BOOL acceptsString = YES;
if (formatter) {
// Ask the formatter if the string is valid
// If it's not, then we'll present an error and refuse the end of the editing
NSString *string = [text string];
id objectValue;
NSError *error = nil;
if ([formatter isKindOfClass:[NSNumberFormatter class]]) {
NSNumberFormatter *numberFormatter = (NSNumberFormatter *)formatter;
acceptsString = [numberFormatter getObjectValue:&objectValue forString:string range:NULL error:&error];
} else {
NSString *errorString;
if ([formatter getObjectValue: &objectValue
forString: string
errorDescription: &errorString] == NO) {
acceptsString = NO;
NSDictionary *info = nil;
if (errorString == nil) {
// Just in case we get no error from the formatter
errorString = NSLocalizedStringFromTableInBundle(@"Invalid number", nil, [NSBundle bundleForClass: [NSTextField class]], @"");
}
info = [NSDictionary dictionaryWithObject:errorString forKey:NSLocalizedDescriptionKey];
error = [NSError errorWithDomain:NSCocoaErrorDomain code:2048 userInfo:info];
}
}
if (error) {
[self presentError:error];
}
}
return acceptsString;
}
-(void)setEditable:(BOOL)flag {

View File

@ -78,7 +78,6 @@ NSString * const NSOldSelectedCharacterRange=@"NSOldSelectedCharacterRange";
@end
@implementation NSTextView
-(void)configureMenu {
static NSMenu *menu=nil;
@ -781,8 +780,13 @@ NSString * const NSOldSelectedCharacterRange=@"NSOldSelectedCharacterRange";
}
-(void)_textDidEndWithMovement:(NSInteger)movement {
[_insertionPointTimer invalidate];
[_insertionPointTimer release];
if ([_delegate respondsToSelector:@selector(textShouldEndEditing:)]) {
if ([_delegate textShouldEndEditing:self] == NO) {
return;
}
}
[_insertionPointTimer invalidate];
[_insertionPointTimer release];
_insertionPointTimer=nil;
NSDictionary *userInfo=[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:movement] forKey:@"NSTextMovement"];
@ -2468,6 +2472,9 @@ NSString * const NSOldSelectedCharacterRange=@"NSOldSelectedCharacterRange";
}
-(BOOL)resignFirstResponder {
if ([super resignFirstResponder] == NO) {
return NO;
}
if (_isEditable)
if ([_delegate respondsToSelector:@selector(textShouldEndEditing:)])
if ([_delegate textShouldEndEditing:self] == NO)

Binary file not shown.

View File

@ -139,7 +139,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
-(NSAttributedString *)attributedSubstringFromRange:(NSRange)range {
NSMutableAttributedString *result=[[[NSMutableAttributedString allocWithZone:NULL] init] autorelease];
NSUInteger location=range.location;
NSUInteger limit=NSMaxRange(range);
NSUInteger limit=MIN(NSMaxRange(range), [self length]);
while(location<limit){
NSRange effectiveRange,appendedRange;

View File

@ -6,13 +6,16 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#import <Foundation/NSString.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSCoder.h>
#import <Foundation/NSNumber.h>
#import <Foundation/NSScanner.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSAttributedString.h>
#import <Foundation/NSNumberFormatter.h>
#import <Foundation/NSException.h>
#import <Foundation/NSError.h>
#import <Foundation/NSRaise.h>
#import <Foundation/NSCharacterSet.h>
#import <Foundation/NSLocale.h>
@ -45,8 +48,10 @@ static NSNumberFormatterBehavior _defaultFormatterBehavior=NSNumberFormatterBeha
_behavior=_defaultFormatterBehavior;
_numberStyle=NSNumberFormatterNoStyle;
_thousandSeparator = @",";
_decimalSeparator = @".";
_locale= [[NSLocale currentLocale] retain];
_thousandSeparator = [[_locale objectForKey:NSLocaleGroupingSeparator] retain];
_decimalSeparator = [[_locale objectForKey:NSLocaleDecimalSeparator] retain];
_attributedStringForNil=[[NSAttributedString allocWithZone:NULL] initWithString:@"(null)"];
_attributedStringForNotANumber=[[NSAttributedString allocWithZone:NULL] initWithString:@"NaN"];
_attributedStringForZero=[[NSAttributedString allocWithZone:NULL] initWithString:@"0.0"];
@ -340,8 +345,53 @@ static void extractFormat(NSString *format,
}
-(void)dealloc {
[_negativeFormat release];
[_positiveFormat release];
[_locale release];
[_multiplier release];
[_minimum release];
[_maximum release];
[_nilSymbol release];
[_notANumberSymbol release];
[_zeroSymbol release];
[_plusSign release];
[_minusSign release];
[_negativePrefix release];
[_negativeSuffix release];
[_positivePrefix release];
[_positiveSuffix release];
[_negativeInfinitySymbol release];
[_positiveInfinitySymbol release];
[_decimalSeparator release];
[_exponentSymbol release];
[_currencyCode release];
[_currencySymbol release];
[_internationalCurrencySymbol release];
[_currencyDecimalSeparator release];
[_currencyGroupingSeparator release];
[_groupingSeparator release];
[_paddingCharacter release];
[_percentSymbol release];
[_perMillSymbol release];
[_roundingIncrement release];
[_positiveFormat release];
[_negativeFormat release];
[_textAttributesForPositiveValues release];
[_textAttributesForNegativeValues release];
[_textAttributesForNegativeInfinity release];
[_textAttributesForNil release];
[_textAttributesForNotANumber release];
[_textAttributesForPositiveInfinity release];
[_textAttributesForZero release];
[_attributedStringForNil release];
[_attributedStringForNotANumber release];
[_attributedStringForZero release];
[_roundingBehavior release];
[_thousandSeparator release];
[super dealloc];
}
@ -1209,9 +1259,53 @@ static BOOL numberIsPositive(NSNumber *number){
return [self stringFromNumber10_4:number];
}
-(NSNumber *)_numberFromString:(NSString *)string error:(NSString **)error
{
// simple test of characters...
NSMutableCharacterSet *digitsAndSeparators = [[[NSCharacterSet decimalDigitCharacterSet] mutableCopy] autorelease];
NSMutableString *mutableString = [[string mutableCopy] autorelease];
unichar thousandSeparator = [_thousandSeparator characterAtIndex:0];
[digitsAndSeparators addCharactersInString:_decimalSeparator];
if (_hasThousandSeparators) {
[digitsAndSeparators addCharactersInString:_thousandSeparator];
}
for (NSUInteger i = 0; i < [mutableString length]; ++i) {
if (![digitsAndSeparators characterIsMember:[mutableString characterAtIndex:i]]) {
if (error != NULL) {
*error = NSLocalizedStringFromTableInBundle(@"Invalid number", nil, [NSBundle bundleForClass: [NSNumberFormatter class]], @"");
}
return nil;
}
// take out the thousand separator
if (_hasThousandSeparators && [mutableString characterAtIndex:i] == thousandSeparator) {
[mutableString deleteCharactersInRange:NSMakeRange(i, 1)];
}
}
NSScanner *scanner = [NSScanner scannerWithString: mutableString];
if (_locale) {
[scanner setLocale: (id)_locale];
} else {
[scanner setLocale:[NSLocale currentLocale]];
}
float value;
NSNumber *number = nil;
if ([scanner scanFloat:&value] == NO) {
if (error != NULL) {
*error = NSLocalizedStringFromTableInBundle(@"Invalid number", nil, [NSBundle bundleForClass: [NSNumberFormatter class]], @"");
}
} else {
if ([self multiplier]) {
value /= [[self multiplier] floatValue];
}
number = [NSNumber numberWithFloat:value];
}
return number;
}
-(NSNumber *)numberFromString:(NSString *)string {
NSUnimplementedMethod();
return 0;
return [self _numberFromString:string error:NULL];
}
// BROKEN
@ -1478,34 +1572,44 @@ static BOOL numberIsPositive(NSNumber *number){
}
-(BOOL)getObjectValue:(id *)valuep forString:(NSString *)string range:(NSRange *)rangep error:(NSError **)errorp {
NSUnimplementedMethod();
return 0;
NSString *errorDescription = nil;
BOOL result = [self getObjectValue:valuep forString:string errorDescription:&errorDescription];
if (errorp) {
if (result) {
*errorp = nil;
} else {
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errorDescription forKey:NSUnderlyingErrorKey];
*errorp = [NSError errorWithDomain:NSCocoaErrorDomain code:2048 userInfo:userInfo];
}
}
return result;
}
-(BOOL)getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error {
// simple test of characters...
NSMutableCharacterSet *digitsAndSeparators = [[[NSCharacterSet decimalDigitCharacterSet] mutableCopy] autorelease];
NSMutableString *mutableString = [[string mutableCopy] autorelease];
unichar thousandSeparator = [_thousandSeparator characterAtIndex:0];
NSUInteger i;
[digitsAndSeparators addCharactersInString:_decimalSeparator];
[digitsAndSeparators addCharactersInString:_thousandSeparator];
for (i = 0; i < [mutableString length]; ++i) {
if (![digitsAndSeparators characterIsMember:[mutableString characterAtIndex:i]]) {
if (error != NULL)
*error = @"Invalid number";
return NO;
}
// take out commas
if ([mutableString characterAtIndex:i] == thousandSeparator)
[mutableString deleteCharactersInRange:NSMakeRange(i, 1)];
}
*object = [NSNumber numberWithFloat:[mutableString floatValue]];
return YES;
if (object) {
*object = nil;
}
NSNumber *number = [self _numberFromString:string error:error];
if (number) {
float value = [number floatValue];
if ([self maximum] && value > [[self maximum] floatValue]) {
if (error != NULL) {
*error = NSLocalizedStringFromTableInBundle(@"Number too big", nil, [NSBundle bundleForClass: [NSNumberFormatter class]], @"");
}
number = nil;
} else if ([self minimum] && value < [[self minimum] floatValue]) {
if (error != NULL) {
*error = NSLocalizedStringFromTableInBundle(@"Number too smaller", nil, [NSBundle bundleForClass: [NSNumberFormatter class]], @"");
}
number = nil;
} else {
if (object) {
*object = number;
}
}
}
return number != nil;
}
-(BOOL)isPartialStringValid:(NSString *)partialString