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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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]; From 918f6fbb8f6de92550e9940f21df377fadc0aa02 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 9 Jul 2011 16:25:53 -0700 Subject: [PATCH 18/19] CPFormatter support, bug fixes... - Test application. CPControl --------- - Moved _formatter declaration up next to value, it was in the Target-Action Support section before. - sendAction:to: should return a BOOL. - Support for CPFormatter -editingStringForObjectValue. - If a nil string is passed to -setStringValue in Cocoa, it raises an invalid parameter assertion and does nothing. - Per Cocoa, if setting a string value fails, it tries again with an empty string. - Removed a few extra blank lines. - Changed NULL to nil. CPTextField ----------- - The string value is now cached in _stringValue to avoid constant calls to the formatter. - There were several places where references to _inputElement were not wrapped with #if PLATFORM(DOM). - When resigning first responder, if there is a formatter and formatting fails, reject the resignation and keep focus. Also, if the delegate responds to control:didFailToFormatString:errorDescription:, invoke it. - _willBecomeFirstResponderByClick was not being set to NO when resigning. As a result, if you clicked in a field, tabbed to another field, and tabbed back to the original field, it would not select the text because it thought there was a mouse click. - Don't send _sendStringValue: in keyUp: if the value has not changed. Previously it would do that for non-printing keys like navigation keys. - insertNewLine: validates the string the same way resigning does. - insertNewLine: would not send textDidEndEditing: if the field had no action, but it should. - insertNewLine: should select all text (per Cocoa). - insertNewLineIgnoringFieldEditor: and insertTabIgnoringFieldEditor: were not replacing the selection, Cocoa docs say they should. - Per Cocoa, when setting an object value and there is a formatter, the value is first formatted as a string. If that fails, an object value for an empty string is attempted. CPFormatter ----------- - Fixed up the docs to match the method signatures. - Indicated with "Ref" in argument types if the argument is pass by reference. - isPartialStringValid:newEditingString:errorDescription: has a default implementation in Cocoa that nils the return values and returns YES. - Fixed the name of isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: - isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: has a default implementation in Cocoa that invokes isPartialStringValid:newEditingString:errorDescription: --- AppKit/CPControl.j | 51 +- AppKit/CPTextField.j | 237 ++- Foundation/CPFormatter.j | 66 +- Tests/Manual/CPFormatterTest/AppController.j | 205 +++ Tests/Manual/CPFormatterTest/DateFormatter.j | 125 ++ Tests/Manual/CPFormatterTest/Info.plist | 10 + Tests/Manual/CPFormatterTest/Jakefile | 94 ++ .../CPFormatterTest/Resources/MainMenu.cib | 1 + .../CPFormatterTest/Resources/MainMenu.xib | 1435 +++++++++++++++++ .../Resources/date-functions.js | 471 ++++++ .../CPFormatterTest/Resources/spinner.gif | Bin 0 -> 1849 bytes Tests/Manual/CPFormatterTest/index-debug.html | 105 ++ Tests/Manual/CPFormatterTest/index.html | 79 + Tests/Manual/CPFormatterTest/main.j | 23 + 14 files changed, 2789 insertions(+), 113 deletions(-) create mode 100644 Tests/Manual/CPFormatterTest/AppController.j create mode 100644 Tests/Manual/CPFormatterTest/DateFormatter.j create mode 100644 Tests/Manual/CPFormatterTest/Info.plist create mode 100644 Tests/Manual/CPFormatterTest/Jakefile create mode 100644 Tests/Manual/CPFormatterTest/Resources/MainMenu.cib create mode 100644 Tests/Manual/CPFormatterTest/Resources/MainMenu.xib create mode 100644 Tests/Manual/CPFormatterTest/Resources/date-functions.js create mode 100644 Tests/Manual/CPFormatterTest/Resources/spinner.gif create mode 100644 Tests/Manual/CPFormatterTest/index-debug.html create mode 100644 Tests/Manual/CPFormatterTest/index.html create mode 100644 Tests/Manual/CPFormatterTest/main.j diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 9e655d796..1d2a567f3 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -19,9 +19,10 @@ * 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 "../Foundation/CPFormatter.j" @import "CPFont.j" @import "CPShadow.j" @import "CPView.j" @@ -84,6 +85,7 @@ var CPControlBlackColor = [CPColor blackColor]; @implementation CPControl : CPView { id _value; + CPFormatter _formatter @accessors(property=formatter); // Target-Action Support id _target; @@ -91,8 +93,6 @@ var CPControlBlackColor = [CPColor blackColor]; int _sendActionOn; BOOL _sendsActionOnEndEditing @accessors(property=sendsActionOnEndEditing); - CPFormatter _formatter @accessors(property=formatter); - // Mouse Tracking Support BOOL _continuousTracking; BOOL _trackingWasWithinFrame; @@ -225,10 +225,11 @@ var CPControlBlackColor = [CPColor blackColor]; @param anAction the action to send @param anObject the object to which the action will be sent */ -- (void)sendAction:(SEL)anAction to:(id)anObject +- (BOOL)sendAction:(SEL)anAction to:(id)anObject { [self _reverseSetBinding]; - [CPApp sendAction:anAction to:anObject from:self]; + + return [CPApp sendAction:anAction to:anObject from:self]; } - (int)sendActionOn:(int)mask @@ -506,13 +507,12 @@ var CPControlBlackColor = [CPColor blackColor]; */ - (CPString)stringValue { - var formatted; - - if (_formatter) + if (_formatter && _value !== undefined && _value !== nil) { - formatted = [_formatter stringForObjectValue:_value]; - if (formatted !== nil && formatted !== undefined) - return formatted; + var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value]; + + if (formattedValue !== nil && formattedValue !== undefined) + return formattedValue; } return (_value === undefined || _value === nil) ? "" : String(_value); @@ -521,16 +521,30 @@ var CPControlBlackColor = [CPColor blackColor]; /*! Sets the receiver's string value. */ -- (void)setStringValue:(CPString)anObject +- (void)setStringValue:(CPString)aString { - var value = anObject; + // Cocoa raises an invalid parameter assertion and returns if you pass nil. + if (aString === nil || aString === undefined) + { + CPLog.warn("nil sent to CPControl -setStringValue"); + return; + } + + var value; if (_formatter) { - var formattedValue = nil; - if ([_formatter getObjectValue:AT_REF(formattedValue) forString:value errorDescription:NULL]) - value = formattedValue; + value = nil; + + if ([_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil] === NO) + { + // If the given string is non-empty and doesn't work, Cocoa tries an empty string. + if (!aString || [_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO) + value = undefined; // Means the value is invalid + } } + else + value = aString; [self setObjectValue:value]; } @@ -548,21 +562,18 @@ var CPControlBlackColor = [CPColor blackColor]; [self setFloatValue:[sender floatValue]]; } - - (void)takeIntegerValueFrom:(id)sender { if ([sender respondsToSelector:@selector(integerValue)]) [self setIntegerValue:[sender integerValue]]; } - - (void)takeIntValueFrom:(id)sender { if ([sender respondsToSelector:@selector(intValue)]) [self setIntValue:[sender intValue]]; } - - (void)takeObjectValueFrom:(id)sender { if ([sender respondsToSelector:@selector(objectValue)]) @@ -904,7 +915,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey"; if (_target !== nil) [aCoder encodeConditionalObject:_target forKey:CPControlTargetKey]; - if (_action !== NULL) + if (_action !== nil) [aCoder encodeObject:_action forKey:CPControlActionKey]; [aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey]; diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index eee5dfd95..e7831c138 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -21,6 +21,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#import "../Foundation/Ref.h" + @import "CPControl.j" @import "CPStringDrawing.j" @import "CPCompatibility.j" @@ -83,12 +85,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPColor _textFieldBackgroundColor; - id _placeholderString; + CPString _placeholderString; + CPString _stringValue; id _delegate; - CPString _textDidChangeValue; - // NS-style Display Properties CPTextFieldBezelStyle _bezelStyle; BOOL _isBordered; @@ -481,17 +482,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self setNeedsLayout]; _isEditing = NO; + _stringValue = [self stringValue]; #if PLATFORM(DOM) - var string = [self stringValue], - element = [self _inputElement], + var element = [self _inputElement], font = [self currentValueForThemeAttribute:@"font"]; // generate the font metric [font _getMetrics]; - element.value = string; + element.value = _stringValue; element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString]; element.style.font = [font cssString]; element.style.zIndex = 1000; @@ -548,8 +549,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPTextFieldInputOwner = self; }, 0.0); - element.value = [self stringValue]; - [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; CPTextFieldInputIsActive = YES; @@ -572,17 +571,33 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { [self unsetThemeState:CPThemeStateEditing]; +#if PLATFORM(DOM) + + var element = [self _inputElement], + error = @""; + + // If there is a formatter, always give it a chance to reject the resignation, + // even if the value has not changed. + if ([self _valueIsValid:element.value] === NO) + { + [self setThemeState:CPThemeStateEditing]; + element.focus(); + return NO; + } + +#endif + + // Cache the formatted string + _stringValue = [self stringValue]; + + _willBecomeFirstResponderByClick = NO; + [self _updatePlaceholderState]; [self setNeedsLayout]; #if PLATFORM(DOM) - var element = [self _inputElement]; - - if ([self stringValue] !== element.value) - [self _setStringValue:element.value]; - CPTextFieldInputResigning = YES; if (CPTextFieldInputIsActive) @@ -610,7 +625,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); #endif - //post CPControlTextDidEndEditingNotification + // post CPControlTextDidEndEditingNotification if (_isEditing) { _isEditing = NO; @@ -625,6 +640,28 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); return YES; } +- (BOOL)_valueIsValid:(CPString)aValue +{ +#if PLATFORM(DOM) + + var error = @""; + + if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO) + { + var acceptInvalidValue = NO; + + if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)]) + acceptInvalidValue = [_delegate control:self didFailToFormatString:[self _inputElement] errorDescription:error]; + + if (acceptInvalidValue === NO) + return NO; + } + +#endif + + return YES; +} + /*! Text fields require panels to become key window, so this returns \c YES. */ @@ -685,11 +722,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)keyUp:(CPEvent)anEvent { - var oldValue = [self stringValue]; - [self _setStringValue:[self _inputElement].value]; +#if PLATFORM(DOM) - if (oldValue !== [self stringValue]) + var newValue = [self _inputElement].value; + + if (newValue !== _stringValue) { + [self _setStringValue:newValue]; + if (!_isEditing) { _isEditing = YES; @@ -699,6 +739,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]]; } +#endif + [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; } @@ -735,45 +777,46 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)insertNewline:(id)sender { - if (_isEditing) + if ([self _valueIsValid:_stringValue]) { - _isEditing = NO; - [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]]; - } + if (![self action] || [self sendAction:[self action] to:[self target]]) + { + if (_isEditing) + { + _isEditing = NO; + [self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]]; + } - [self sendAction:[self action] to:[self target]]; - [self selectText:nil]; + [self selectAll:nil]; + } + } [[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; } - (void)insertNewlineIgnoringFieldEditor:(id)sender { - var oldValue = [self stringValue]; - - [self _inputElement].value += CPNewlineCharacter; - [self _setStringValue:[self _inputElement].value]; - - if (oldValue !== [self stringValue]) - { - if (!_isEditing) - { - _isEditing = YES; - [self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]]; - } - - [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]]; - } + [self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter]; } - (void)insertTabIgnoringFieldEditor:(id)sender { - var oldValue = [self stringValue]; + [self _insertCharacterIgnoringFieldEditor:CPTabCharacter]; +} - [self _inputElement].value += CPTabCharacter; - [self _setStringValue:[self _inputElement].value]; +- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter +{ +#if PLATFORM(DOM) - if (oldValue !== [self stringValue]) + var oldValue = _stringValue, + range = [self selectedRange], + element = [self _inputElement]; + + element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter]; + [self _setStringValue:element.value]; + + // NOTE: _stringValue is now the current input element value + if (oldValue !== _stringValue) { if (!_isEditing) { @@ -783,6 +826,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]]; } + +#endif } - (void)textDidBlur:(CPNotification)note @@ -813,15 +858,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [super textDidChange:note]; } -- (void)sendAction:(SEL)anAction to:(id)anObject -{ - [self _reverseSetBinding]; - - [CPApp sendAction:anAction to:anObject from:self]; -} - /*! - Returns the string the text field. + Returns the string in the text field. */ - (id)objectValue { @@ -830,24 +868,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); /* @ignore - Sets the internal string value without updating the value in the input element + Sets the internal string value without updating the value in the input element. + This should only be invoked when the underlying text element's value has changed. */ -- (void)_setStringValue:(id)aValue +- (BOOL)_setStringValue:(CPString)aValue { - [self willChangeValueForKey:@"objectValue"]; - [super setObjectValue:String(aValue)]; - [self _updatePlaceholderState]; - [self didChangeValueForKey:@"objectValue"]; + return [self _setStringValue:aValue isNewValue:YES errorDescription:nil]; +} + +/* + @ignore + Sets the internal string value without updating the value in the input element. + If there is a formatter and formatting fails, returns NO. Otherwise returns YES. +*/ +- (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError +{ + _stringValue = aValue; + + var objectValue = aValue, + formatter = [self formatter], + result = YES; + + if (formatter) + { + var object = nil; + + if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError]) + objectValue = object; + else + { + objectValue = undefined; // Mark the value as invalid + result = NO; + } + + isNewValue |= objectValue !== [super objectValue]; + } + + if (isNewValue) + { + [self willChangeValueForKey:@"objectValue"]; + [super setObjectValue:objectValue]; + [self _updatePlaceholderState]; + [self didChangeValueForKey:@"objectValue"]; + } + + return result; } - (void)setObjectValue:(id)aValue { [super setObjectValue:aValue]; + var formatter = [self formatter]; + + if (formatter) + { + // If there is a formatter, make sure the object value can be formatted successfully + var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue]; + + if (formattedString === nil) + { + var value = nil; + + // Formatting failed, get an "empty" object by formatting an empty string. + // If that fails, the value is undefined. + if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO) + value = undefined; + + [super setObjectValue:value]; + } + } + + _stringValue = [self stringValue]; + #if PLATFORM(DOM) if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self) - [self _inputElement].value = aValue; + [self _inputElement].value = _stringValue; + #endif [self _updatePlaceholderState]; @@ -855,9 +953,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)_updatePlaceholderState { - var string = [self stringValue]; - - if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing]) + if ((!_stringValue || _stringValue.length === 0) && ![self hasThemeState:CPThemeStateEditing]) [self setThemeState:CPTextFieldStatePlaceholder]; else [self unsetThemeState:CPTextFieldStatePlaceholder]; @@ -923,7 +1019,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); minSize = [self currentValueForThemeAttribute:@"min-size"], maxSize = [self currentValueForThemeAttribute:@"max-size"], lineBreakMode = [self lineBreakMode], - text = ([self stringValue] || @" "), + text = (_stringValue || @" "), textSize = _CGSizeMakeCopy(frameSize), font = [self currentValueForThemeAttribute:@"font"]; @@ -994,8 +1090,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); return; var pasteboard = [CPPasteboard generalPasteboard], - stringValue = [self stringValue], - stringForPasting = [stringValue substringWithRange:selectedRange]; + stringForPasting = [_stringValue substringWithRange:selectedRange]; [pasteboard declareTypes:[CPStringPboardType] owner:nil]; [pasteboard setString:stringForPasting forType:CPStringPboardType]; @@ -1025,9 +1120,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self deleteBackward:sender]; var selectedRange = [self selectedRange], - stringValue = [self stringValue], pasteString = [pasteboard stringForType:CPStringPboardType], - newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; + newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; [self setStringValue:newValue]; [self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)]; @@ -1041,6 +1135,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); if ([[self window] firstResponder] !== self) return CPMakeRange(0, 0); +#if PLATFORM(DOM) + // we wrap this in try catch because firefox will throw an exception in certain instances try { @@ -1067,6 +1163,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); // fall through to the return } +#endif + return CPMakeRange(0, 0); } @@ -1075,6 +1173,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); if (![[self window] firstResponder] === self) return; +#if PLATFORM(DOM) + var inputElement = [self _inputElement]; try @@ -1103,6 +1203,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); catch (e) { } + +#endif } - (void)selectAll:(id)sender @@ -1120,8 +1222,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); selectedRange.location += 1; selectedRange.length -= 1; - var stringValue = [self stringValue], - newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""]; + var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""]; [self setStringValue:newValue]; [self setSelectedRange:CPMakeRange(selectedRange.location, 0)]; @@ -1274,7 +1375,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); string = [self placeholderString]; else { - string = [self stringValue]; + string = _stringValue; if ([self isSecure]) string = secureStringForString(string); diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j index e74b0058c..d7cc4b11e 100644 --- a/Foundation/CPFormatter.j +++ b/Foundation/CPFormatter.j @@ -33,6 +33,8 @@ make sure that you cannot configure the public subclasses CPDateFormatter and CPNumberFormatter to satisfy your requirements. */ +#import "Ref.h" + @import "CPException.j" @import "CPObject.j" @@ -80,19 +82,19 @@ /*! The default implementation of this method raises an exception. - When implementing a subclass, return by reference the object anObject after creating it from string. - Return YES if the conversion is successful. If you return NO, also return by indirection (in error) + When implementing a subclass, return by reference the object anObject after creating it from aString. + Return \c YES if the conversion is successful. If you return \c NO, also return by reference (in anError) a localized user-presentable CPString object that explains the reason why the conversion failed; the delegate - (if any) of the CPControl object managing the cell can then respond to the failure in - control:didFailToFormatString:errorDescription:. However, if error is nil, the sender is not interested in + (if any) of the CPControl object can then respond to the failure in + control:didFailToFormatString:errorDescription:. However, if anError is nil, the sender is not interested in the error description, and you should not attempt to assign one. @param anObject if conversion is successful, upon return contains the object created from the string @param aString the string to parse. @param anError if non-nil, if there is an error during the conversion, upon return contains an CPString object that describes the problem. - @return BOOL YES if the conversion from the string to a view content object was successful, otherwise NO. + @return BOOL \c YES if the conversion from the string to a view content object was successful, otherwise \c NO. */ -- (BOOL)getObjectValue:(id)anObject forString:(CPString)aString errorDescription:(CPString)anError +- (BOOL)getObjectValue:(idRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError { _CPRaiseInvalidAbstractInvocation(self, _cmd); return NO; @@ -104,11 +106,11 @@ This method is invoked each time the user presses a key while the cell has the keyboard focus it lets you verify and edit the cell text as the user types it. - In a subclass implementation, evaluate partialString according to the context, edit the text if necessary, and return - by reference any edited string in newString. Return YES if partialString is acceptable and NO if partialString is unacceptable. - If you return NO and newString is nil, the cell displays partialString minus the last character typed. If you return NO, you can - also return by indirection an CPString object (in error) that explains the reason why the validation failed; the delegate (if any) - of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. + In a subclass implementation, evaluate aPartialString according to the context, edit the text if necessary, and return + by reference any edited string in aNewString. Return \c YES if aPartialString is acceptable and \c NO if aPartialString is unacceptable. + If you return \c NO and aNewString is nil, the control displays aPartialString minus the last character typed. If you return \c NO, you can + also return by reference a CPString object (in anError) that explains the reason why the validation failed; the delegate (if any) + of the CPControl can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. The selection range will always be set to the end of the text if replacement occurs. This method is a compatibility method. If a subclass overrides this method and does not override @@ -118,12 +120,16 @@ @param aPartialString the text currently in the view. @param aNewString if aPartialString needs to be modified, upon return contains the replacement string. @param anError if non-nil, if validation fails contains a CPString object that describes the problem. - @return YES if aPartialString is an acceptable value, otherwise NO. + @return \c YES if aPartialString is an acceptable value, otherwise \c NO. */ -- (BOOL)isPartialStringValid:(CPString)aPartialString newEditingString:(CPString)aNewString errorDescription:(CPString)anError +- (BOOL)isPartialStringValid:(CPString)aPartialString newEditingString:(CPStringRef)aNewString errorDescription:(CPStringRef)anError { - _CPRaiseInvalidAbstractInvocation(self, _cmd); - return NO; + AT_DEREF(aPartialString, nil); + + if (anError) + AT_DEREF(anError, nil); + + return YES; } /*! @@ -131,24 +137,35 @@ not necessarily at the end of the string, and preserve the selection (or set a different one, such as selecting the erroneous part of the string the user has typed). - In a subclass implementation, evaluate partialString according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr - is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and - change the selection range. If you return NO, you can also return by indirection an CPString object (in error) that explains the reason why the - validation failed; the delegate (if any) of the CPControl object managing the cell can then respond to the failure in + In a subclass implementation, evaluate aPartialString according to the context. Return \c YES if aPartialString is acceptable and \c NO if aPartialString + is unacceptable. Assign a new string by reference to aPartialString and a new range by reference to aProposedSelectedRange and return \c NO if you want to replace the string and + change the selection range. If you return \c NO, you can also return by reference a CPString object (in anError) that explains the reason why the + validation failed; the delegate (if any) of the CPControl can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. @param aPartialString The new string to validate. @param aProposedSelectedRange The selection range that will be used if the string is accepted or replaced. @param originalString The original string, before the proposed change. @param originalSelectedRange The selection range over which the change is to take place. - @param error If non-nil, if validation fails contains an CPString object that describes the problem. - @return YES if aPartialString is acceptable, otherwise NO. + @param anError If non-nil, if validation fails contains an CPString object that describes the problem. + @return \c YES if aPartialString is acceptable, otherwise \c NO. */ -- (BOOL)isPartialStringValue:(CPString)aPartialString proposedSelectedRange:(CPRange)aProposedSelectedRange originalString:(CPString)originalString originalSelectedRange:(CPRange)originalSelectedRange errorDescription:(CPString)anError +- (BOOL)isPartialStringValid:(CPStringRef)aPartialString proposedSelectedRange:(CPRangeRef)aProposedSelectedRange originalString:(CPString)originalString originalSelectedRange:(CPRange)originalSelectedRange errorDescription:(CPStringRef)anError { - _CPRaiseInvalidAbstractInvocation(self, _cmd); - return NO; + var newString = nil, + valid = [self isPartialStringValid:aPartialString newEditingString:AT_REF(newString) errorDescription:anError]; + + if (!valid) + { + AT_DEREF(aPartialString, newString); + + // If a new string is passed back, the selection is always put at the end + if (newString !== nil) + AT_DEREF(aProposedSelectedRange, CPMakeRange(newString.length, 0)); + } + + return valid; } - (id)initWithCoder:(CPCoder)aCoder @@ -158,7 +175,6 @@ - (void)encodeWithCoder:(CPCoder)aCoder { - } @end diff --git a/Tests/Manual/CPFormatterTest/AppController.j b/Tests/Manual/CPFormatterTest/AppController.j new file mode 100644 index 000000000..8fcae1407 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/AppController.j @@ -0,0 +1,205 @@ +/* + * AppController.j + * CPFormatterTest + * + * Created by aparajita on June 30, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +@import +@import "DateFormatter.j" + +var RecordData = [ + {name:"Tom", age:34}, + {name:"Dick", age:27}, + {name:"Harry", age:50} + ]; + +var randomFromTo = function(from, to) +{ + return Math.floor(Math.random() * (to - from + 1) + from); +}; + +@implementation AppController : CPObject +{ + CPWindow theWindow; + CPTextField dateField1; + CPTextField dateField2; + CPTextField error1; + CPTextField textField; + CPTextField error2; + CPTextField recordField; + CPPopUpButton recordMenu; +} + +- (void)awakeFromCib +{ + [theWindow setInitialFirstResponder:dateField1]; + [dateField1 setFormatter:[DateFormatter formatterWithDisplayFormat:@"D M jS, Y" editingFormat:@"m/j/Y" emptyIsValid:NO]]; + [dateField2 setFormatter:[DateFormatter formatterWithDisplayFormat:@"m-d-Y" editingFormat:@"m-d-Y" emptyIsValid:YES]]; + [dateField2 setDelegate:self]; + + [[CPNotificationCenter defaultCenter] addObserver:self + selector:@selector(resetErrorMessage:) + name:CPTextFieldDidFocusNotification + object:nil]; + + [textField setFormatter:[TextFormatter new]]; + [textField setDelegate:self]; + + [error1 setStringValue:@""]; + [error2 setStringValue:@""]; + + [recordField setFormatter:[ContactFormatter new]]; + [recordField setObjectValue:RecordData[0]]; +} + +- (void)selectRecord:(id)sender +{ + var record = RecordData[[sender selectedIndex]]; + + [recordField setObjectValue:record]; +} + +- (void)setDate1:(id)sender +{ + [self setDate:dateField1]; +} + +- (void)setDate2:(id)sender +{ + [self setDate:dateField2]; +} + +- (void)setDate:(CPTextField)field +{ + var date = new Date(randomFromTo(1931, 2012), randomFromTo(0, 11), randomFromTo(1, 31)); + + [field setObjectValue:date]; +} + +- (void)objectValue1:(id)sender +{ + CPLog.info("Date 1: %s", [[dateField1 objectValue] description]); +} + +- (void)objectValue2:(id)sender +{ + CPLog.info("Date 2: %s", [[dateField2 objectValue] description]); +} + +- (void)setNil:(id)sender +{ + [dateField1 setStringValue:nil]; // should log a warning and do nothing +} + +- (void)setEmptyOK:(id)sender +{ + [[dateField2 formatter] setEmptyIsValid:[sender state] === CPOnState]; +} + +- (void)controlTextDidChange:(CPNotification)aNotification +{ + var field = [aNotification object], + error; + + if (field === dateField2) + error = error1; + else if (field === textField) + error = error2; + + [error setStringValue:@""]; +} + +- (BOOL)control:(CPControl)aControl didFailToFormatString:(CPString)aString errorDescription:(CPString)anError +{ + CPLog.info("control:didFailToFormatString:%s errorDescription:%s", aString, anError); + + if (anError) + { + var error; + + if (aControl === dateField2) + error = error1; + else if (aControl === textField) + error = error2; + + [error setStringValue:anError]; + } + + return NO; +} + +- (void)resetErrorMessage:(CPNotification)aNotification +{ + [error2 setStringValue:@""]; +} + +@end + + +@implementation TextFormatter : CPFormatter + +- (CPString)stringForObjectValue:(id)anObject +{ + var result; + + if ([anObject isKindOfClass:[CPString class]]) + result = [self errorDescriptionForString:anObject] === nil ? anObject : nil; + else + result = nil; + + console.log("stringForObjectValue:%s ==> %s", [anObject description], result); + return result; +} + +- (BOOL)getObjectValue:(CPStringRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError +{ + var error = [self errorDescriptionForString:aString]; + + if (error) + { + anObject(nil); + + if (anError) + anError(error); + } + else + anObject(aString); + + result = error === nil; + + console.log("getObjectValue:forString:%s ==> %s", aString, result); + return result; +} + +- (CPString)errorDescriptionForString:(CPString)aString +{ + if (aString.length > 7) + return @"Maximum length is 7 characters."; + else if (!/^[a-zA-Z0-9]*$/.test(aString)) + return @"Invalid characters in string."; + else + return nil; +} + +@end + + +@implementation ContactFormatter : CPFormatter + +- (CPString)stringForObjectValue:(id)anObject +{ + if (anObject && typeof(anObject) === "object" && anObject.hasOwnProperty("name")) + return [CPString stringWithFormat:@"%s (age %d)", anObject.name, anObject.age]; + else + return nil; +} + +- (BOOL)getObjectValue:(CPStringRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError +{ + // We don't support reverse conversion + return NO; +} + +@end diff --git a/Tests/Manual/CPFormatterTest/DateFormatter.j b/Tests/Manual/CPFormatterTest/DateFormatter.j new file mode 100644 index 000000000..6b90d364a --- /dev/null +++ b/Tests/Manual/CPFormatterTest/DateFormatter.j @@ -0,0 +1,125 @@ +/* + * AppController.j + * CPFormatterTest + * + * Created by aparajita on July 6, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +@import + + +@implementation DateFormatter : CPFormatter +{ + CPString displayFormat; + CPString editingFormat; + BOOL emptyIsValid @accessors(getter=isEmptyValid); +} + ++ (DateFormatter)formatterWithDisplayFormat:(CPString)aDisplayFormat editingFormat:(CPString)anEditingFormat emptyIsValid:(BOOL)emptyValid +{ + return [[self alloc] initWithDisplayFormat:aDisplayFormat editingFormat:anEditingFormat emptyIsValid:emptyValid]; +} + +- (id)initWithDisplayFormat:(CPString)aDisplayFormat editingFormat:(CPString)anEditingFormat emptyIsValid:(BOOL)emptyValid +{ + self = [super init]; + + if (self) + { + displayFormat = aDisplayFormat; + editingFormat = anEditingFormat; + emptyIsValid = emptyValid; + } + + return self; +} + +- (CPString)stringForObjectValue:(id)anObject +{ + var result; + + if ([anObject isKindOfClass:[CPDate class]]) + result = anObject.dateFormat(displayFormat); + else + result = nil; + + console.log("stringForObjectValue:%s ==> %s", [anObject description], result); + return result; +} + +- (CPString)editingStringForObjectValue:(id)anObject +{ + var result; + + if ([anObject isKindOfClass:[CPDate class]]) + result = anObject.dateFormat(editingFormat); + else + result = nil; + + console.log("editingStringForObjectValue:%s ==> %s", [anObject description], result); + return result; +} + +- (BOOL)getObjectValue:(CPStringRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError +{ + var result; + + if (anError) + anError(nil); + + if (aString.length === 0) + { + anObject(nil); + result = emptyIsValid; + + if (anError) + anError(@"Please enter a date."); + } + else + { + var date = Date.parseDate(aString, editingFormat); + + anObject(date); + + if (date === nil && anError) + anError(@"Invalid date format."); + + result = date !== nil; + } + + console.log("getObjectValue:forString:%s ==> %s", aString, result); + return result; +} + +@end + +var DateFormatterDisplayFormatKey = @"DateFormatterDisplayFormatKey", + DateFormatterEditingFormatKey = @"DateFormatterEditingFormatKey", + DateFormatterEmptyIsValidKey = @"DateFormatterEmptyIsValidKey"; + +@implementation DateFormatter (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super initWithCoder:aCoder]; + + if (self) + { + displayFormat = [aCoder decodeObjectForKey:DateFormatterDisplayFormatKey]; + editingFormat = [aCoder decodeObjectForKey:DateFormatterEditingFormatKey]; + emptyIsValid = [aCoder decodeObjectForKey:DateFormatterEmptyIsValidKey]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [super encodeWithCoder:aCoder]; + [aCoder encodeObject:displayFormat forKey:DateFormatterDisplayFormatKey]; + [aCoder encodeObject:editingFormat forKey:DateFormatterEditingFormatKey]; + [aCoder encodeObject:emptyIsValid forKey:DateFormatterEmptyIsValidKey]; +} + +@end diff --git a/Tests/Manual/CPFormatterTest/Info.plist b/Tests/Manual/CPFormatterTest/Info.plist new file mode 100644 index 000000000..813950e7e --- /dev/null +++ b/Tests/Manual/CPFormatterTest/Info.plist @@ -0,0 +1,10 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + CPFormatterTest + + diff --git a/Tests/Manual/CPFormatterTest/Jakefile b/Tests/Manual/CPFormatterTest/Jakefile new file mode 100644 index 000000000..4b4864d37 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/Jakefile @@ -0,0 +1,94 @@ +/* + * Jakefile + * CPFormatterTest + * + * Created by aparajita on June 30, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"); + +app ("CPFormatterTest", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "CPFormatterTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPFormatterTest"); + task.setIdentifier("com.aparajita.CPFormatterTest"); + task.setVersion("1.0"); + task.setAuthor("Victory-Heart Productions"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPFormatterTest"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + task.setNib2CibFlags("-R Resources/"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["CPFormatterTest"], function() +{ + printResults(configuration); +}); + +task ("build", ["default"]); + +task ("debug", function() +{ + ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", "CPFormatterTest", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "CPFormatterTest", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "CPFormatterTest")); + OS.system(["press", "-f", FILE.join("Build", "Release", "CPFormatterTest"), FILE.join("Build", "Deployment", "CPFormatterTest")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "CPFormatterTest")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPFormatterTest"), FILE.join("Build", "Desktop", "CPFormatterTest", "CPFormatterTest.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "CPFormatterTest", "CPFormatterTest.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPFormatterTest")); + print("----------------------------"); +} diff --git a/Tests/Manual/CPFormatterTest/Resources/MainMenu.cib b/Tests/Manual/CPFormatterTest/Resources/MainMenu.cib new file mode 100644 index 000000000..76de15636 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/Resources/MainMenu.cib @@ -0,0 +1 @@ +280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;4E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;7E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;9E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;10E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;11E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;12E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;13E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;16E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;18E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;54E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;55E;D;K;6;CP$UIDd;2;56E;D;K;6;CP$UIDd;2;57E;D;K;6;CP$UIDd;2;58E;D;K;6;CP$UIDd;2;59E;D;K;6;CP$UIDd;2;60E;D;K;6;CP$UIDd;2;61E;D;K;6;CP$UIDd;2;62E;D;K;6;CP$UIDd;2;63E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;D;K;6;CP$UIDd;2;66E;D;K;6;CP$UIDd;2;67E;D;K;6;CP$UIDd;2;68E;D;K;6;CP$UIDd;2;69E;D;K;6;CP$UIDd;2;70E;D;K;6;CP$UIDd;2;71E;D;K;6;CP$UIDd;2;72E;D;K;6;CP$UIDd;2;73E;D;K;6;CP$UIDd;2;74E;D;K;6;CP$UIDd;2;75E;D;K;6;CP$UIDd;2;76E;D;K;6;CP$UIDd;2;77E;D;K;6;CP$UIDd;2;78E;D;K;6;CP$UIDd;2;79E;D;K;6;CP$UIDd;2;80E;D;K;6;CP$UIDd;2;81E;D;K;6;CP$UIDd;2;82E;D;K;6;CP$UIDd;2;83E;D;K;6;CP$UIDd;2;84E;D;K;6;CP$UIDd;2;85E;D;K;6;CP$UIDd;2;86E;D;K;6;CP$UIDd;2;87E;D;K;6;CP$UIDd;2;88E;D;K;6;CP$UIDd;2;89E;D;K;6;CP$UIDd;2;90E;D;K;6;CP$UIDd;2;91E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;93E;D;K;6;CP$UIDd;2;94E;D;K;6;CP$UIDd;2;95E;D;K;6;CP$UIDd;2;96E;D;K;6;CP$UIDd;2;97E;D;K;6;CP$UIDd;2;98E;D;K;6;CP$UIDd;2;99E;D;K;6;CP$UIDd;3;100E;D;K;6;CP$UIDd;3;101E;D;K;6;CP$UIDd;3;102E;D;K;6;CP$UIDd;3;103E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;105E;D;K;6;CP$UIDd;3;106E;D;K;6;CP$UIDd;3;107E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;109E;D;K;6;CP$UIDd;3;110E;D;K;6;CP$UIDd;3;111E;D;K;6;CP$UIDd;3;112E;D;K;6;CP$UIDd;3;114E;D;K;6;CP$UIDd;3;115E;D;K;6;CP$UIDd;3;116E;D;K;6;CP$UIDd;3;117E;D;K;6;CP$UIDd;3;118E;D;K;6;CP$UIDd;3;119E;D;K;6;CP$UIDd;3;120E;E;E;S;16;IBCocoaFrameworkD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;46E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;44E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;121E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;17E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;3;122E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;124E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;125E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;134E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;8;CPButtonK;8;$classesA;S;8;CPButtonS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;137E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;138E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;140E;K;16;$aimage-positionD;K;6;CP$UIDd;3;123E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;131E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;143E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;123E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;23E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;3;144E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;3;145E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;3;146E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;3;147E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;3;148E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;29E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;149E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;150E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;151E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;152E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;153E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;140E;K;16;$aimage-positionD;K;6;CP$UIDd;3;123E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;131E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;154E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;123E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;155E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;156E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;157E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;28E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;158E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;158E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;159E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;1;0E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;160E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;161E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;162E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;163E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;133E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;165E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;166E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;167E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;12;$atext-colorD;K;6;CP$UIDd;3;168E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;169E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;10;CPMenuItemK;8;$classesA;S;10;CPMenuItemS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;32E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;170E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;44E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;171E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;46E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;172E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;173E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;138E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;140E;K;16;$aimage-positionD;K;6;CP$UIDd;3;123E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;131E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;143E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;123E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;174E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;12;$atext-colorD;K;6;CP$UIDd;3;176E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;177E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;178E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;161E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;162E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;163E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;133E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;165E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;179E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;161E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;162E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;163E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;133E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;133E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;3;165E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;180E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;167E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;12;$atext-colorD;K;6;CP$UIDd;3;181E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;182E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;32E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;183E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;44E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;171E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;3;142E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;46E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;172E;E;D;K;6;$classD;K;6;CP$UIDd;2;32E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;184E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;44E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;171E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;46E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;172E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;185E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;12;$atext-colorD;K;6;CP$UIDd;3;186E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;187E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;121E;E;D;K;10;$classnameS;13;CPPopUpButtonK;8;$classesA;S;13;CPPopUpButtonS;8;CPButtonS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;43E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;2;46E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;188E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;189E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;190E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;191E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;132E;K;11;$aalignmentD;K;6;CP$UIDd;3;123E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;123E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;1;0E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;131E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;6;CPMenuK;8;$classesA;S;6;CPMenuS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;45E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;3;192E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;3;193E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;194E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;153E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;140E;K;16;$aimage-positionD;K;6;CP$UIDd;3;123E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;131E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;154E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;123E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;195E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;12;$atext-colorD;K;6;CP$UIDd;3;196E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;197E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;10;CPCheckBoxK;8;$classesA;S;10;CPCheckBoxS;8;CPButtonS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;49E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;198E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;199E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;200E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;201E;K;16;$aimage-positionD;K;6;CP$UIDd;3;131E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;123E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;202E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;131E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;203E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;156E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;204E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;205E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;206E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;156E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;127E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;128E;K;6;$afontD;K;6;CP$UIDd;3;130E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;131E;K;11;$aalignmentD;K;6;CP$UIDd;3;132E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;3;133E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;207E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;135E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;136E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;3;136E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;3;131E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;3;132E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;29E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;3;123E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;208E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;138E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;29E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;3;139E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;140E;K;16;$aimage-positionD;K;6;CP$UIDd;3;123E;K;6;$afontD;K;6;CP$UIDd;3;141E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;123E;K;11;$aalignmentD;K;6;CP$UIDd;3;131E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;142E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;132E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;3;209E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonAllowsMixedStateKeyD;K;6;CP$UIDd;3;136E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;24;CPButtonImagePositionKeyD;K;6;CP$UIDd;3;123E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;3;123E;K;24;CPButtonPeriodicDelayKeyD;K;6;CP$UIDd;1;0E;K;27;CPButtonPeriodicIntervalKeyD;K;6;CP$UIDd;1;0E;E;S;21;Static Text (Record:)S;30;Round Textured Button (Random)S;30;Window (CPFormatter & Friends)S;18;Static Text (name)S;35;Round Textured Button (objectValue)S;17;Text Field Cell-1S;24;Text Field Cell (error1)S;22;Button Cell (Empty OK)S;12;File's OwnerS;20;Static Text (Date 1)S;17;Text Field Cell-2S;12;Content ViewS;10;Text FieldS;29;Pop Up Button Cell (Tom - 34)S;46;Static Text (Input: [a-zA-Z0-9], max length 7)S;22;Menu Item (Harry - 50)S;24;Text Field Cell (error2)S;32;Round Textured Button (Random)-1S;20;Static Text (error2)S;12;Text Field-1S;12;Text Field-2S;24;Text Field Cell (Date 1)S;22;Text Field Cell (Text)S;24;Text Field Cell (Date 2)S;21;Button Cell (Set nil)S;22;Text Field Cell (name)S;25;Text Field Cell (Record:)S;58;Text Field Cell (Input: mm-dd-yyyy Display: mm-dd-yyyy)S;25;Button Cell (objectValue)S;54;Static Text (Input: mm-dd-yyyy Display: mm-dd-yyyy)S;59;Text Field Cell (Input: mm/dd/yyyy Display: abbreviated)S;15;Text Field CellS;20;Menu Item (Tom - 34)S;21;Menu Item (Dick - 27)S;55;Static Text (Input: mm/dd/yyyy Display: abbreviated)S;27;Button Cell (objectValue)-1S;11;ApplicationS;13;Pop Up ButtonS;17;Menu (OtherViews)S;20;Button Cell (Random)S;37;Round Textured Button (objectValue)-1S;50;Text Field Cell (Input: [a-zA-Z0-9], max length 7)S;20;Static Text (error1)S;20;Check Box (Empty OK)S;18;Static Text (Text)S;22;Button Cell (Random)-1S;14;App ControllerS;20;Static Text (Date 2)S;31;Round Textured Button (Set nil)D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;36E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;210E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;37E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;211E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;48E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;197E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;35E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;177E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;25E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;212E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;44E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;213E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;30E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;214E;E;D;K;6;$classD;K;6;CP$UIDd;3;104E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;52E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;24E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;215E;E;D;K;10;$classnameS;21;CPCibControlConnectorK;8;$classesA;S;21;CPCibControlConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;44E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;216E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;22E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;217E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;34E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;218E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;54E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;219E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;47E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;220E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;26E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;221E;E;D;K;6;$classD;K;6;CP$UIDd;3;113E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;50E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;52E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;222E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;24E;E;E;d;1;0S;21;{{31, 284}, {58, 17}}S;18;{{0, 0}, {58, 17}}d;2;36S;9;textfieldS;6;normalD;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;129E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;223E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;224E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;3;136E;K;17;CPFontIsItalicKeyD;K;6;CP$UIDd;3;136E;E;d;1;2d;1;4T;S;7;Record:d;4;3072F;S;21;{{406, 37}, {66, 24}}S;18;{{0, 0}, {66, 24}}S;6;buttonS;17;selected+borderedD;K;6;$classD;K;6;CP$UIDd;3;129E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;223E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;224E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;3;133E;K;17;CPFontIsItalicKeyD;K;6;CP$UIDd;3;136E;E;d;1;1S;6;RandomS;28;{1.79769e+308, 1.79769e+308}S;8;CPWindowS;24;{{233, 100}, {734, 327}}d;1;7S;21;CPFormatter & FriendsS;22;{{96, 284}, {200, 17}}S;19;{{0, 0}, {200, 17}}S;4;nameS;22;{{493, 122}, {88, 24}}S;18;{{0, 0}, {88, 24}}S;11;objectValueS;20;{{31, 42}, {50, 17}}S;18;{{0, 0}, {50, 17}}S;6;Date 1S;20;{{0, 0}, {734, 327}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;38E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;35E;E;E;S;22;{{88, 210}, {279, 29}}S;19;{{0, 0}, {279, 29}}S;19;bezeled+placeholderS;0;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;225E;E;S;22;{{96, 189}, {357, 17}}S;19;{{0, 0}, {357, 17}}D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;226E;E;S;32;Input: [a-zA-Z0-9], max length 7S;10;Harry - 50S;17;_popUpItemAction:d;7;1048576S;22;{{406, 122}, {66, 24}}S;22;{{96, 241}, {282, 17}}S;19;{{0, 0}, {282, 17}}D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;227E;E;S;6;error2S;21;{{88, 35}, {279, 29}}S;22;{{88, 122}, {279, 29}}S;22;{{96, 101}, {357, 17}}D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;228E;E;S;40;Input: mm-dd-yyyy Display: mm-dd-yyyyS;8;Tom - 34S;9;Dick - 27S;21;{{96, 14}, {282, 17}}D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;229E;E;S;41;Input: mm/dd/yyyy Display: abbreviatedS;23;{{204, 279}, {120, 24}}S;19;{{0, 0}, {120, 24}}S;12;popup-buttonS;8;borderedS;10;OtherViewsD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;33E;E;E;S;21;{{493, 37}, {88, 24}}S;22;{{96, 153}, {282, 17}}D;K;6;$classD;K;6;CP$UIDd;3;164E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;230E;E;S;6;error1S;22;{{604, 127}, {84, 18}}S;18;{{0, 0}, {84, 18}}S;9;check-boxS;8;selectedS;8;Empty OKS;21;{{31, 217}, {50, 17}}S;4;TextS;13;AppControllerS;21;{{31, 129}, {50, 17}}S;6;Date 2S;21;{{604, 37}, {66, 24}}S;7;Set nilS;10;dateField1S;10;dateField2S;11;recordFieldS;10;recordMenuS;9;textFieldS;9;theWindowS;13;selectRecord:S;9;setDate1:S;9;setDate2:S;7;setNil:S;13;objectValue1:S;13;objectValue2:S;11;setEmptyOK:S;17;Arial, sans-serifd;2;12D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;142E;D;K;6;CP$UIDd;3;142E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;142E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;232E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;142E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;142E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;231E;D;K;6;CP$UIDd;3;142E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;232E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;123E;D;K;6;CP$UIDd;3;142E;E;E;f;3;0.5f;12;0.8816326531E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/Manual/CPFormatterTest/Resources/MainMenu.xib b/Tests/Manual/CPFormatterTest/Resources/MainMenu.xib new file mode 100644 index 000000000..21153c71f --- /dev/null +++ b/Tests/Manual/CPFormatterTest/Resources/MainMenu.xib @@ -0,0 +1,1435 @@ + + + + 1050 + 10K540 + 804 + 1038.36 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 804 + + + YES + + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + 7 + 2 + {{233, 991}, {734, 327}} + 1946157056 + CPFormatter & Friends + NSWindow + + {1.79769e+308, 1.79769e+308} + + + 256 + + YES + + + 268 + {{94, 266}, {271, 22}} + + YES + + -1804468671 + 272630784 + + + LucidaGrande + 13 + 1044 + + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + textColor + + 3 + MAA + + + + + + + 268 + {{31, 268}, {50, 17}} + + YES + + 68288064 + 272630784 + Date 1 + + LucidaGrande + 13 + 16 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + + + + 268 + {{31, 26}, {58, 17}} + + YES + + 68288064 + 272630784 + Record: + + + + + + + + + 268 + {{96, 26}, {200, 17}} + + YES + + 68288064 + 272630784 + name + + + + + + + + + 268 + {{96, 296}, {282, 17}} + + YES + + 68288064 + 272630784 + Input: mm/dd/yyyy Display: abbreviated + + + + + 3 + MC41AA + + 2 + + + + + + + 268 + {{203, 22}, {126, 26}} + + YES + + -2076049856 + 2048 + + + 109199615 + 129 + + + 400 + 75 + + + Tom - 34 + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + OtherViews + + YES + + + + Dick - 27 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Harry - 50 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + + 1 + YES + YES + 2 + + + + + 268 + {{94, 179}, {271, 22}} + + YES + + -1804468671 + 272630784 + + + + YES + + + + + + + 268 + {{31, 181}, {50, 17}} + + YES + + 68288064 + 272630784 + Date 2 + + + + + + + + + 268 + {{96, 209}, {357, 17}} + + YES + + 68288064 + 272630784 + Input: mm-dd-yyyy Display: mm-dd-yyyy + + + + + 3 + MC41AA + + + + + + + 268 + {{408, 264}, {66, 25}} + + YES + + -2080244224 + 134217728 + Random + + + -2038152961 + 163 + + + 400 + 75 + + + + + 268 + {{495, 264}, {88, 25}} + + YES + + -2080244224 + 134217728 + objectValue + + + -2038152961 + 163 + + + 400 + 75 + + + + + 268 + {{606, 264}, {66, 25}} + + YES + + -2080244224 + 134217728 + Set nil + + + -2038152961 + 163 + + + 400 + 75 + + + + + 268 + {{408, 179}, {66, 25}} + + YES + + -2080244224 + 134217728 + Random + + + -2038152961 + 163 + + + 400 + 75 + + + + + 268 + {{495, 179}, {88, 25}} + + YES + + -2080244224 + 134217728 + objectValue + + + -2038152961 + 163 + + + 400 + 75 + + + + + 268 + {{604, 182}, {84, 18}} + + YES + + -2080244224 + 0 + Empty OK + + + 1211912703 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + + + + 268 + {{96, 157}, {282, 17}} + + YES + + 68288064 + 272630784 + error1 + + + + + 1 + MC44ODE2MzI2NTMxIDAgMAA + + + + + + 268 + {{94, 91}, {271, 22}} + + YES + + -1804468671 + 272630784 + + + + YES + + + + + + + 268 + {{31, 93}, {50, 17}} + + YES + + 68288064 + 272630784 + Text + + + + + + + + + 268 + {{96, 121}, {357, 17}} + + YES + + 68288064 + 272630784 + Input: [a-zA-Z0-9], max length 7 + + + + + 3 + MC41AA + + + + + + + 268 + {{96, 69}, {282, 17}} + + YES + + 68288064 + 272630784 + error2 + + + + + 1 + MC44ODE2MzI2NTMxIDAgMAA + + + + + {734, 327} + + + {{0, 0}, {2560, 1418}} + {1.79769e+308, 1.79769e+308} + + + AppController + + + + + YES + + + theWindow + + + + 467 + + + + recordField + + + + 482 + + + + recordMenu + + + + 483 + + + + selectRecord: + + + + 484 + + + + dateField1 + + + + 491 + + + + dateField2 + + + + 492 + + + + setDate1: + + + + 497 + + + + setDate2: + + + + 498 + + + + setNil: + + + + 504 + + + + objectValue1: + + + + 511 + + + + objectValue2: + + + + 512 + + + + setEmptyOK: + + + + 517 + + + + textField + + + + 532 + + + + error1 + + + + 533 + + + + error2 + + + + 534 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 371 + + + YES + + + + + + 372 + + + YES + + + + + + + + + + + + + + + + + + + + + + + + + 456 + + + YES + + + + + + 457 + + + + + 460 + + + YES + + + + + + 461 + + + + + 463 + + + YES + + + + + + 464 + + + + + 466 + + + + + 472 + + + YES + + + + + + 473 + + + + + 474 + + + YES + + + + + + 475 + + + YES + + + + + + 476 + + + YES + + + + + + + + 477 + + + + + 478 + + + + + 479 + + + + + 480 + + + YES + + + + + + 481 + + + + + 485 + + + YES + + + + + + 486 + + + YES + + + + + + 487 + + + YES + + + + + + 488 + + + + + 489 + + + + + 490 + + + + + 493 + + + YES + + + + + + 494 + + + + + 495 + + + YES + + + + + + 496 + + + + + 501 + + + YES + + + + + + 502 + + + + + 505 + + + YES + + + + + + 506 + + + + + 508 + + + YES + + + + + + 509 + + + + + 515 + + + YES + + + + + + 516 + + + + + 520 + + + YES + + + + + + 521 + + + + + 524 + + + YES + + + + + + 525 + + + YES + + + + + + 526 + + + YES + + + + + + 527 + + + YES + + + + + + 528 + + + + + 529 + + + + + 530 + + + + + 531 + + + + + + + YES + + YES + -3.IBPluginDependency + 371.IBEditorWindowLastContentRect + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 371.editorWindowContentRectSynchronizationRect + 372.IBPluginDependency + 456.IBPluginDependency + 456.IBViewBoundsToFrameTransform + 457.IBPluginDependency + 460.IBPluginDependency + 460.IBViewBoundsToFrameTransform + 461.IBPluginDependency + 463.IBPluginDependency + 463.IBViewBoundsToFrameTransform + 464.IBPluginDependency + 472.IBPluginDependency + 472.IBViewBoundsToFrameTransform + 473.IBPluginDependency + 474.IBPluginDependency + 475.IBPluginDependency + 476.IBEditorWindowLastContentRect + 476.IBPluginDependency + 477.IBPluginDependency + 478.IBPluginDependency + 479.IBPluginDependency + 480.IBPluginDependency + 480.IBViewBoundsToFrameTransform + 481.IBPluginDependency + 485.IBPluginDependency + 485.IBViewBoundsToFrameTransform + 486.IBPluginDependency + 486.IBViewBoundsToFrameTransform + 487.IBPluginDependency + 487.IBViewBoundsToFrameTransform + 488.IBPluginDependency + 489.IBPluginDependency + 490.IBPluginDependency + 493.IBPluginDependency + 493.IBViewBoundsToFrameTransform + 494.IBPluginDependency + 495.IBPluginDependency + 495.IBViewBoundsToFrameTransform + 496.IBPluginDependency + 501.IBPluginDependency + 501.IBViewBoundsToFrameTransform + 502.IBPluginDependency + 505.IBPluginDependency + 505.IBViewBoundsToFrameTransform + 506.IBPluginDependency + 508.IBPluginDependency + 508.IBViewBoundsToFrameTransform + 509.IBPluginDependency + 515.IBPluginDependency + 515.IBViewBoundsToFrameTransform + 516.IBPluginDependency + 520.IBPluginDependency + 520.IBViewBoundsToFrameTransform + 521.IBPluginDependency + 524.IBPluginDependency + 524.IBViewBoundsToFrameTransform + 525.IBPluginDependency + 525.IBViewBoundsToFrameTransform + 526.IBPluginDependency + 526.IBViewBoundsToFrameTransform + 527.IBPluginDependency + 527.IBViewBoundsToFrameTransform + 528.IBPluginDependency + 529.IBPluginDependency + 530.IBPluginDependency + 531.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + {{563, 711}, {734, 327}} + com.apple.InterfaceBuilder.CocoaPlugin + {{563, 711}, {734, 327}} + + {{33, 99}, {480, 360}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCvAAAw5+AAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABB+AAAw0YAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABB+AAAw4uAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCwAAAw4AAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{885, 954}, {138, 63}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCwAAAwmAAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCvAAAw0cAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABB+AAAw0QAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCwAAAw2AAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDzAAAw0gAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABDygAAw4EAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD+4AAw0gAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD94AAw0gAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABD94AAw0gAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABEFwAAwwIAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCwAAAwywAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCxgAAw0IAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCEAAAwz8AAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCygAAw1sAAA + + com.apple.InterfaceBuilder.CocoaPlugin + + P4AAAL+AAABCygAAwycAAA + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 534 + + + + YES + + AppController + + theWindow + NSWindow + + + theWindow + + theWindow + NSWindow + + + + IBProjectSource + ./Classes/AppController.h + + + + AppController + + YES + + YES + objectValue1: + objectValue2: + selectRecord: + setDate1: + setDate2: + setEmptyOK: + setNil: + + + YES + id + id + id + id + id + id + id + + + + YES + + YES + objectValue1: + objectValue2: + selectRecord: + setDate1: + setDate2: + setEmptyOK: + setNil: + + + YES + + objectValue1: + id + + + objectValue2: + id + + + selectRecord: + id + + + setDate1: + id + + + setDate2: + id + + + setEmptyOK: + id + + + setNil: + id + + + + + YES + + YES + dateField1 + dateField2 + error1 + error2 + recordField + recordMenu + textField + + + YES + NSTextField + NSTextField + NSTextField + NSTextField + NSTextField + NSPopUpButton + NSTextField + + + + YES + + YES + dateField1 + dateField2 + error1 + error2 + recordField + recordMenu + textField + + + YES + + dateField1 + NSTextField + + + dateField2 + NSTextField + + + error1 + NSTextField + + + error2 + NSTextField + + + recordField + NSTextField + + + recordMenu + NSPopUpButton + + + textField + NSTextField + + + + + IBUserSource + + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + + 3 + + YES + + YES + NSMenuCheckmark + NSMenuMixedState + NSSwitch + + + YES + {9, 8} + {7, 2} + {15, 15} + + + + diff --git a/Tests/Manual/CPFormatterTest/Resources/date-functions.js b/Tests/Manual/CPFormatterTest/Resources/date-functions.js new file mode 100644 index 000000000..639a6c2ee --- /dev/null +++ b/Tests/Manual/CPFormatterTest/Resources/date-functions.js @@ -0,0 +1,471 @@ +/* + * http://code.google.com/p/flexible-js-formatting/ + * + * Copyright (C) 2004 Baron Schwartz + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +Date.parseFunctions = {count:0}; +Date.parseRegexes = []; +Date.formatFunctions = {count:0}; + +Date.prototype.dateFormat = function(format, ignore_offset) { + if (Date.formatFunctions[format] == null) { + Date.createNewFormat(format); + } + var func = Date.formatFunctions[format]; + if (ignore_offset || ! this.offset) { + return this[func](); + } else { + return (new Date(this.valueOf() - this.offset))[func](); + } +}; + +Date.createNewFormat = function(format) { + var funcName = "format" + Date.formatFunctions.count++; + Date.formatFunctions[format] = funcName; + var code = "Date.prototype." + funcName + " = function(){return "; + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + // escape character start + if (!special && ch == "\\") { + special = true; + } + // escaped string + else if (!special && ch == '"') { + var end = format.indexOf('"', i+1); + if (end==-1) + { + end = format.length; + } + code += "'" + String.escape(format.substring(i+1, end)) + "' + "; + i = end; + } + // escaped character + else if (special) { + special = false; + code += "'" + String.escape(ch) + "' + "; + } + else { + code += Date.getFormatCode(ch); + } + } + eval(code.substring(0, code.length - 3) + ";}"); +}; + +Date.getFormatCode = function(character) { + switch (character) { + case "d": + return "String.leftPad(this.getDate(), 2, '0') + "; + case "D": + return "Date.dayNames[this.getDay()].substring(0, 3) + "; + case "j": + return "this.getDate() + "; + case "l": + return "Date.dayNames[this.getDay()] + "; + case "S": + return "this.getSuffix() + "; + case "w": + return "this.getDay() + "; + case "z": + return "this.getDayOfYear() + "; + case "W": + return "this.getWeekOfYear() + "; + case "F": + return "Date.monthNames[this.getMonth()] + "; + case "m": + return "String.leftPad(this.getMonth() + 1, 2, '0') + "; + case "M": + return "Date.monthNames[this.getMonth()].substring(0, 3) + "; + case "n": + return "(this.getMonth() + 1) + "; + case "t": + return "this.getDaysInMonth() + "; + case "L": + return "(this.isLeapYear() ? 1 : 0) + "; + case "Y": + return "this.getFullYear() + "; + case "y": + return "('' + this.getFullYear()).substring(2, 4) + "; + case "a": + return "(this.getHours() < 12 ? 'am' : 'pm') + "; + case "A": + return "(this.getHours() < 12 ? 'AM' : 'PM') + "; + case "g": + return "((this.getHours() %12) ? this.getHours() % 12 : 12) + "; + case "G": + return "this.getHours() + "; + case "h": + return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + "; + case "H": + return "String.leftPad(this.getHours(), 2, '0') + "; + case "i": + return "String.leftPad(this.getMinutes(), 2, '0') + "; + case "s": + return "String.leftPad(this.getSeconds(), 2, '0') + "; + case "X": + return "String.leftPad(this.getMilliseconds(), 3, '0') + "; + case "O": + return "this.getGMTOffset() + "; + case "T": + return "this.getTimezone() + "; + case "Z": + return "(this.getTimezoneOffset() * -60) + "; + case "q": // quarter num, Q for name? + return "this.getQuarter() + "; + default: + return "'" + String.escape(character) + "' + "; + } +}; + +Date.parseDate = function(input, format) { + if (Date.parseFunctions[format] == null) { + Date.createParser(format); + } + var func = Date.parseFunctions[format]; + return Date[func](input); +}; + +Date.createParser = function(format) { + var funcName = "parse" + Date.parseFunctions.count++; + var regexNum = Date.parseRegexes.length; + var currentGroup = 1; + Date.parseFunctions[format] = funcName; + + var code = "Date." + funcName + " = function(input){\n" + + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, ms = -1, z = 0;\n" + + "var d = new Date();\n" + + "y = d.getFullYear();\n" + + "m = d.getMonth();\n" + + "d = d.getDate();\n" + + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n" + + "if (results && results.length > 0) {" ; + var regex = ""; + + var special = false; + var ch = ''; + for (var i = 0; i < format.length; ++i) { + ch = format.charAt(i); + if (!special && ch == "\\") { + special = true; + } + else if (special) { + special = false; + regex += String.escape(ch); + } + else { + obj = Date.formatCodeToRegex(ch, currentGroup); + currentGroup += obj.g; + regex += obj.s; + if (obj.g && obj.c) { + code += obj.c; + } + } + } + + code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0 && ms >= 0)\n" + + "{return new Date(y, m, d, h, i, s, ms).applyOffset(z);}\n" + + "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n" + + "{return new Date(y, m, d, h, i, s).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n" + + "{return new Date(y, m, d, h, i).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n" + + "{return new Date(y, m, d, h).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0 && d > 0)\n" + + "{return new Date(y, m, d).applyOffset(z);}\n" + + "else if (y > 0 && m >= 0)\n" + + "{return new Date(y, m).applyOffset(z);}\n" + + "else if (y > 0)\n" + + "{return new Date(y).applyOffset(z);}\n" + + "}return null;}"; + + Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$"); + eval(code); +}; + +Date.formatCodeToRegex = function(character, currentGroup) { + switch (character) { + case "D": + return {g:0, + c:null, + s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"}; + case "j": + case "d": + return {g:1, + c:"d = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "l": + return {g:0, + c:null, + s:"(?:" + Date.dayNames.join("|") + ")"}; + case "S": + return {g:0, + c:null, + s:"(?:st|nd|rd|th)"}; + case "w": + return {g:0, + c:null, + s:"\\d"}; + case "z": + return {g:0, + c:null, + s:"(?:\\d{1,3})"}; + case "W": + return {g:0, + c:null, + s:"(?:\\d{2})"}; + case "F": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n", + s:"(" + Date.monthNames.join("|") + ")"}; + case "M": + return {g:1, + c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n", + s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"}; + case "n": + case "m": + return {g:1, + c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n", + s:"(\\d{1,2})"}; + case "t": + return {g:0, + c:null, + s:"\\d{1,2}"}; + case "L": + return {g:0, + c:null, + s:"(?:1|0)"}; + case "Y": + return {g:1, + c:"y = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{4})"}; + case "y": + return {g:1, + c:"var ty = parseInt(results[" + currentGroup + "], 10);\n" + + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", + s:"(\\d{1,2})"}; + case "a": + return {g:1, + c:"if (results[" + currentGroup + "] == 'am') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(am|pm)"}; + case "A": + return {g:1, + c:"if (results[" + currentGroup + "] == 'AM') {\n" + + "if (h == 12) { h = 0; }\n" + + "} else { if (h < 12) { h += 12; }}", + s:"(AM|PM)"}; + case "g": + case "G": + case "h": + case "H": + return {g:1, + c:"h = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{1,2})"}; + case "i": + return {g:1, + c:"i = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "s": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{2})"}; + case "X": + return {g:1, + c:"ms = parseInt(results[" + currentGroup + "], 10);\n", + s:"(\\d{3})"}; + case "O": + case "P": + return {g:1, + c:"z = Date.parseOffset(results[" + currentGroup + "], 10);\n", + s:"(Z|[+-]\\d{2}:?\\d{2})"}; // "Z", "+05:00", "+0500" all acceptable. + case "T": + return {g:0, + c:null, + s:"[A-Z]{3}"}; + case "Z": + return {g:1, + c:"s = parseInt(results[" + currentGroup + "], 10);\n", + s:"([+-]\\d{1,5})"}; + default: + return {g:0, + c:null, + s:String.escape(character)}; + } +}; + +Date.parseOffset = function(str) { + if (str == "Z") { return 0 ; } // UTC, no offset. + var seconds ; + seconds = parseInt(str[0] + str[1] + str[2]) * 3600 ; // e.g., "+05" or "-08" + if (str[3] == ":") { // "+HH:MM" is preferred iso8601 format ("O") + seconds += parseInt(str[4] + str[5]) * 60; + } else { // "+HHMM" is frequently used, though. ("P") + seconds += parseInt(str[3] + str[4]) * 60; + } + return seconds ; +}; + +// convert the parsed date into UTC, but store the offset so we can optionally use it in dateFormat() +Date.prototype.applyOffset = function(offset_seconds) { + this.offset = offset_seconds * 1000 ; + this.setTime(this.valueOf() + this.offset); + return this ; +}; + +Date.prototype.getTimezone = function() { + return this.toString().replace( + /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace( + /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3").replace( + /^.*?[0-9]{4} \(([A-Z]{3})\)/, "$1"); +}; + +Date.prototype.getGMTOffset = function() { + return (this.getTimezoneOffset() > 0 ? "-" : "+") + + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0") + + String.leftPad(this.getTimezoneOffset() % 60, 2, "0"); +}; + +Date.prototype.getDayOfYear = function() { + var num = 0; + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + for (var i = 0; i < this.getMonth(); ++i) { + num += Date.daysInMonth[i]; + } + return num + this.getDate() - 1; +}; + +Date.prototype.getWeekOfYear = function() { + // Skip to Thursday of this week + var now = this.getDayOfYear() + (4 - this.getDay()); + // Find the first Thursday of the year + var jan1 = new Date(this.getFullYear(), 0, 1); + var then = (7 - jan1.getDay() + 4); + document.write(then); + return String.leftPad(((now - then) / 7) + 1, 2, "0"); +}; + +Date.prototype.isLeapYear = function() { + var year = this.getFullYear(); + return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year))); +}; + +Date.prototype.getFirstDayOfMonth = function() { + var day = (this.getDay() - (this.getDate() - 1)) % 7; + return (day < 0) ? (day + 7) : day; +}; + +Date.prototype.getLastDayOfMonth = function() { + var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7; + return (day < 0) ? (day + 7) : day; +}; + +Date.prototype.getDaysInMonth = function() { + Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28; + return Date.daysInMonth[this.getMonth()]; +}; +Date.prototype.getQuarter = function() { + return Date.quarterFromMonthNum[this.getMonth()]; +}; + +Date.prototype.getSuffix = function() { + switch (this.getDate()) { + case 1: + case 21: + case 31: + return "st"; + case 2: + case 22: + return "nd"; + case 3: + case 23: + return "rd"; + default: + return "th"; + } +}; + +String.escape = function(string) { + return string.replace(/('|\\)/g, "\\$1"); +}; + +String.leftPad = function (val, size, ch) { + var result = new String(val); + if (ch == null) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result; +}; + +Date.quarterFromMonthNum = [1,1,1,2,2,2,3,3,3,4,4,4]; +Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31]; +Date.monthNames = + ["January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"]; +Date.dayNames = + ["Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday"]; +Date.y2kYear = 50; +Date.monthNumbers = { + Jan:0, + Feb:1, + Mar:2, + Apr:3, + May:4, + Jun:5, + Jul:6, + Aug:7, + Sep:8, + Oct:9, + Nov:10, + Dec:11}; +Date.patterns = { + ISO8601LongPattern: "Y\\-m\\-d\\TH\\:i\\:sO", + ISO8601ShortPattern: "Y\\-m\\-d", + ShortDatePattern: "n/j/Y", + LongDatePattern: "l, F d, Y", + FullDateTimePattern: "l, F d, Y g:i:s A", + MonthDayPattern: "F d", + ShortTimePattern: "g:i A", + LongTimePattern: "g:i:s A", + SortableDateTimePattern: "Y-m-d\\TH:i:s", + UniversalSortableDateTimePattern: "Y-m-d H:i:sO", + YearMonthPattern: "F, Y"}; diff --git a/Tests/Manual/CPFormatterTest/Resources/spinner.gif b/Tests/Manual/CPFormatterTest/Resources/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..06dbc2bc21dddcf0e09b566d5b211aee89570f52 GIT binary patch literal 1849 zcma*odr(tX9tZHtz31lM+(&Y`A`Ou`NeG&R#DrIfV%?hng21vs6v>ooRQQFbk7E_K!V( z{?5!fpZWgIZ%*d6t%i*j24bL}AZUJm9)h6R*;%L4IWse3G#VWaN1#$zSSXcBhlYlH zJ|D}n{r&w2f+Qp)SS*&n?*G4}{}!h?td_mjU6Kad-rW*QwWYCUk7d^e+sjpZAn6kT z5rM;`{~_}-wm+L@%+E;JphLm}C3WzQAQD0wBoY|rOTQX{(@pp-WAA8Iw0HKl|15j) zhGh(SFWu#5zUCw^T!}C~eC}~?{xG-r7ugQC>taC+|L^xr&a%{#cgUOZXIM&v?)k^2 z1i5%0!U00wq)r4vlAwXBA_m5J5WNeuBm-XJQ5pG4GD%vc|K){+TJ{AkHqN@SJKczX zU}QRd9n*_bf^h94)6Ctv{CUfz_;qs#RDuQ$DR%y1&5G-a6rhf*4Y zl+UOD1*GE{GQ7vv;c-tTIMkz0ovO>9j%b5hpa@a*CBJ#W!0@ndSwF|%hMkdFtXiU) z`BEp+yhkt8ZY>tg&uyH@%^%K4jDrbA;et&vnnzZ3z22@e6<27z2Vk13kb7OtISyxv z(XoO-LNQCZe3lfzc%*pNqU<9T+p~teThOEB+~e&U0mC|zS{Q)dJZ)!^1f7L(zg*L> z*vSW%?dR~@@0(}x6-V^A`~ImD;)NaBUnP8;RH=bS2@pk`wp>>8r&jGjmGPy%1BW}v zoPo}ca$~bze@efc3kapuEVW1!%teOZT3j2Tw5=hjiAf02d}7dL0oFC%@=RXp5Ow#% z@a>+AM|YWt$n&e`>sB-32gBcuTi>R>*|8@lp`y6thc7ydyqDsuUn~YzZf|{-R@-3y zL#wx{Ii}xxL_csiW*LBn0-A$>zp4WOmkf6=ilrjlW?-l9+bCd7|i?*b5NTmy<<6NZ0T8$SN@mwdC2f z6jqK=N@bS@!=YSj%>h0}*4p+%0HbTIrE$w7UMT6+AZZ&DAo*qZAAi(OtNbIfl#Dw^ zJWeiCp~zi#&t6x}m9)O^eR4HiLV3QA<<0>HZ8%$^lrSE94Wb}=+MM^!b>n#5&-JQR zkr-CEu9C;_F*7DqDisulV6Pmg$nFL0TPn%~*m^-`Z3^BgU(sNpnx%nW(!eV9A&FvI zHL3X3lw8Wji^6=8KbQDE-e%b?svdFxxdh$8r97@7$ojeI`6AL8Ob6QC$qh&>ZWVDX1F{0vJnT%%mE;GveKWR%C} zM&4d;Jf3s9|HAA)yVUPo`Aq;0do#)uHSXi5*QF*)x@MVVHr+cN)uMZ__F|&Ta#p8d z53TOKtce!PJUuie8UWol-S(`c2nH?UGqJP{!4RR4u$LCfn)q-hj0^f=h(VYy)T6eN zhRO!ja-aDBTcgeyP(8Ua4IdiOog^*CQa?R(cP#9AgL9`j>EX-6Yf1lzX(!~``M1XC zNmM<4<6d~wWZ$Xrk0K}UteTrq@LBBk#MsjkK;pbuVhe)NI7(7Pf(l?lxC7=1Z7Pzl zMbS;nV4NI5_N{1$P)&XC)huOGQ+h^zpYUZfb*1n6>!`#*b3y52LGmi+<4sY5jyD#- zw&$d}DTguLAfnRtjrM*JfqtHqUu6rQoU=g%1E9xk%;)TDm^2<8n-0IhTsQFaek)MY}>PK4;nBk=ow4pF>vzkO& gna%Org-kgQCf=+BeMi^RbuY;YE~rTjend;_cdi8t>i_@% literal 0 HcmV?d00001 diff --git a/Tests/Manual/CPFormatterTest/index-debug.html b/Tests/Manual/CPFormatterTest/index-debug.html new file mode 100644 index 000000000..106d36a06 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/index-debug.html @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + CPFormatterTest + + + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPFormatterTest/index.html b/Tests/Manual/CPFormatterTest/index.html new file mode 100644 index 000000000..80e399ef6 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + CPFormatterTest + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPFormatterTest/main.j b/Tests/Manual/CPFormatterTest/main.j new file mode 100644 index 000000000..d827b2325 --- /dev/null +++ b/Tests/Manual/CPFormatterTest/main.j @@ -0,0 +1,23 @@ +/* + * AppController.j + * CPFormatterTest + * + * Created by aparajita on June 30, 2011. + * Copyright 2011, Victory-Heart Productions All rights reserved. + */ + +@import +@import + +@import "AppController.j" + +function formatter(aString, aLevel, aTitle) +{ + return aString; +} + +function main(args, namedArgs) +{ + CPLogRegister(CPLogConsole, null, formatter); + CPApplicationMain(args, namedArgs); +} From ebdba330820f982b38fbfe97fadd47c79775b5c1 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 9 Jul 2011 17:06:54 -0700 Subject: [PATCH 19/19] Whitespace cleanup --- Tests/Manual/CPFormatterTest/AppController.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Manual/CPFormatterTest/AppController.j b/Tests/Manual/CPFormatterTest/AppController.j index 8fcae1407..26b42c595 100644 --- a/Tests/Manual/CPFormatterTest/AppController.j +++ b/Tests/Manual/CPFormatterTest/AppController.j @@ -43,7 +43,7 @@ var randomFromTo = function(from, to) selector:@selector(resetErrorMessage:) name:CPTextFieldDidFocusNotification object:nil]; - + [textField setFormatter:[TextFormatter new]]; [textField setDelegate:self]; @@ -156,11 +156,11 @@ var randomFromTo = function(from, to) - (BOOL)getObjectValue:(CPStringRef)anObject forString:(CPString)aString errorDescription:(CPStringRef)anError { var error = [self errorDescriptionForString:aString]; - + if (error) { anObject(nil); - + if (anError) anError(error); }