From 2b6fddf26c6e6dfd4f3ee3ae523686b08d670532 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 6 Jul 2011 12:42:49 +0200 Subject: [PATCH 01/17] move menu delegate logic to generic methods --- AppKit/CPMenu/CPMenu.j | 26 ++++++++++++++++++-------- AppKit/CPMenu/_CPMenuManager.j | 6 +----- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 961f2a421..4589b059e 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -711,10 +711,7 @@ var _CPMenuBarVisible = NO, if (aView && !theWindow) throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window."; - var delegate = [self delegate]; - - if ([delegate respondsToSelector:@selector(menuWillOpen:)]) - [delegate menuWillOpen:self]; + [self _menuWillOpen]; // Convert location to global coordinates if not already in them. if (aView) @@ -802,10 +799,7 @@ var _CPMenuBarVisible = NO, + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont { - var delegate = [aMenu delegate]; - - if ([delegate respondsToSelector:@selector(menuWillOpen:)]) - [delegate menuWillOpen:aMenu]; + [aMenu _menuWillOpen]; if (!aFont) aFont = [CPFont systemFontOfSize:12.0]; @@ -890,6 +884,22 @@ var _CPMenuBarVisible = NO, return _delegate; } +- (void)_menuWillOpen +{ + var delegate = [self delegate]; + + if ([delegate respondsToSelector:@selector(menuWillOpen:)]) + [delegate menuWillOpen:self]; +} + +- (void)_menuDidClose +{ + var delegate = [self delegate]; + + if ([delegate respondsToSelector:@selector(menuDidClose:)]) + [delegate menuDidClose:self]; +} + // Handling Tracking /*! Cancels tracking. diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index 1aec30b9d..93ebc0480 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -306,11 +306,7 @@ var STICKY_TIME_INTERVAL = 500, // Hide all submenus. [self showMenu:nil fromMenu:trackingMenu atPoint:nil]; - - var delegate = [trackingMenu delegate]; - - if ([delegate respondsToSelector:@selector(menuDidClose:)]) - [delegate menuDidClose:trackingMenu]; + [trackingMenu _menuDidClose]; if (_trackingCallback) _trackingCallback([self trackingMenuContainer], trackingMenu); From 0318587f80b2af8aa33c301f0e7c843013523bd5 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 6 Jul 2011 12:52:48 +0200 Subject: [PATCH 02/17] Set the title of a menu item's submenu Correspond to Cocoa's behavior by automatically having CPMenuItem set the title of it's submenu --- AppKit/CPMenuItem/CPMenuItem.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index 0cff6177a..e8e39a15f 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -496,6 +496,7 @@ CPOffState if (_submenu) { [_submenu setSupermenu:_menu]; + [_submenu setTitle:[self title]] [self setTarget:_menu]; [self setAction:@selector(submenuAction:)]; From ad30f4dcbbf28b4bf750e773d2ff083b47bf1a9c Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 6 Jul 2011 13:28:06 +0200 Subject: [PATCH 03/17] call delegate when submenu open and close --- AppKit/CPMenu/_CPMenuManager.j | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index 93ebc0480..9c7b27213 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -375,6 +375,8 @@ var STICKY_TIME_INTERVAL = 500, var count = _menuContainerStack.length, index = count; + [newMenu _menuWillOpen]; + // Hide all menus up to the base menu... while (index--) { @@ -394,6 +396,8 @@ var STICKY_TIME_INTERVAL = 500, [_CPMenuWindow poolMenuWindow:menuContainer]; [_menuContainerStack removeObjectAtIndex:index]; + + [menu _menuDidClose]; } if (!newMenu) From 73b4c33f05d9badc1b7401d3328328b265ac14df Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 7 Jul 2011 15:58:03 +0200 Subject: [PATCH 04/17] track if the mouse was released after menu open Make sure the menu isn't closed by the mouse up that is directly followed by the mouse down that opened the menu. --- AppKit/CPMenu/_CPMenuManager.j | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index 9c7b27213..57f253a65 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -11,6 +11,7 @@ var STICKY_TIME_INTERVAL = 500, @implementation _CPMenuManager: CPObject { CPTimeInterval _startTime; + BOOL _hasMouseGoneUpAfterStartedTracking; int _scrollingState; CGPoint _lastGlobalLocation; @@ -87,6 +88,8 @@ var STICKY_TIME_INTERVAL = 500, return [self trackMenuBarButtonEvent:anEvent]; } + _hasMouseGoneUpAfterStartedTracking = NO; + [self trackEvent:anEvent]; } @@ -221,8 +224,13 @@ var STICKY_TIME_INTERVAL = 500, [CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04]; } } - else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5))) - [trackingMenu cancelTracking]; + else if (type === CPLeftMouseUp) + { + if (_hasMouseGoneUpAfterStartedTracking) + [trackingMenu cancelTracking]; + else + _hasMouseGoneUpAfterStartedTracking = YES; + } } // Prevent previous selected menu items from opening by stopping the timer if a From ecb04e983ef393d82a2b2e8f943bcedd22632e0e Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 10 Jun 2011 11:23:36 -0700 Subject: [PATCH 05/17] Simple CPNumberFormatter stringFromNumber for CPNumberFormatterDecimalStyle. --- Foundation/CPNumberFormatter.j | 76 ++++++++++++++++++++++++ Tests/Foundation/CPNumberFormatterTest.j | 19 ++++++ 2 files changed, 95 insertions(+) create mode 100644 Tests/Foundation/CPNumberFormatterTest.j diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index aeb9ace71..89d46e7cc 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -24,12 +24,85 @@ @import @import +CPNumberFormatterNoStyle = 0; +CPNumberFormatterDecimalStyle = 1; +CPNumberFormatterCurrencyStyle = 2; +CPNumberFormatterPercentStyle = 3; +CPNumberFormatterScientificStyle = 4; +CPNumberFormatterSpellOutStyle = 5; + +/*! + @ingroup foundation + @class CPNumberFormatter + + CPNumberFormatter takes a numeric NSNumber value and formats it as text for + display. It also supports the converse, taking text and interpreting it as a + CPNumber by configurable formatting rules. +*/ @implementation CPNumberFormatter : CPFormatter { + CPNumberFormatterStyle _numberStyle @accessors(property=numberStyle); + CPString _perMillSymbol @accessors(property=perMillSymbol); +} + +- (CPString)stringFromNumber:(CPNumber)number +{ + // TODO Add locale support. + switch(_numberStyle) + { + case CPNumberFormatterDecimalStyle: + var dcmn = [CPDecimalNumber numberWithFloat:number], + numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; + + dcmn = [dcmn decimalNumberByRoundingAccordingToBehavior:numberHandler]; + + var output = [dcmn descriptionWithLocale:nil], + parts = [output componentsSeparatedByString:"."], // FIXME Locale specific. + preFraction = parts[0], + fraction = parts.length > 1 ? parts[1] : "", + preFractionLength = [preFraction length], + commaPosition = 3, + perMillSymbol = [self _effectivePerMillSymbol]; + + // TODO This is just a temporary solution. Should be generalised. + // Add in thousands separators. + if (perMillSymbol) + while(commaPosition < [preFraction length]) + { + preFraction = [preFraction stringByReplacingCharactersInRange:CPMakeRange(commaPosition, 0) withString:perMillSymbol]; + commaPosition += 4; + } + + if (fraction) + return preFraction + "." + fraction; + else + return preFraction; + default: + return [number description]; + } +} + +- (CPNumber)numberFromString:(CPString)string +{ + +} + + +/*! + @ignore + Return the perMillSymbol if set, otherwise the locale default. +*/ +- (CPString)_effectivePerMillSymbol +{ + if (_perMillSymbol === nil || _perMillSymbol === undefined) + return ","; // (FIXME US Locale specific.) + return _perMillSymbol; } @end +var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey"; + @implementation CPNumberFormatter (CPCoding) - (id)initWithCoder:(CPCoder)aCoder @@ -38,6 +111,7 @@ if (self) { + _numberStyle = [aCoder decodeIntForKey:CPNumberFormatterStyleKey]; } return self; @@ -46,6 +120,8 @@ - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; + + [aCoder encodeInt:_numberStyle forKey:CPNumberFormatterStyleKey]; } @end diff --git a/Tests/Foundation/CPNumberFormatterTest.j b/Tests/Foundation/CPNumberFormatterTest.j new file mode 100644 index 000000000..d9ad0b89b --- /dev/null +++ b/Tests/Foundation/CPNumberFormatterTest.j @@ -0,0 +1,19 @@ +@import + +@implementation CPNumberFormatterTest : OJTestCase +{ +} + +- (void)testDecimalStyle +{ + var numberFormatter = [[CPNumberFormatter alloc] init]; + [numberFormatter setNumberStyle:CPNumberFormatterDecimalStyle]; + var formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithInt:123]]; + [self assert:@"123" equals:formattedNumberString]; + + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:122344.4563]]; + // TODO Locale support. This test is sensitive to float precision. + [self assert:@"122,344.456" equals:formattedNumberString]; +} + +@end From 279326ffe181a2259f1c5ab26319936f07515eee Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 10 Jun 2011 11:41:23 -0700 Subject: [PATCH 06/17] CPNumberFormatter rounding mode support. --- Foundation/CPDecimal.j | 5 ++++ Foundation/CPNumberFormatter.j | 27 +++++++++++++++++++--- Tests/Foundation/CPNumberFormatterTest.j | 29 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Foundation/CPDecimal.j b/Foundation/CPDecimal.j index c0812f9f8..2c54a333e 100644 --- a/Foundation/CPDecimal.j +++ b/Foundation/CPDecimal.j @@ -72,6 +72,7 @@ CPRoundPlain = 1; CPRoundDown = 2; CPRoundUp = 3; CPRoundBankers = 4; +_CPRoundHalfDown = 5; // Private API rounding mode used by CPNumberFormatter. //Exceptions CPDecimalNumberOverflowException = @"CPDecimalNumberOverflowException"; @@ -1330,6 +1331,10 @@ function CPDecimalRound(result, dcm, scale ,roundingMode) n = result._mantissa[l]; up = (n >= 5); break; + case _CPRoundHalfDown: + n = result._mantissa[l]; + up = (n > 5); + break; case CPRoundBankers: n = result._mantissa[l]; if (n > 5) diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 89d46e7cc..806df5c04 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -23,6 +23,7 @@ @import @import +@import CPNumberFormatterNoStyle = 0; CPNumberFormatterDecimalStyle = 1; @@ -31,6 +32,14 @@ CPNumberFormatterPercentStyle = 3; CPNumberFormatterScientificStyle = 4; CPNumberFormatterSpellOutStyle = 5; +CPNumberFormatterRoundCeiling = CPRoundUp; +CPNumberFormatterRoundFloor = CPRoundDown; +CPNumberFormatterRoundDown = CPRoundDown; +CPNumberFormatterRoundUp = CPRoundUp; +CPNumberFormatterRoundHalfEven = CPRoundBankers; +CPNumberFormatterRoundHalfDown = _CPRoundHalfDown; +CPNumberFormatterRoundHalfUp = CPRoundPlain; + /*! @ingroup foundation @class CPNumberFormatter @@ -41,8 +50,19 @@ CPNumberFormatterSpellOutStyle = 5; */ @implementation CPNumberFormatter : CPFormatter { - CPNumberFormatterStyle _numberStyle @accessors(property=numberStyle); - CPString _perMillSymbol @accessors(property=perMillSymbol); + CPNumberFormatterStyle _numberStyle @accessors(property=numberStyle); + CPString _perMillSymbol @accessors(property=perMillSymbol); + CPNumberFormatterRoundingMode _roundingMode @accessors(property=roundingMode); +} + +- (id)init +{ + if (self = [super init]) + { + _roundingMode = CPNumberFormatterRoundHalfUp; + } + + return self; } - (CPString)stringFromNumber:(CPNumber)number @@ -52,7 +72,8 @@ CPNumberFormatterSpellOutStyle = 5; { case CPNumberFormatterDecimalStyle: var dcmn = [CPDecimalNumber numberWithFloat:number], - numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundPlain scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; + roundingMode = [self roundingMode], + numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; dcmn = [dcmn decimalNumberByRoundingAccordingToBehavior:numberHandler]; diff --git a/Tests/Foundation/CPNumberFormatterTest.j b/Tests/Foundation/CPNumberFormatterTest.j index d9ad0b89b..05ded5fc9 100644 --- a/Tests/Foundation/CPNumberFormatterTest.j +++ b/Tests/Foundation/CPNumberFormatterTest.j @@ -16,4 +16,33 @@ [self assert:@"122,344.456" equals:formattedNumberString]; } +- (void)testRoundingMode +{ + var numberFormatter = [[CPNumberFormatter alloc] init], + formattedNumberString; + [numberFormatter setNumberStyle:CPNumberFormatterDecimalStyle]; + + [numberFormatter setRoundingMode:CPNumberFormatterRoundUp]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5672]]; + [self assert:@"123.568" equals:formattedNumberString]; + + [numberFormatter setRoundingMode:CPNumberFormatterRoundDown]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5679]]; + [self assert:@"123.567" equals:formattedNumberString]; + + [numberFormatter setRoundingMode:CPNumberFormatterRoundHalfEven]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5675]]; + [self assert:@"123.568" equals:formattedNumberString]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5665]]; + [self assert:@"123.566" equals:formattedNumberString]; + + [numberFormatter setRoundingMode:CPNumberFormatterRoundHalfDown]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5675]]; + [self assert:@"123.567" equals:formattedNumberString]; + + [numberFormatter setRoundingMode:CPNumberFormatterRoundHalfUp]; + formattedNumberString = [numberFormatter stringFromNumber:[CPNumber numberWithFloat:123.5675]]; + [self assert:@"123.568" equals:formattedNumberString]; +} + @end From 134bfec6151eec70444bcb0c263a3d8b9181a478 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 11 Jun 2011 03:36:44 -0700 Subject: [PATCH 07/17] Temporary numberFromString:. --- Foundation/CPNumberFormatter.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 806df5c04..6628a3f5c 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -105,10 +105,10 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; - (CPNumber)numberFromString:(CPString)string { - + // TODO + return parseFloat(string); } - /*! @ignore Return the perMillSymbol if set, otherwise the locale default. From 06670f2214decd05506c802a1fef154d99994431 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 11 Jun 2011 03:59:33 -0700 Subject: [PATCH 08/17] CPFormatter support for CPControl. --- AppKit/CPControl.j | 22 +++++++++++++++++++++- Foundation/CPNumberFormatter.j | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 0df00d6c6..18afec8f6 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -89,6 +89,8 @@ var CPControlBlackColor = [CPColor blackColor]; int _sendActionOn; BOOL _sendsActionOnEndEditing @accessors(property=sendsActionOnEndEditing); + CPFormatter _formatter @accessors(property=formatter); + // Mouse Tracking Support BOOL _continuousTracking; BOOL _trackingWasWithinFrame; @@ -502,6 +504,15 @@ var CPControlBlackColor = [CPColor blackColor]; */ - (CPString)stringValue { + var formatted; + + if (_formatter) + { + formatted = [_formatter stringForObjectValue:_value]; + if (formatted !== nil && formatted !== undefined) + return formatted; + } + return (_value === undefined || _value === nil) ? "" : String(_value); } @@ -510,7 +521,16 @@ var CPControlBlackColor = [CPColor blackColor]; */ - (void)setStringValue:(CPString)anObject { - [self setObjectValue:anObject]; + var value = anObject; + + if (_formatter) + { + var formattedValue = nil; + if ([_formatter getObjectValue:@ref(formattedValue) forString:value errorDescription:NULL]) + value = formattedValue; + } + + [self setObjectValue:value]; } - (void)takeDoubleValueFrom:(id)sender diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 6628a3f5c..2e0921d4b 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -109,6 +109,27 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; return parseFloat(string); } +- (CPString)stringForObjectValue:(id)anObject +{ + if ([anObject isKindOfClass:[CPNumber class]]) + return [self stringFromNumber:anObject]; + else + return [anObject description]; +} + +- (CPString)editingStringForObjectValue:(id)anObject +{ + return [self stringForObjectValue:anObject]; +} + +- (BOOL)getObjectValue:(id)anObject forString:(CPString)aString errorDescription:(CPString)anError +{ + // TODO Error handling. + var value = [self numberFromString:aString]; + @deref(anObject, value); + return YES; +} + /*! @ignore Return the perMillSymbol if set, otherwise the locale default. From 49c29ded92aeb10c092389de9688ed9d7c6ab954 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 11 Jun 2011 03:59:52 -0700 Subject: [PATCH 09/17] Nib2cib support for formatters. --- Tools/nib2cib/NSCell.j | 3 +++ Tools/nib2cib/NSControl.j | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Tools/nib2cib/NSCell.j b/Tools/nib2cib/NSCell.j index 23bfccba5..ae8b2709f 100644 --- a/Tools/nib2cib/NSCell.j +++ b/Tools/nib2cib/NSCell.j @@ -48,6 +48,7 @@ id _objectValue @accessors(readonly, getter=objectValue); CPFont _font @accessors(readonly, getter=font); int _lineBreakMode @accessors(readonly, getter=lineBreakMode); + CPFormatter _formatter @accessors(readonly, getter=formatter); } - (id)initWithCoder:(CPCoder)aCoder @@ -78,6 +79,8 @@ _objectValue = [aCoder decodeObjectForKey:@"NSContents"]; _font = [aCoder decodeObjectForKey:@"NSSupport"]; + + _formatter = [aCoder decodeObjectForKey:@"NSFormatter"]; } return self; diff --git a/Tools/nib2cib/NSControl.j b/Tools/nib2cib/NSControl.j index 06afe13cd..a2ee25a75 100644 --- a/Tools/nib2cib/NSControl.j +++ b/Tools/nib2cib/NSControl.j @@ -54,6 +54,8 @@ [self setAction:[aCoder decodeObjectForKey:@"NSAction"]]; [self setLineBreakMode:[cell lineBreakMode]]; + + [self setFormatter:[cell formatter]]; } return self; From 110d4c478d6196bd4ccc56d88000bdc8fa317c23 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 11 Jun 2011 04:21:49 -0700 Subject: [PATCH 10/17] Fixed: pressing the up arrow key in a table view would cause a crash if the previous selection was non continuous. --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 0677dca7d..2853079a4 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -4609,7 +4609,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad } _wasSelectionBroken = true; } - else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex]))) + else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastIndex]))) { shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex]; _wasSelectionBroken = false; From 63b00186f4cfc50bba6d1e59d8dd9fc8150217c8 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 11 Jun 2011 04:43:16 -0700 Subject: [PATCH 11/17] Fixed: level indicator warning and critical level ranges should be inclusive. --- AppKit/CPLevelIndicator.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPLevelIndicator.j b/AppKit/CPLevelIndicator.j index 373ca319a..911dea311 100644 --- a/AppKit/CPLevelIndicator.j +++ b/AppKit/CPLevelIndicator.j @@ -149,9 +149,9 @@ var _CPLevelIndicatorBezelColor = nil, var filledColor = _CPLevelIndicatorSegmentNormalColor, value = [self doubleValue]; - if (value < _criticalValue) + if (value <= _criticalValue) filledColor = _CPLevelIndicatorSegmentCriticalColor; - else if (value < _warningValue) + else if (value <= _warningValue) filledColor = _CPLevelIndicatorSegmentWarningColor; for (var i = 0; i < segmentCount; i++) From 3db61216e1ff20ba322028c7e61e8463bb9026fd Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 13 Jun 2011 18:39:17 -0700 Subject: [PATCH 12/17] CPFormatter support for CPControl which actually works. --- AppKit/CPControl.j | 4 +++- Foundation/CPNumberFormatter.j | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 18afec8f6..9e655d796 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -19,6 +19,8 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#import "../Foundation/Ref.h" @import "CPFont.j" @import "CPShadow.j" @@ -526,7 +528,7 @@ var CPControlBlackColor = [CPColor blackColor]; if (_formatter) { var formattedValue = nil; - if ([_formatter getObjectValue:@ref(formattedValue) forString:value errorDescription:NULL]) + if ([_formatter getObjectValue:AT_REF(formattedValue) forString:value errorDescription:NULL]) value = formattedValue; } diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 2e0921d4b..18d70b900 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#import "Ref.h" @import @import @@ -126,7 +127,8 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; { // TODO Error handling. var value = [self numberFromString:aString]; - @deref(anObject, value); + AT_DEREF(anObject, value); + return YES; } From e848e161d4fcbfc5cb67421583e216a81aeb9413 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 13 Jun 2011 23:19:06 -0700 Subject: [PATCH 13/17] CPNumberFormatter maximum fractional digits support. Optimise by only creating CPDecimalNumberHandler when needed and caching the result. --- Foundation/CPNumberFormatter.j | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 18d70b900..174db6b39 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -26,6 +26,10 @@ @import @import +#define UPDATE_NUMBER_HANDLER_IF_NECESSARY() if (!_numberHandler) \ + _numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:_roundingMode scale:_maximumFractionalDigits raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; +#define SET_NEEDS_NUMBER_HANDLER_UPDATE() _numberHandler = nil; + CPNumberFormatterNoStyle = 0; CPNumberFormatterDecimalStyle = 1; CPNumberFormatterCurrencyStyle = 2; @@ -54,6 +58,9 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; CPNumberFormatterStyle _numberStyle @accessors(property=numberStyle); CPString _perMillSymbol @accessors(property=perMillSymbol); CPNumberFormatterRoundingMode _roundingMode @accessors(property=roundingMode); + CPUInteger _maximumFractionalDigits @accessors(property=maximalFractionalDigits); + + CPDecimalNumberHandler _numberHandler; } - (id)init @@ -72,11 +79,10 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; switch(_numberStyle) { case CPNumberFormatterDecimalStyle: - var dcmn = [CPDecimalNumber numberWithFloat:number], - roundingMode = [self roundingMode], - numberHandler = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode scale:3 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES]; + UPDATE_NUMBER_HANDLER_IF_NECESSARY(); - dcmn = [dcmn decimalNumberByRoundingAccordingToBehavior:numberHandler]; + var dcmn = [CPDecimalNumber numberWithFloat:number]; + dcmn = [dcmn decimalNumberByRoundingAccordingToBehavior:_numberHandler]; var output = [dcmn descriptionWithLocale:nil], parts = [output componentsSeparatedByString:"."], // FIXME Locale specific. @@ -143,6 +149,18 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; return _perMillSymbol; } +- (void)setRoundingMode:(CPNumberFormatterRoundingMode)aRoundingMode +{ + _roundingMode = aRoundingMode; + SET_NEEDS_NUMBER_HANDLER_UPDATE(); +} + +- (void)setMaximumFractionDigits:(CPUInteger)aNumber +{ + _maximumFractionalDigits = aNumber; + SET_NEEDS_NUMBER_HANDLER_UPDATE(); +} + @end var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey"; From a69f7dc81a62d610f1e9b78b70c39d30701d0062 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 6 Jul 2011 13:36:41 -0400 Subject: [PATCH 14/17] Test CPTextField with a formatter. --- Tests/AppKit/CPTextFieldTest.j | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Tests/AppKit/CPTextFieldTest.j b/Tests/AppKit/CPTextFieldTest.j index 65fba1642..6570c63b5 100644 --- a/Tests/AppKit/CPTextFieldTest.j +++ b/Tests/AppKit/CPTextFieldTest.j @@ -22,6 +22,31 @@ [self assert:[view valueForThemeAttribute:@"content-inset"].top equals:[decoded valueForThemeAttribute:@"content-inset"].top message:@"content-inset should unarchive correctly"]; } +- (void)testFormatters +{ + var control = [[CPTextField alloc] initWithFrame:CGRectMakeZero()], + numberFormatter = [[CPNumberFormatter alloc] init]; + + [numberFormatter setNumberStyle:CPNumberFormatterDecimalStyle]; + [numberFormatter setMaximumFractionDigits:3]; + + [control setFormatter:numberFormatter]; + [control setStringValue:@"12.3456"]; + [self assert:[CPNumber class] equals:[[control objectValue] class] message:@"object should be a number"]; + // Note that the control stores the value with a different precision than the maximum fraction + // digits of the number formatter. It's a little surprising but this makes the implementation easier + // and Cocoa does it too. + [self assert:[CPNumber numberWithFloat:12.3456] equals:[control objectValue]]; + [self assert:"12.346" equals:[control stringValue]]; + + [control setFloatValue:45.3456]; + [self assertTrue:"45.346" === [control stringValue]]; + + [control setFormatter:nil]; + [control setStringValue:@"12"]; + [self assert:@"12" equals:[control objectValue]]; +} + @end @implementation CPTextFieldSubclass : CPTextField From 51585402087a3c1d313ed349077664bb6609d45a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 6 Jul 2011 14:08:44 -0400 Subject: [PATCH 15/17] Fixed: initialise CPNumberFormatter maximumFractionalDigits to 3. --- Foundation/CPNumberFormatter.j | 1 + 1 file changed, 1 insertion(+) diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 174db6b39..fda0ba00a 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -68,6 +68,7 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; if (self = [super init]) { _roundingMode = CPNumberFormatterRoundHalfUp; + _maximumFractionalDigits = 3; } return self; From 63d208bf20f7c09c40682f9f1809a2f49645be89 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 7 Jul 2011 18:33:00 +0200 Subject: [PATCH 16/17] never return a separator as the highlighted item --- AppKit/CPMenu/CPMenu.j | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 4589b059e..3816b7e50 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -869,7 +869,15 @@ var _CPMenuBarVisible = NO, */ - (CPMenuItem)highlightedItem { - return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil; + if (_highlightedIndex <= 0) + return nil; + + var highlightedItem = _items[_highlightedIndex]; + + if ([highlightedItem isSeparatorItem]) + return nil; + + return highlightedItem; } // Managing the Delegate From 4719578f107e147f324a2df7a8ba872eed4cad56 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 7 Jul 2011 20:40:22 +0200 Subject: [PATCH 17/17] fix 0 is a valid highlighted index --- AppKit/CPMenu/CPMenu.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 3816b7e50..cf9eb933a 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -869,7 +869,7 @@ var _CPMenuBarVisible = NO, */ - (CPMenuItem)highlightedItem { - if (_highlightedIndex <= 0) + if (_highlightedIndex < 0) return nil; var highlightedItem = _items[_highlightedIndex];