From 0a96cb8eb3cc4aa9804674332c51ecada3511674 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 6 May 2010 17:36:11 +0200 Subject: [PATCH 001/356] call willChange* and didChange* methods on the actual classes --- Foundation/CPKeyValueObserving.j | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index b88f766a0..39f29779d 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -480,6 +480,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)willChangeValueForKey:(CPString)aKey { + var superClass = [self class], + methodSelector = @selector(willChangeValueForKey:), + methodImp = class_getMethodImplementation(superClass, methodSelector); + methodImp(self, methodSelector, aKey); + if (!aKey) return; @@ -490,6 +495,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)didChangeValueForKey:(CPString)aKey { + var superClass = [self class], + methodSelector = @selector(didChangeValueForKey:), + methodImp = class_getMethodImplementation(superClass, methodSelector); + methodImp(self, methodSelector, aKey); + if (!aKey) return; @@ -498,6 +508,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)willChange:(CPKeyValueChange)change valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)aKey { + var superClass = [self class], + methodSelector = @selector(willChange:valuesAtIndexes:forKey:), + methodImp = class_getMethodImplementation(superClass, methodSelector); + methodImp(self, methodSelector, change, indexes, aKey); + if (!aKey) return; @@ -508,6 +523,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)didChange:(CPKeyValueChange)change valuesAtIndexes:(CPIndexSet)indexes forKey:(CPString)aKey { + var superClass = [self class], + methodSelector = @selector(didChange:valuesAtIndexes:forKey:), + methodImp = class_getMethodImplementation(superClass, methodSelector); + methodImp(self, methodSelector, change, indexes, aKey); + if (!aKey) return; From db568af302ac3a9085a439cf165c2ffd083283ef Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 17 May 2010 12:32:56 +0200 Subject: [PATCH 002/356] made sure CPViewController calls viewDidLoad if it's view property is set directly --- AppKit/CPViewController.j | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j index 3fffe261d..ab8c3a22e 100644 --- a/AppKit/CPViewController.j +++ b/AppKit/CPViewController.j @@ -162,8 +162,6 @@ var CPViewControllerCachedCibs; if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) [cibOwner viewControllerDidLoadCib:self]; - - [self viewDidLoad]; } return _view; @@ -189,7 +187,13 @@ var CPViewControllerCachedCibs; */ - (void)setView:(CPView)aView { + var viewWasLoaded = !_view; + _view = aView; + + // Make sure the viewDidLoad method is called if the view is set directly + if (viewWasLoaded) + [self viewDidLoad]; } @end From 322d8c67b3d675ff4526cd007516a9ad111d973e Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 19 May 2010 18:31:21 +0200 Subject: [PATCH 003/356] Fixed NSTableColumn user resizable nib2cib --- Tools/nib2cib/NSTableColumn.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/nib2cib/NSTableColumn.j b/Tools/nib2cib/NSTableColumn.j index 735ed5fc5..635889344 100644 --- a/Tools/nib2cib/NSTableColumn.j +++ b/Tools/nib2cib/NSTableColumn.j @@ -51,9 +51,9 @@ _minWidth = [aCoder decodeFloatForKey:@"NSMinWidth"]; _maxWidth = [aCoder decodeFloatForKey:@"NSMaxWidth"]; - _resizingMask = [aCoder decodeBoolForKey:@"NSIsResizable"]; + _resizingMask = [aCoder decodeBoolForKey:@"NSIsResizeable"] ? CPTableColumnUserResizingMask : CPTableColumnAutoresizingMask; } - + return self; } From 76df9be4fbbe2a88c374c6143a579a5258ec1aef Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 19 May 2010 18:51:18 +0200 Subject: [PATCH 004/356] implemented CPTableColumn isHidden nib2cib support --- AppKit/CPTableColumn.j | 5 ++++- Tools/nib2cib/NSTableColumn.j | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 5c6b91cea..2d4e5af03 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -395,7 +395,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", CPTableColumnWidthKey = @"CPTableColumnWidthKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", - CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey"; + CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", + CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey"; @implementation CPTableColumn (CPCoding) @@ -417,6 +418,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]]; _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey]; + _isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenkey]; } return self; @@ -434,6 +436,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey]; [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey]; + [aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenkey]; } @end diff --git a/Tools/nib2cib/NSTableColumn.j b/Tools/nib2cib/NSTableColumn.j index 635889344..bcbea7422 100644 --- a/Tools/nib2cib/NSTableColumn.j +++ b/Tools/nib2cib/NSTableColumn.j @@ -52,6 +52,7 @@ _maxWidth = [aCoder decodeFloatForKey:@"NSMaxWidth"]; _resizingMask = [aCoder decodeBoolForKey:@"NSIsResizeable"] ? CPTableColumnUserResizingMask : CPTableColumnAutoresizingMask; + _isHidden = [aCoder decodeBoolForKey:@"NSHidden"]; } return self; From 6a33acbb7c7bf92e566e5d42ff3cbf9dbbf4b8a9 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 20 May 2010 11:39:47 +0200 Subject: [PATCH 005/356] implemented CPCoding support for CPSortDescriptor and made CPTableColumn decode it's _sortDescriptorPrototype --- AppKit/CPTableColumn.j | 7 ++++++- Foundation/CPSortDescriptor.j | 28 +++++++++++++++++++++++++ Tools/nib2cib/NSAppKit.j | 1 + Tools/nib2cib/NSSortDescriptor.j | 35 ++++++++++++++++++++++++++++++++ Tools/nib2cib/NSTableColumn.j | 2 ++ 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 Tools/nib2cib/NSSortDescriptor.j diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index e8b6f1c5e..14f239484 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -396,7 +396,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", - CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey"; + CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey", + CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey"; @implementation CPTableColumn (CPCoding) @@ -419,6 +420,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey]; _isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenkey]; + + _sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey]; } return self; @@ -437,6 +440,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey]; [aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenkey]; + + [aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey]; } @end diff --git a/Foundation/CPSortDescriptor.j b/Foundation/CPSortDescriptor.j index c7b78c840..c7d29f16a 100755 --- a/Foundation/CPSortDescriptor.j +++ b/Foundation/CPSortDescriptor.j @@ -149,3 +149,31 @@ CPOrderedDescending = 1; } @end + +var CPSortDescriptorKeyKey = @"CPSortDescriptorKeyKey", // Don't you just love naming schemes ;) + CPSortDescriptorAscendingKey = @"CPSortDescriptorAscendingKey", + CPSortDescriptorSelectorKey = @"CPSortDescriptorSelectorKey"; + +@implementation CPSortDescriptor (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + if (self = [super init]) + { + _key = [aCoder decodeObjectForKey:CPSortDescriptorKeyKey]; + _ascending = [aCoder decodeBoolForKey:CPSortDescriptorAscendingKey]; + _selector = CPSelectorFromString([aCoder decodeObjectForKey:CPSortDescriptorSelectorKey]); + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_key forKey:CPSortDescriptorKeyKey]; + [aCoder encodeBool:_ascending forKey:CPSortDescriptorAscendingKey]; + [aCoder encodeObject:CPStringFromSelector(_selector) forKey:CPSortDescriptorSelectorKey]; +} + +@end + diff --git a/Tools/nib2cib/NSAppKit.j b/Tools/nib2cib/NSAppKit.j index 8a54fb2d1..96a3a52b8 100644 --- a/Tools/nib2cib/NSAppKit.j +++ b/Tools/nib2cib/NSAppKit.j @@ -67,6 +67,7 @@ @import "NSViewController.j" @import "NSWindowTemplate.j" @import "WebView.j" +@import "NSSortDescriptor.j" function CP_NSMapClassName(aClassName) diff --git a/Tools/nib2cib/NSSortDescriptor.j b/Tools/nib2cib/NSSortDescriptor.j new file mode 100644 index 000000000..c4f0beb87 --- /dev/null +++ b/Tools/nib2cib/NSSortDescriptor.j @@ -0,0 +1,35 @@ +@import + +@implementation CPSortDescriptor (NSCoding) +{ +} + +- (id)NS_initWithCoder:(CPCoder)aCoder +{ + if (self = [super init]) + { + _key = [aCoder decodeObjectForKey:@"NSKey"]; + _selector = CPSelectorFromString([aCoder decodeObjectForKey:@"NSSelector"]); + _ascending = [aCoder decodeBoolForKey:@"NSAscending"]; + } + + return self; +} + +@end + +@implementation NSSortDescriptor : CPSortDescriptor +{ +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + return [self NS_initWithCoder:aCoder]; +} + +- (Class)classForKeyedArchiver +{ + return [CPSortDescriptor class]; +} + +@end \ No newline at end of file diff --git a/Tools/nib2cib/NSTableColumn.j b/Tools/nib2cib/NSTableColumn.j index bcbea7422..bdafee212 100644 --- a/Tools/nib2cib/NSTableColumn.j +++ b/Tools/nib2cib/NSTableColumn.j @@ -53,6 +53,8 @@ _resizingMask = [aCoder decodeBoolForKey:@"NSIsResizeable"] ? CPTableColumnUserResizingMask : CPTableColumnAutoresizingMask; _isHidden = [aCoder decodeBoolForKey:@"NSHidden"]; + + _sortDescriptorPrototype = [aCoder decodeObjectForKey:@"NSSortDescriptorPrototype"]; } return self; From f7dd6e4387ca7bc770445a752c9822c9d0004f8b Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 20 May 2010 18:52:43 +0200 Subject: [PATCH 006/356] fixed a typo where CPThemeStateSelectedDataView was set on the header view of a table column --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 2ef0dde9b..aad636598 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1837,7 +1837,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (_headerView) { if (_currentHighlightedTableColumn != nil) - [[_currentHighlightedTableColumn headerView] unsetThemeState:CPThemeStateSelectedDataView]; + [[_currentHighlightedTableColumn headerView] unsetThemeState:CPThemeStateSelected]; if (aTableColumn != nil) [[aTableColumn headerView] setThemeState:CPThemeStateSelected]; From 528203d8e51dd029a84a9407dc827e49997ce522 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 25 May 2010 20:37:00 +0200 Subject: [PATCH 007/356] made CPDictionary call [super valueForKey:] on keys prefixed with @ --- Foundation/CPKeyValueCoding.j | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 36ef5b48c..6543d04b6 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -267,7 +267,10 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; - (id)valueForKey:(CPString)aKey { - return [self objectForKey:aKey]; + if ([aKey hasPrefix:@"@"]) + return [super valueForKey:aKey.substr(1)]; + + return [self objectForKey:aKey]; } - (void)setValue:(id)aValue forKey:(CPString)aKey From 468d8e7c33ed453aa3379898a7081f5bdc4d550a Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 31 May 2010 13:45:51 +0200 Subject: [PATCH 008/356] call windowWillLoad and windowDidLoad if the window is set directly from the initializer --- AppKit/CPWindowController.j | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index aebbc5e89..a123238ab 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -72,11 +72,17 @@ if (self) { + if (aWindow) + [self windowWillLoad]; + [self setWindow:aWindow]; [self setShouldCloseDocument:NO]; [self setNextResponder:CPApp]; + if (aWindow) + [self windowDidLoad]; + _documents = []; } From 43f0e43de7e8fbec69fb59dac6c7d2496ed70ae1 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 31 May 2010 15:41:52 +0200 Subject: [PATCH 009/356] call tableview doubleclick action even if target is nil (action will travel down the responder chain) --- AppKit/CPTableView.j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 8dd282e4e..1b866b17f 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2709,7 +2709,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } //end of editing conditional //double click actions - if([[CPApp currentEvent] clickCount] === 2 && _doubleAction && _target) + if([[CPApp currentEvent] clickCount] === 2 && _doubleAction) + { + _clickedRow = [self rowAtPoint:aPoint]; [self sendAction:_doubleAction to:_target]; } From 9ab446b7903b0acdc4c96fb0c194c1752aa0aaa2 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 8 Jun 2010 23:22:41 -0400 Subject: [PATCH 010/356] Added image alignment support to CPImageView, CPWindowController always loads a cib from the main bundle for consistency with Cocoa, CPApplication modified to explicitly load the About panel cib from the Framework bundle --- AppKit/CPApplication.j | 4 +- AppKit/CPImageView.j | 101 ++++++++++++++++++++++++++++++++---- AppKit/CPWindowController.j | 4 +- Tools/nib2cib/NSImageView.j | 3 +- 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 41d8d6dee..7958fc45f 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -325,7 +325,9 @@ CPRunContinuesResponse = -1002; applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"], copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"]; - var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"], + var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"], + aboutPanelController = [CPWindowController alloc], + aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController], aboutPanel = [aboutPanelController window], contentView = [aboutPanel contentView], imageView = [contentView viewWithTag:1], diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index 7d365f71f..ab9722cae 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -35,6 +35,16 @@ CPScaleProportionally = 0; CPScaleToFit = 1; CPScaleNone = 2; +CPImageAlignCenter = 0; +CPImageAlignTop = 1; +CPImageAlignTopLeft = 2; +CPImageAlignTopRight = 3; +CPImageAlignLeft = 4; +CPImageAlignBottom = 5; +CPImageAlignBottomLeft = 6; +CPImageAlignBottomRight = 7; +CPImageAlignRight = 8; + var CPImageViewShadowBackgroundColor = nil; var LEFT_SHADOW_INSET = 3.0, @@ -52,14 +62,15 @@ var LEFT_SHADOW_INSET = 3.0, */ @implementation CPImageView : CPControl { - DOMElement _DOMImageElement; + DOMElement _DOMImageElement; - BOOL _hasShadow; - CPView _shadowView; + BOOL _hasShadow; + CPView _shadowView; - BOOL _isEditable; + BOOL _isEditable; - CGRect _imageRect; + CGRect _imageRect; + CPImageAlignment _imageAlignment; } - (id)initWithFrame:(CGRect)aFrame @@ -191,6 +202,30 @@ var LEFT_SHADOW_INSET = 3.0, [self hideOrDisplayContents]; } +/*! + Sets the type of image alignment that should be used to + render the image. + @param anImageAlignment the type of scaling to use +*/ +- (void)setImageAlignment:(CPImageAlignment)anImageAlignment +{ + if (_imageAlignment == anImageAlignment) + return; + + _imageAlignment = anImageAlignment; + + if (![self image]) + return; + + [self setNeedsLayout]; + [self setNeedsDisplay:YES]; +} + +- (unsigned)imageAlignment +{ + return _imageAlignment; +} + /*! Sets the type of image scaling that should be used to render the image. @@ -318,8 +353,49 @@ var LEFT_SHADOW_INSET = 3.0, #endif } - var x = (boundsWidth - width) / 2.0, - y = (boundsHeight - height) / 2.0; + var x, y; + + switch (_imageAlignment) + { + case CPImageAlignLeft: + case CPImageAlignTopLeft: + case CPImageAlignBottomLeft: + x = 0.0; + break; + + case CPImageAlignRight: + case CPImageAlignTopRight: + case CPImageAlignBottomRight: + x = boundsWidth - width; + break; + + case CPImageAlignCenter: + case CPImageAlignTop: + case CPImageAlignBottom: + x = (boundsWidth - width) / 2.0; + break; + } + + switch (_imageAlignment) + { + case CPImageAlignTop: + case CPImageAlignTopLeft: + case CPImageAlignTopRight: + y = 0.0; + break; + + case CPImageAlignBottom: + case CPImageAlignBottomLeft: + case CPImageAlignBottomRight: + y = boundsHeight - height; + break; + + case CPImageAlignLeft: + case CPImageAlignRight: + case CPImageAlignCenter: + y = (boundsHeight - height) / 2.0; + break; + } #if PLATFORM(DOM) CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y); @@ -380,10 +456,11 @@ var LEFT_SHADOW_INSET = 3.0, @end -var CPImageViewImageKey = @"CPImageViewImageKey", - CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", - CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", - CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; +var CPImageViewImageKey = @"CPImageViewImageKey", + CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", + CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey", + CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", + CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; @implementation CPImageView (CPCoding) @@ -416,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", #endif [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]]; + [self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]]; if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO) [self setEditable:YES]; @@ -450,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", _subviews = actualSubviews; [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey]; + [aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey]; if (_isEditable) [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey]; diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index aebbc5e89..2d011af98 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -133,7 +133,7 @@ if (_window) return; - [[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]]; + [[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]]; } /*! @@ -424,7 +424,7 @@ if (_windowCibPath) return _windowCibPath; - return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"]; + return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"]; } // Setting and Getting Window Attributes diff --git a/Tools/nib2cib/NSImageView.j b/Tools/nib2cib/NSImageView.j index 2624c2582..9c83e4a7b 100644 --- a/Tools/nib2cib/NSImageView.j +++ b/Tools/nib2cib/NSImageView.j @@ -34,6 +34,7 @@ var cell = [aCoder decodeObjectForKey:@"NSCell"]; [self setImageScaling:[cell imageScaling]]; + [self setImageAlignment:[cell imageAlignment]]; _isEditable = [cell isEditable]; } @@ -92,7 +93,7 @@ NSImageScalingToCPImageScaling[NSImageScaleProportionallyUpOrDown] = CPScalePro @implementation NSImageCell : NSCell { BOOL _animates @accessors; - NSImageAlignment _imageAlignment @accessors; + NSImageAlignment _imageAlignment @accessors(readonly, getter=imageAlignment); NSImageScaling _imageScaling @accessors(readonly, getter=imageScaling); NSImageFrameStyle _frameStyle @accessors; } From 421ae6b3162ec05da3d9c4b9d687367764f213d8 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 10 Jun 2010 10:41:15 -0700 Subject: [PATCH 011/356] Make CPButton archive its key equivalents, and make nib2cib support the feature. --- AppKit/CPButton.j | 14 +++++++++++++- Objective-J/CFPropertyList.js | 12 +++++++++--- Tools/nib2cib/Converter.j | 6 +++--- Tools/nib2cib/NSButton.j | 9 +++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index b8997986c..744de7a29 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -629,7 +629,9 @@ var CPButtonImageKey = @"CPButtonImageKey", CPButtonTitleKey = @"CPButtonTitleKey", CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey", CPButtonIsBorderedKey = @"CPButtonIsBorderedKey", - CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey"; + CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey", + CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey", + CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey"; @implementation CPButton (CPCoding) @@ -653,6 +655,11 @@ var CPButtonImageKey = @"CPButtonImageKey", [self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]]; + if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey]) + [self setKeyEquivalent:CFData.decodeBase64ToString([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; + + [self setKeyEquivalentModifierMask:[aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey]]; + [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -675,6 +682,11 @@ var CPButtonImageKey = @"CPButtonImageKey", [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey]; [aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey]; + + if (_keyEquivalent) + [aCoder encodeObject:CFData.encodeBase64String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; + + [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey]; } @end diff --git a/Objective-J/CFPropertyList.js b/Objective-J/CFPropertyList.js index 39ba97e13..5faeb473b 100644 --- a/Objective-J/CFPropertyList.js +++ b/Objective-J/CFPropertyList.js @@ -306,6 +306,8 @@ var XML_XML = "xml", #define PARENT_NODE(anXMLNode) (anXMLNode.parentNode) #define DOCUMENT_ELEMENT(aDocument) (aDocument.documentElement) +#define HAS_ATTRIBUTE_VALUE(anXMLNode, anAttributeName, aValue) (anXMLNode.getAttribute(anAttributeName) === aValue) + #define IS_OF_TYPE(anXMLNode, aType) (NODE_NAME(anXMLNode) === aType) #define IS_PLIST(anXMLNode) IS_OF_TYPE(anXMLNode, PLIST_PLIST) @@ -559,13 +561,17 @@ CFPropertyList.propertyListFromXML = function(/*String | XMLNode*/ aStringOrXMLN case PLIST_DICTIONARY: object = new CFMutableDictionary(); containers.push(object); break; - + case PLIST_NUMBER_REAL: object = parseFloat(CHILD_VALUE(XMLNode)); break; case PLIST_NUMBER_INTEGER: object = parseInt(CHILD_VALUE(XMLNode), 10); break; - - case PLIST_STRING: object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + + case PLIST_STRING: if (HAS_ATTRIBUTE_VALUE(XMLNode, "type", "base64")) + object = FIRST_CHILD(XMLNode) ? CFData.decodeBase64ToString(CHILD_VALUE(XMLNode)) : ""; + else + object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + break; case PLIST_BOOLEAN_TRUE: object = YES; diff --git a/Tools/nib2cib/Converter.j b/Tools/nib2cib/Converter.j index 46eb0036a..88175bb48 100644 --- a/Tools/nib2cib/Converter.j +++ b/Tools/nib2cib/Converter.j @@ -121,9 +121,9 @@ ConverterConversionException = @"ConverterConversionException"; else plistContents = plistContents.replace(/\\s*CF\$UID\s*\<\/key\>/g, "CP$UID"); - plistContents = plistContents.replace(/\u001b/g, function(c) { - CPLog.warn("Warning: Stripping character 0x"+c.charCodeAt(0).toString(16)); - return ""; + plistContents = plistContents.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]<\/string>/g, function(c) { + CPLog.warn("Warning: Converting character 0x"+c.charCodeAt(8).toString(16)+" to base64 representation"); + return ""+CFData.encodeBase64String(c.charAt(8))+""; }); return [CPData dataWithRawString:plistContents]; diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 9c13724e4..130e4f395 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -180,6 +180,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; } } + [self setKeyEquivalent:[cell keyEquivalent]]; + [self setKeyEquivalentModifierMask:[cell keyEquivalentModifierMask]]; + return [self NS_initWithCoder:aCoder]; } @@ -203,6 +206,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; CPString _title @accessors(readonly, getter=title); CPImage _alternateImage @accessors(readonly, getter=alternateImage); + + CPString _keyEquivalent @accessors(readonly, getter=keyEquivalent); + unsigned _keyEquivalentModifierMask @accessors(readonly, getter=keyEquivalentModifierMask); } - (id)initWithCoder:(CPCoder)aCoder @@ -223,6 +229,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _objectValue = [self state]; _alternateImage = [aCoder decodeObjectForKey:@"NSAlternateImage"]; + + _keyEquivalent = [aCoder decodeObjectForKey:@"NSKeyEquivalent"]; + _keyEquivalentModifierMask = buttonFlags2 >> 8; } return self; From 51825db71699ae12de534f48b6194c85bc170235 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 14 Feb 2010 22:52:47 -0300 Subject: [PATCH 012/356] Fixed: [CPDate description] did not generate a correct date for users in timezones with a negative timezone offset. --- Foundation/CPDate.j | 5 +++-- Tests/Foundation/CPDateTest.j | 37 ++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index 6340ef48c..cba9ec382 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -177,10 +177,11 @@ var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); */ - (CPString)description { - var hours = Math.floor(self.getTimezoneOffset() / 60), + var positive = self.getTimezoneOffset() >= 0, + hours = FLOOR(self.getTimezoneOffset() / 60), minutes = self.getTimezoneOffset() - hours * 60; - return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d +%02d%02d", self.getFullYear(), self.getMonth() + 1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), hours, minutes]; + return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d %s%02d%02d", self.getFullYear(), self.getMonth()+1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), positive ? "+" : "-", ABS(hours), ABS(minutes)]; } - (id)copy diff --git a/Tests/Foundation/CPDateTest.j b/Tests/Foundation/CPDateTest.j index 4668d37af..62d9600b2 100644 --- a/Tests/Foundation/CPDateTest.j +++ b/Tests/Foundation/CPDateTest.j @@ -62,15 +62,46 @@ - (void)testDescription { - // Unfortunately the result will be different depending on the testing machine's timezone. + // Unfortunately the result will be different depending on the testing machine's timezone, so + // this test turns out to be more complex than the code tested. We can't just reuse the + // original code as then we'd have exactly the same bugs. var date = [CPDate dateWithTimeIntervalSince1970: 1234567890], + expectedDay = 13, expectedHour = 23, expectedMinute = 31, + offsetPositive = date.getTimezoneOffset() >= 0, offsetHours = Math.floor(date.getTimezoneOffset() / 60), offsetMinutes = date.getTimezoneOffset() - offsetHours * 60, - expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes]; + expectedString; + expectedHour -= offsetHours; + expectedMinute -= offsetMinutes; + if (expectedMinute < 0) + { + expectedMinute += 60; + expectedHour--; + } + else if (expectedMinute > 59) + { + expectedMinute -= 60; + expectedHour++; + } + if (expectedHour < 0) + { + expectedHour += 24; + expectedDay--; + } + else if (expectedHour > 23) + { + expectedHour -= 24; + expectedDay++; + } - [self assert:expectedString equals:[date description]]; + if (offsetPositive) + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 +%02d%02d", expectedDay, expectedHour, expectedMinute, offsetHours, offsetMinutes]; + else + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 -%02d%02d", expectedDay, expectedHour, expectedMinute, ABS(offsetHours), ABS(offsetMinutes)]; + + [self assert:expectedString equals: [date description]]; } - (void)testCopy From 17669fd09d13efe1cc097bd04eda48b7a07e0f9a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 17:24:13 -0400 Subject: [PATCH 013/356] Optimized _triggersKeyEquivalent for a 6.5% performance gain in the CPKeyEquivalentPerformance test. --- AppKit/CPEvent.j | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index 0fca38549..cf62a7597 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -178,7 +178,8 @@ CPDOMEventTouchEnd = "touchend"; CPDOMEventTouchCancel = "touchcancel"; var _CPEventPeriodicEventPeriod = 0, - _CPEventPeriodicEventTimer = nil; + _CPEventPeriodicEventTimer = nil, + _CPEventUpperCaseRegex = new RegExp("[A-Z]"); /*! @ingroup appkit @@ -521,10 +522,7 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask { - var characters = [self charactersIgnoringModifiers], - modifierFlags = [self modifierFlags]; - - if (new RegExp("[A-Z]").test(aKeyEquivalent)) + if (_CPEventUpperCaseRegex.test(aKeyEquivalent)) aKeyEquivalentModifierMask |= CPShiftKeyMask; if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask)) @@ -533,10 +531,10 @@ var _CPEventPeriodicEventPeriod = 0, aKeyEquivalentModifierMask &= ~CPCommandKeyMask; } - if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) + if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) return NO; - return [characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; + return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; } - (BOOL)_couldBeKeyEquivalent From 5ed475eeddc3de4cf473586c6e4479f88e053d28 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 14:15:27 -0400 Subject: [PATCH 014/356] Slightly faster _couldBeKeyEquivalent (1% of runtime in 3000 calls). Performance test included. --- AppKit/CPEvent.j | 27 ++++---- Tests/AppKit/CPKeyEquivalentPerformance.j | 76 +++++++++++++++++++++++ 2 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 Tests/AppKit/CPKeyEquivalentPerformance.j diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index cf62a7597..b2b62fa00 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -21,6 +21,7 @@ */ @import +@import "CPText.j" #include "CoreGraphics/CGGeometry.h" @@ -539,22 +540,20 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_couldBeKeyEquivalent { - // FIXME: More cases? Space? - return _type === CPKeyDown && - ((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) && - [_characters length] > 0) || - [self _hasActionCharacter]); -} + if (_type !== CPKeyDown) + return NO; -- (BOOL)_hasActionCharacter -{ - var characters = [self characters], - characterCount = [characters length]; + var characterCount = _characters.length; + + if (!characterCount) + return NO; + + if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) + return YES; for(var i=0; i +@import +@import +@import + +[CPApplication sharedApplication]; + +@implementation CPKeyEquivalentPerformance : OJTestCase + +- (void)testKeyEquivalentSpeed +{ + var REPEATS = 1000, + theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,200,150) + styleMask:CPWindowNotSizable], + contentView = [theWindow contentView], + subView1 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + subView2 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + button1 = [CPButton buttonWithTitle:"when"], + button2 = [CPButton buttonWithTitle:"you have eliminated"], + button3 = [CPButton buttonWithTitle:"the impossible"]; + + [contentView addSubview:subView1]; + [contentView addSubview:subView2]; + [subView1 addSubview:button1]; + [subView2 addSubview:button2]; + [subView2 addSubview:button3]; + + [button1 setTarget:self]; + [button1 setAction:@selector(clicked:)]; + [button1 setKeyEquivalent:"a"]; + [button1 setKeyEquivalentModifierMask:CPControlKeyMask]; + button1.clicks = 0; + + [button2 setTarget:self]; + [button2 setAction:@selector(clicked:)]; + [button2 setKeyEquivalent:"a"]; + [button2 setKeyEquivalentModifierMask:CPAlternateKeyMask|CPCommandKeyMask]; + button2.clicks = 0; + + [button3 setTarget:self]; + [button3 setAction:@selector(clicked:)]; + [button3 setKeyEquivalent:"A"]; + [button3 setKeyEquivalentModifierMask:CPControlKeyMask]; + button3.clicks = 0; + + var start = (new Date).getTime(); + + for (var i=0; i Date: Thu, 10 Jun 2010 13:29:47 -0700 Subject: [PATCH 015/356] Slight switch statement change so that nil/0 are treated equivalently. --- AppKit/CPImageView.j | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index ab9722cae..017b59ad3 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -368,10 +368,8 @@ var LEFT_SHADOW_INSET = 3.0, case CPImageAlignBottomRight: x = boundsWidth - width; break; - - case CPImageAlignCenter: - case CPImageAlignTop: - case CPImageAlignBottom: + + default: x = (boundsWidth - width) / 2.0; break; } @@ -389,10 +387,8 @@ var LEFT_SHADOW_INSET = 3.0, case CPImageAlignBottomRight: y = boundsHeight - height; break; - - case CPImageAlignLeft: - case CPImageAlignRight: - case CPImageAlignCenter: + + default: y = (boundsHeight - height) / 2.0; break; } From 443e23e348e578db3133f9b653fc538ec6a437bc Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 9 Jun 2010 19:28:42 -0700 Subject: [PATCH 016/356] Without the commas, these create global variables --- AppKit/CPViewAnimation.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AppKit/CPViewAnimation.j b/AppKit/CPViewAnimation.j index b1bc4d414..594b638a2 100644 --- a/AppKit/CPViewAnimation.j +++ b/AppKit/CPViewAnimation.j @@ -79,9 +79,9 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut"; while (animationIndex--) { var dictionary = [_viewAnimations objectAtIndex:animationIndex], - view = [self _targetView:dictionary] - startFrame = [self _startFrame:dictionary] - endFrame = [self _endFrame:dictionary] + view = [self _targetView:dictionary], + startFrame = [self _startFrame:dictionary], + endFrame = [self _endFrame:dictionary], differenceFrame = _CGRectMakeZero(); differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; From 1899250a530115543729ce59f6eabb44a0a10b13 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 9 Jun 2010 19:29:04 -0700 Subject: [PATCH 017/356] Semicolons are nice... --- AppKit/CPCollectionView.j | 2 +- AppKit/CPColor.j | 2 +- AppKit/CPCursor.j | 2 +- AppKit/CPKeyValueBinding.j | 2 +- AppKit/CPMenu/_CPMenuManager.j | 2 +- AppKit/CPMenuItem/_CPMenuItemStandardView.j | 2 +- AppKit/CPMenuItem/_CPMenuItemView.j | 2 +- AppKit/CPSplitView.j | 2 +- AppKit/CPTableView.j | 6 +++--- AppKit/CPView.j | 2 +- AppKit/CPWindow/CPWindow.j | 6 +++--- AppKit/Cib/CPCib.j | 2 +- CommonJS/lib/cappuccino/cib-analysis-tools.j | 4 ++-- Foundation/CPArray.j | 2 +- Foundation/CPKeyValueObserving.j | 6 +++--- Foundation/CPObject.j | 2 +- Foundation/CPTimer.j | 2 +- 17 files changed, 24 insertions(+), 24 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 11d4b2ed6..80957124c 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -313,7 +313,7 @@ [_items[index] setSelected:YES]; if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) - [_delegate collectionViewDidChangeSelection:self] + [_delegate collectionViewDidChangeSelection:self]; } /*! diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index b6eda360c..3203257bf 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -422,7 +422,7 @@ var cachedBlackColor, parseInt(parts[1], 10) / 255.0, parseInt(parts[2], 10) / 255.0, parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0 - ] + ]; _cssString = aString; diff --git a/AppKit/CPCursor.j b/AppKit/CPCursor.j index 45b3f1ab8..d550fb10c 100755 --- a/AppKit/CPCursor.j +++ b/AppKit/CPCursor.j @@ -197,7 +197,7 @@ var currentCursor = nil, + (void)unhide { - [self _setCursorCSS:[currentCursor _cssString]] + [self _setCursorCSS:[currentCursor _cssString]]; } + (void)setHiddenUntilMouseMoves:(BOOL)flag diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 09ae8a59e..3aabc98a6 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -108,7 +108,7 @@ var CPBindingOperationAnd = 0, count = allKeys.length; while (count--) - [anObject unbind:[bindings objectForKey:allKeys[count]]] + [anObject unbind:[bindings objectForKey:allKeys[count]]]; [bindingsMap removeObjectForKey:[anObject hash]]; } diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index e022f8ddc..18d1021e1 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -96,7 +96,7 @@ var SharedMenuManager = nil; // Close Menu Event. if (type === CPAppKitDefined) - return [self completeTracking] + return [self completeTracking]; [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES]; diff --git a/AppKit/CPMenuItem/_CPMenuItemStandardView.j b/AppKit/CPMenuItem/_CPMenuItemStandardView.j index db15e5417..63777e96f 100644 --- a/AppKit/CPMenuItem/_CPMenuItemStandardView.j +++ b/AppKit/CPMenuItem/_CPMenuItemStandardView.j @@ -39,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil, SUBMENU_INDICATOR_COLOR = [CPColor grayColor]; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPMenuItem/_CPMenuItemView.j b/AppKit/CPMenuItem/_CPMenuItemView.j index d4ef798f0..7b5438a17 100644 --- a/AppKit/CPMenuItem/_CPMenuItemView.j +++ b/AppKit/CPMenuItem/_CPMenuItemView.j @@ -43,7 +43,7 @@ var _CPMenuItemSelectionColor = nil, return; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 70f1a9282..4a90dcf99 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -152,7 +152,7 @@ var CPSplitViewHorizontalImage = nil, _isPaneSplitter = shouldBePaneSplitter; if(_DOMDividerElements[_drawingDivider]) - [self _setupDOMDivider] + [self _setupDOMDivider]; // The divider changes size when pane splitter mode is toggled, so the // subviews need to change size too. diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index c8bac1aae..3a2b0f0d9 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -654,9 +654,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return; _sourceListActiveGradient = [aDictionary valueForKey:CPSourceListGradient]; - _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor] + _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor]; _sourceListActiveBottomLineColor = [aDictionary valueForKey:CPSourceListBottomLineColor]; - [self setNeedsDisplay:YES] + [self setNeedsDisplay:YES]; } /*! @@ -3481,7 +3481,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; - _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey] + _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]; _alternatingRowBackgroundColors = [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]]; diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 3085a06fe..56025cd47 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1679,7 +1679,7 @@ setBoundsOrigin: var theWindow = [self window]; [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 00cd3b8de..caf713d63 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1600,7 +1600,7 @@ CPTexturedBackgroundWindowMask if (!pasteboardTypes) return; - [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes] + [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]; if ([_inclusiveRegisteredDraggedTypes count] === 0) _inclusiveRegisteredDraggedTypes = nil; @@ -1631,7 +1631,7 @@ CPTexturedBackgroundWindowMask return; [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; @@ -1644,7 +1644,7 @@ CPTexturedBackgroundWindowMask - (CPArray)registeredDraggedTypes { if (!_registeredDraggedTypesArray) - _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects] + _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; return _registeredDraggedTypesArray; } diff --git a/AppKit/Cib/CPCib.j b/AppKit/Cib/CPCib.j index f9a3eeafc..5cc8e4fd2 100644 --- a/AppKit/Cib/CPCib.j +++ b/AppKit/Cib/CPCib.j @@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects]; - [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; diff --git a/CommonJS/lib/cappuccino/cib-analysis-tools.j b/CommonJS/lib/cappuccino/cib-analysis-tools.j index cab6a919a..2427987f8 100644 --- a/CommonJS/lib/cappuccino/cib-analysis-tools.j +++ b/CommonJS/lib/cappuccino/cib-analysis-tools.j @@ -17,7 +17,7 @@ function findCibClassDependencies(cibPath) { } // make sure CPApp is init'd - [CPApplication sharedApplication] + [CPApplication sharedApplication]; try { var x = [cib pressInstantiate]; @@ -61,7 +61,7 @@ function findCibClassDependencies(cibPath) { var topLevelObjects = nil;//[anExternalNameTable objectForKey:CPCibTopLevelObjects]; - [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 70d33f9db..27acbd1f2 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -796,7 +796,7 @@ */ - (CPArray)sortedArrayUsingSelector:(SEL)aSelector { - var sorted = [self copy] + var sorted = [self copy]; [sorted sortUsingSelector:aSelector]; diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 66d08fbb0..12f2f6e51 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -738,7 +738,7 @@ var _kvoInsertMethodForMethod = function _kvoInsertMethodForMethod(theKey, theMe { [self willChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, object, index); - [self didChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } @@ -748,7 +748,7 @@ var _kvoReplaceMethodForMethod = function _kvoReplaceMethodForMethod(theKey, the { [self willChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, index, object); - [self didChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } @@ -758,7 +758,7 @@ var _kvoRemoveMethodForMethod = function _kvoRemoveMethodForMethod(theKey, theMe { [self willChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, index); - [self didChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j index c518f4f70..34d023421 100644 --- a/Foundation/CPObject.j +++ b/Foundation/CPObject.j @@ -548,7 +548,7 @@ CPLog(@"Got some class: %@", inst); objj_class.prototype.toString = objj_object.prototype.toString = function() { if (this.isa && class_getInstanceMethod(this.isa, "description") != NULL) - return [this description] + return [this description]; else return String(this) + " (-description not implemented)"; } diff --git a/Foundation/CPTimer.j b/Foundation/CPTimer.j index 6e14ba46a..5c25f1c59 100644 --- a/Foundation/CPTimer.j +++ b/Foundation/CPTimer.j @@ -62,7 +62,7 @@ */ + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat { - var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat] + var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat]; //add to the runloop [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode]; From 1edb0bcc4a8204d1d08773ed279bfb47b2b654ce Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 10 Jun 2010 16:13:48 -0700 Subject: [PATCH 018/356] Fix for null key equivalents. --- AppKit/CPEvent.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index b2b62fa00..f50c15130 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -523,6 +523,9 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask { + if (!aKeyEquivalent) + return NO; + if (_CPEventUpperCaseRegex.test(aKeyEquivalent)) aKeyEquivalentModifierMask |= CPShiftKeyMask; From 9ff056f07338c5b2ad2d7c0e1cbd88355c18b231 Mon Sep 17 00:00:00 2001 From: Derek Hammer Date: Thu, 10 Jun 2010 17:03:43 -0500 Subject: [PATCH 019/356] Making the DisclosureButton a little more subtle. Adding shadow to the disclosure buttons. --- AppKit/CPOutlineView.j | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 06812521a..f3bb21bac 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -1245,13 +1245,34 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt CGContextAddLineToPoint(context, 9.0, 0.0); CGContextAddLineToPoint(context, 4.5, 8.0); CGContextAddLineToPoint(context, 0.0, 0.0); - + CGContextClosePath(context); - var isHighlighted = [self hasThemeState:CPThemeStateHighlighted]; - var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]); - - CGContextSetFillColor(context, color); + CGContextSetFillColor(context, + colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected], + [self hasThemeState:CPThemeStateHighlighted])); CGContextFillPath(context); + + + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0.0, 0.0); + if(_angle === 0.0) { + CGContextAddLineToPoint(context, 4.5, 8.0); + CGContextAddLineToPoint(context, 9.0, 0.0); + } else { + CGContextAddLineToPoint(context, 4.5, 8.0); + } + CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]); + CGContextStrokePath(context); } @end + +var colorForDisclosureTriangle = function(isSelected, isHighlighted) { + return isSelected + ? (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0]) + : (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]); +} From f62d81e79f855728de286440dbd57e3038e5a411 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 10 Jun 2010 22:37:52 -0500 Subject: [PATCH 020/356] Fix for nib2cib breaking with an emptry class implementation. --- AppKit/CPText.j | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AppKit/CPText.j b/AppKit/CPText.j index 1ef33efe1..5458583ec 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -31,10 +31,9 @@ CPBackspaceCharacter = "\u0008"; CPBackTabCharacter = "\u0019"; CPDeleteCharacter = "\u007f"; -@implementation CPText : CPView +/*@implementation CPText : CPView { } -@end - +@end*/ From dcec14decdee22afb2219ba0b83466c4c72185e1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 20:49:43 -0400 Subject: [PATCH 021/356] Fixed: delete (backspace) and forward delete were switched as compared to Cocoa. Fixed: delete could not be used as a key equivalent without a modifier. --- AppKit/CPEvent.j | 1 + AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index f50c15130..581c3349a 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -560,6 +560,7 @@ var _CPEventPeriodicEventPeriod = 0, { case CPBackspaceCharacter: case CPDeleteCharacter: + case CPDeleteFunctionKey: case CPTabCharacter: case CPCarriageReturnCharacter: case CPEscapeFunctionKey: diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index e5bd7a19d..2132d0c80 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -144,8 +144,8 @@ var KeyCodesToPrevent = {}, KeyCodesToPrevent[CPKeyCodes.A] = YES; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPBackspaceCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; From 44555ac72405e2b8446be25f804f5950e9f99e7f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 20:38:41 -0400 Subject: [PATCH 022/356] UTF compatible CFData base64 string encoder and decoder. Use it for CPButton key equivalent archiving. Also ordered CPText.j constants by value and removed the empty CPText class definition as it caused errors with nib2cib. Fixed: the key equivalent for forward delete (CPDeleteFunctionKey, \uF728) was transformed to '(' (\u0028) when archived and unarchived. --- AppKit/CPButton.j | 4 ++-- AppKit/CPText.j | 15 ++++----------- Objective-J/CFData.js | 30 ++++++++++++++++++++++++++++++ Tests/Objective-J/base64Test.j | 8 +++++++- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 744de7a29..75206a02c 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -656,7 +656,7 @@ var CPButtonImageKey = @"CPButtonImageKey", [self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]]; if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey]) - [self setKeyEquivalent:CFData.decodeBase64ToString([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; + [self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; [self setKeyEquivalentModifierMask:[aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey]]; @@ -684,7 +684,7 @@ var CPButtonImageKey = @"CPButtonImageKey", [aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey]; if (_keyEquivalent) - [aCoder encodeObject:CFData.encodeBase64String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; + [aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey]; } diff --git a/AppKit/CPText.j b/AppKit/CPText.j index 5458583ec..4ac6354d4 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -22,18 +22,11 @@ @import "CPView.j" -CPTabCharacter = "\u0009"; -CPFormFeedCharacter = "\u000c"; -CPNewlineCharacter = "\u000a"; -CPCarriageReturnCharacter = "\u000d"; CPEnterCharacter = "\u0003"; CPBackspaceCharacter = "\u0008"; +CPTabCharacter = "\u0009"; +CPNewlineCharacter = "\u000a"; +CPFormFeedCharacter = "\u000c"; +CPCarriageReturnCharacter = "\u000d"; CPBackTabCharacter = "\u0019"; CPDeleteCharacter = "\u007f"; - -/*@implementation CPText : CPView -{ - -} - -@end*/ diff --git a/Objective-J/CFData.js b/Objective-J/CFData.js index 51743a5a9..7898756f7 100644 --- a/Objective-J/CFData.js +++ b/Objective-J/CFData.js @@ -227,6 +227,11 @@ CFData.decodeBase64ToString = function(input, strip) return CFData.bytesToString(CFData.decodeBase64ToArray(input, strip)); } +CFData.decodeBase64ToUtf16String = function(input, strip) +{ + return CFData.bytesToUtf16String(CFData.decodeBase64ToArray(input, strip)); +} + CFData.bytesToString = function(bytes) { // This is relatively efficient, I think: @@ -242,3 +247,28 @@ CFData.encodeBase64String = function(input) return CFData.encodeBase64Array(temp); } + +CFData.bytesToUtf16String = function(bytes) +{ + // Strings are encoded with 16 bits per character. + var temp = []; + for (var i = 0; i < bytes.length; i+=2) + temp.push(bytes[i+1] << 8 | bytes[i]); + // This is relatively efficient, I think: + return String.fromCharCode.apply(NULL, temp); +} + + +CFData.encodeBase64Utf16String = function(input) +{ + // charCodeAt returns UTF-16. + var temp = []; + for (var i = 0; i < input.length; i++) + { + var c = input.charCodeAt(i); + temp.push(input.charCodeAt(i) & 0xFF); + temp.push((input.charCodeAt(i) & 0xFF00) >> 8); + } + + return CFData.encodeBase64Array(temp); +} diff --git a/Tests/Objective-J/base64Test.j b/Tests/Objective-J/base64Test.j index 43186ff9b..bce099d2c 100644 --- a/Tests/Objective-J/base64Test.j +++ b/Tests/Objective-J/base64Test.j @@ -42,10 +42,16 @@ var base64TestStrings = [ { var result = CFData.decodeBase64ToArray(base64TestStrings[i][1]), expected = base64TestStrings[i][0]; - + for (var j = 0; j < expected.length || j < result.length; j++) [self assert:result[j] equals:expected.charCodeAt(j)]; } } +- (void)test_CFData_encodeUtfString +{ + var utfTest = "\uF728"; // A common key equivalent. + [self assert:CFData.decodeBase64ToUtf16String(CFData.encodeBase64Utf16String(utfTest)) equals:utfTest]; +} + @end From 854481e395bdcf39285ef683f5da8d0d6d375ad9 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 13:03:07 -0400 Subject: [PATCH 023/356] Fixes #710. Treat \r and \n key equivalents as the same key (return). --- AppKit/CPEvent.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index 581c3349a..6c05c96d6 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -538,6 +538,10 @@ var _CPEventPeriodicEventPeriod = 0, if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) return NO; + // Treat \r and \n as the same key equivalent. See issue #710. + if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter) + return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent; + return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; } @@ -563,6 +567,7 @@ var _CPEventPeriodicEventPeriod = 0, case CPDeleteFunctionKey: case CPTabCharacter: case CPCarriageReturnCharacter: + case CPNewlineCharacter: case CPEscapeFunctionKey: case CPPageUpFunctionKey: case CPPageDownFunctionKey: From c28222e04daeda132e38e0677f11009fa25662d4 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 12:38:25 -0400 Subject: [PATCH 024/356] Test CPResponder's interpretKeyEvents in preparation for rewrite. --- Tests/AppKit/CPResponderTest.j | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Tests/AppKit/CPResponderTest.j diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j new file mode 100644 index 000000000..891d3076b --- /dev/null +++ b/Tests/AppKit/CPResponderTest.j @@ -0,0 +1,71 @@ +@import +@import +@import + +@import + +[CPApplication sharedApplication] + +@implementation CPResponderTest : OJTestCase +{ + CPWindow theWindow; + CPResponder responder; +} + +- (void)setUp +{ + responder = [TestResponder new]; + responder.doCommandCalls = []; +} + +- (void)testInterpretKeyEvents +{ + var tests = [ + CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(pageUp:), + CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(pageDown:), + CPKeyCodes.LEFT, CPLeftArrowFunctionKey, @selector(moveLeft:), + CPKeyCodes.RIGHT, CPRightArrowFunctionKey, @selector(moveRight:), + CPKeyCodes.UP, CPUpArrowFunctionKey, @selector(moveUp:), + CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), + CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), + CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), + CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), + CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) + ]; + + for (var i=0; i Date: Fri, 11 Jun 2010 12:47:05 -0400 Subject: [PATCH 025/356] Don't test keyCodes directly in CPResponder now that we have proper key equivalent characters. --- AppKit/CPResponder.j | 64 ++++++++++++++++------------------ Tests/AppKit/CPResponderTest.j | 1 + 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 746e4e992..4b81635d1 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -22,7 +22,6 @@ @import - CPDeleteKeyCode = 8; CPTabKeyCode = 9; CPReturnKeyCode = 13; @@ -39,7 +38,7 @@ CPDeleteForwardKeyCode = 46; /*! @ingroup appkit @class CPResponder - + Subclasses of CPResonder can be part of the responder chain. */ @implementation CPResponder : CPObject @@ -107,39 +106,36 @@ CPDeleteForwardKeyCode = 46; { var event = events[index]; - switch([event keyCode]) + switch([[event characters] characterAtIndex:0]) { - case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)]; - break; - case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)]; - break; - case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)]; - break; - case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)]; - break; - case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)]; - break; - case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)]; - break; - case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)]; - break; - case CPReturnKeyCode: - case 3: [self doCommandBySelector:@selector(insertLineBreak:)]; - break; - - case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)]; - break; + case CPPageUpFunctionKey: [self doCommandBySelector:@selector(pageUp:)]; + break; + case CPPageDownFunctionKey: [self doCommandBySelector:@selector(pageDown:)]; + break; + case CPLeftArrowFunctionKey: [self doCommandBySelector:@selector(moveLeft:)]; + break; + case CPRightArrowFunctionKey: [self doCommandBySelector:@selector(moveRight:)]; + break; + case CPUpArrowFunctionKey: [self doCommandBySelector:@selector(moveUp:)]; + break; + case CPDownArrowFunctionKey: [self doCommandBySelector:@selector(moveDown:)]; + break; + case CPDeleteCharacter: [self doCommandBySelector:@selector(deleteBackward:)]; + break; + case CPCarriageReturnCharacter: + case CPNewlineCharacter: [self doCommandBySelector:@selector(insertLineBreak:)]; + break; - case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask; + case CPEscapeFunctionKey: [self doCommandBySelector:@selector(cancel:)]; + break; - if (!shift) - [self doCommandBySelector:@selector(insertTab:)]; - else - [self doCommandBySelector:@selector(insertBackTab:)]; + case CPTabCharacter: if (!([event modifierFlags] & CPShiftKeyMask)) + [self doCommandBySelector:@selector(insertTab:)]; + else + [self doCommandBySelector:@selector(insertBackTab:)]; + break; - break; - - default: [self insertText:[event characters]]; + default: [self insertText:[event characters]]; } } } @@ -316,7 +312,7 @@ CPDeleteForwardKeyCode = 46; if([self respondsToSelector:aSelector]) { [self performSelector:aSelector withObject:anObject]; - + return YES; } @@ -367,10 +363,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey"; - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; - + return self; } diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j index 891d3076b..eab226833 100644 --- a/Tests/AppKit/CPResponderTest.j +++ b/Tests/AppKit/CPResponderTest.j @@ -29,6 +29,7 @@ CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), + 0, CPNewlineCharacter, @selector(insertLineBreak:), CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) ]; From 5c5412db67bde3c9f5096a881d6a3266ea87b419 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 00:07:53 -0400 Subject: [PATCH 026/356] Make didChangeValueForKey work even if willChangeValueForKey was not called. --- Foundation/CPKeyValueObserving.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 12f2f6e51..0ff9fdd26 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -426,6 +426,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, } else { + // The isBefore path may not have been called as would happen if didChangeX + // was called alone. + if (!changes) + changes = [CPDictionary new]; + [changes removeObjectForKey:CPKeyValueChangeNotificationIsPriorKey]; var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey]; From fed39694f69093e8deb13222d94f1e90d43fd19a Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sat, 12 Jun 2010 18:23:51 -0700 Subject: [PATCH 027/356] Improve the handling of key window's losing their status. --- AppKit/CPWindow/CPWindow.j | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index caf713d63..41e410a4b 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1942,10 +1942,16 @@ CPTexturedBackgroundWindowMask else { var mainMenu = [CPApp mainMenu], - menuWindow = mainMenu ? mainMenu._menuWindow : nil; + menuBarClass = objj_getClass("_CPMenuBarWindow"), + menuWindow; + for (var i = 0; i < windowCount; i++) { var currentWindow = allWindows[i]; + + if ([currentWindow isKindOfClass:menuBarClass]) + menuWindow = currentWindow; + if (currentWindow === self || currentWindow === menuWindow) continue; @@ -1971,10 +1977,16 @@ CPTexturedBackgroundWindowMask else { var mainMenu = [CPApp mainMenu], - menuWindow = mainMenu ? mainMenu._menuWindow : nil; + menuBarClass = objj_getClass("_CPMenuBarWindow"), + menuWindow; + for (var i = 0; i < windowCount; i++) { var currentWindow = allWindows[i]; + + if ([currentWindow isKindOfClass:menuBarClass]) + menuWindow = currentWindow; + if (currentWindow === self || currentWindow === menuWindow) continue; From 9a3c2d5311a98d15f56733c620528c3981234285 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sat, 12 Jun 2010 17:46:38 -0700 Subject: [PATCH 028/356] Fix for scrolling affecting background windows with NativeHost. Reviewed by me. --- Tools/NativeHost/Application.m | 2 ++ Tools/NativeHost/WebWindow.m | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Tools/NativeHost/Application.m b/Tools/NativeHost/Application.m index 4dbb8a397..2234f307d 100644 --- a/Tools/NativeHost/Application.m +++ b/Tools/NativeHost/Application.m @@ -15,6 +15,8 @@ - (void)sendEvent:(NSEvent *)anEvent { + [WebWindow enableAllWindows]; + NSWindow * window = [anEvent window]; if (!window || [window isKindOfClass:[WebWindow class]]) diff --git a/Tools/NativeHost/WebWindow.m b/Tools/NativeHost/WebWindow.m index 631e73a72..122aa453b 100644 --- a/Tools/NativeHost/WebWindow.m +++ b/Tools/NativeHost/WebWindow.m @@ -18,9 +18,6 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e // It's dangerous to fail in this code: could disable mousedown system-wide. So just try catch it all. @try { - [DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)]; - [DisabledWindows removeAllObjects]; - if (type == kCGEventLeftMouseDown) { CGPoint location = CGEventGetLocation(event); @@ -55,6 +52,12 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e @implementation WebWindow ++ (void)enableAllWindows +{ + [DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)]; + [DisabledWindows removeAllObjects]; +} + + (void)initialize { if (self != [WebWindow class]) @@ -117,8 +120,9 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e [self setBackgroundColor:[NSColor clearColor]]; [self setOpaque:NO]; + [self setIgnoresMouseEvents:NO]; [self setReleasedWhenClosed:YES]; - [super setHasShadow:NO]; + [super setHasShadow:NO]; } return self; From 2f58517ce57366658c5cbc8c29b980137ae8b1df Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 15 Jun 2010 09:28:22 -0700 Subject: [PATCH 029/356] Request headers should be set after the request is re-opened. Closes #701. --- Objective-J/CFHTTPRequest.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Objective-J/CFHTTPRequest.js b/Objective-J/CFHTTPRequest.js index d4007f585..2ef8c721f 100644 --- a/Objective-J/CFHTTPRequest.js +++ b/Objective-J/CFHTTPRequest.js @@ -219,12 +219,6 @@ CFHTTPRequest.prototype.open = function(/*String*/ aMethod, /*String*/ aURL, /*B CFHTTPRequest.prototype.send = function(/*Object*/ aBody) { - for (var i in this._requestHeaders) - { - if (this._requestHeaders.hasOwnProperty(i)) - this._nativeRequest.setRequestHeader(i, this._requestHeaders[i]); - } - if (!this._isOpen) { delete this._nativeRequest.onreadystatechange; @@ -232,6 +226,12 @@ CFHTTPRequest.prototype.send = function(/*Object*/ aBody) this._nativeRequest.onreadystatechange = this._stateChangeHandler; } + for (var i in this._requestHeaders) + { + if (this._requestHeaders.hasOwnProperty(i)) + this._nativeRequest.setRequestHeader(i, this._requestHeaders[i]); + } + if (this._mimeType && "overrideMimeType" in this._nativeRequest) this._nativeRequest.overrideMimeType(this._mimeType); From 16be03b16296ba1f7c4b3b069da08cc48cf9a100 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 15 Jun 2010 01:58:09 -0400 Subject: [PATCH 030/356] If first segment is enabled and mode is one-only, _selectedSegment is correctly set to 0 --- Tools/nib2cib/NSSegmentedControl.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tools/nib2cib/NSSegmentedControl.j b/Tools/nib2cib/NSSegmentedControl.j index 737132f80..df3145d20 100644 --- a/Tools/nib2cib/NSSegmentedControl.j +++ b/Tools/nib2cib/NSSegmentedControl.j @@ -98,6 +98,9 @@ _selectedSegment = [aCoder decodeIntForKey:"NSSelectedSegment"] || -1; _segmentStyle = [aCoder decodeIntForKey:"NSSegmentStyle"]; _trackingMode = [aCoder decodeIntForKey:"NSTrackingMode"] || CPSegmentSwitchTrackingSelectOne; + + if (_trackingMode == CPSegmentSwitchTrackingSelectOne && _selectedSegment == -1) + _selectedSegment = 0; } return self; From 17a8be1ae67c47168fa328ff1712a81d05ccff2d Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 15 Jun 2010 19:20:48 -0700 Subject: [PATCH 031/356] Return the actually last selected row in CPTableView. Closes 716. --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 3a2b0f0d9..e889cfa28 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1020,7 +1020,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (int)selectedRow { - return [_selectedRowIndexes lastIndex]; + return _lastSelectedRow; } - (CPIndexSet)selectedRowIndexes From eaf4fa240f29755271b6b1890994713b2e137220 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 16 Jun 2010 14:16:17 +0200 Subject: [PATCH 032/356] slightly delay triggering the action in CPControl performClick: to make sure the click is always visible --- AppKit/CPControl.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 7de6719c4..3a1ec1200 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -337,13 +337,13 @@ var CPControlBlackColor = [CPColor blackColor]; [self highlight:YES]; [self setState:[self nextState]]; - [self sendAction:[self action] to:[self target]]; [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; } - (void)unhighlightButtonTimerDidFinish:(id)sender { + [self sendAction:[self action] to:[self target]]; [self highlight:NO]; } From f40fc321fe007586aaeb5c30668b8fe2430b3af3 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 16 Jun 2010 14:17:58 +0200 Subject: [PATCH 033/356] Make the window perform it's defaults button's key equivalent after the default keyDown messages are handled --- AppKit/CPButton.j | 20 ++++++++++++++++++++ AppKit/CPWindow/CPWindow.j | 28 +++++++++++++++++----------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 75206a02c..3bc21844b 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -569,9 +569,25 @@ CPButtonStateMixed = CPThemeState("mixed"); */ - (void)setKeyEquivalent:(CPString)aString { + // Check if the key equivalent is the enter key + // Treat \r and \n as the same key equivalent. See issue #710. + if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter) + [[self window] setDefaultButton:self]; + else if ([[self window] defaultButton] === self) + [[self window] setDefaultButton:NO]; + _keyEquivalent = aString || @""; } +- (void)viewWillMoveToWindow:(CPWindow)aWindow +{ + if ([[self window] defaultButton] === self) + [[self window] setDefaultButton:nil]; + + if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter) + [aWindow setDefaultButton:self]; +} + /*! Returns the keyboard shortcut for this button. */ @@ -602,6 +618,10 @@ CPButtonStateMixed = CPThemeState("mixed"); */ - (BOOL)performKeyEquivalent:(CPEvent)anEvent { + // Don't handle the key equivalent for the default window because the window will handle it for us + if ([[self window] defaultButton] === self) + return NO; + if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]]) return NO; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 41e410a4b..effa1788c 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1377,7 +1377,15 @@ CPTexturedBackgroundWindowMask switch (type) { case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; - case CPKeyDown: return [[self firstResponder] keyDown:anEvent]; + + case CPKeyDown: [[self firstResponder] keyDown:anEvent]; + + // Trigger the default button if needed + if (![self disableKeyEquivalentForDefaultButton]) + if ([anEvent _triggersKeyEquivalent:[[self defaultButton] keyEquivalent] withModifierMask:[[self defaultButton] keyEquivalentModifierMask]]) + [[self defaultButton] performClick:self]; + + return; case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; @@ -2250,7 +2258,7 @@ CPTexturedBackgroundWindowMask return NO; } -- (void)performKeyEquivalent:(CPEvent)anEvent +- (BOOL)performKeyEquivalent:(CPEvent)anEvent { // FIXME: should we be starting at the root, in other words _windowView? // The evidence seems to point to no... @@ -2261,14 +2269,11 @@ CPTexturedBackgroundWindowMask { // It's not clear why we do performKeyEquivalent again here... // Perhaps to allow something to happen between sendEvent: and keyDown:? - if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent]) - [self interpretKeyEvents:[anEvent]]; -} + if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) + return; -- (void)insertNewline:(id)sender -{ - if (_defaultButton && _defaultButtonEnabled) - [_defaultButton performClick:nil]; + // Interpret the key events + [self interpretKeyEvents:[anEvent]]; } - (void)insertTab:(id)sender @@ -2381,10 +2386,11 @@ CPTexturedBackgroundWindowMask - (void)setDefaultButton:(CPButton)aButton { + if (_defaultButton === aButton) + return; + [_defaultButton setDefaultButton:NO]; - _defaultButton = aButton; - [_defaultButton setDefaultButton:YES]; } From 1b174b86cadeeeec7e42a6c7afa22dd2ac8b39c1 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 16 Jun 2010 08:14:04 -0700 Subject: [PATCH 034/356] Buttons should also be re-centered after their height is changed in nib2cib. --- Tools/nib2cib/NSButton.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 130e4f395..6bbb426c0 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -93,10 +93,11 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _bezelStyle = CPHUDBezelStyle; } - if ([cell isBordered]) + if ([cell isBordered] && _frame.size.height === 32.0) { CPLog.info("Adjusting CPButton height from " +_frame.size.height+ " / " + _bounds.size.height+" to " + 24); _frame.size.height = 24.0; + _frame.origin.y += 4.0; _bounds.size.height = 24.0; } } From 6a43c544eba40d3912b50b9482e3b0f0306b97fb Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 14 Jun 2010 20:01:30 -0400 Subject: [PATCH 035/356] Added support for reading max rows/columns from cib --- AppKit/CPCollectionView.j | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 80957124c..084686395 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -847,11 +847,13 @@ @end -var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", - CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", - CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", - CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", - CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; +var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", + CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", + CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", + CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey", + CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey", + CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", + CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; @implementation CPCollectionView (CPCoding) @@ -871,6 +873,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); + + _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0; + _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0; _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey]; @@ -898,6 +903,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey]; + [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey]; + [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey]; + [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; From db3514a2c1c9bccf4527a26acad9c5be82071a2f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:40:35 -0400 Subject: [PATCH 036/356] Only allow a single window frame animation at a time; stop the previous animation before starting a new one. This allows e.g. a sheet animating open to 'turn around' and animate right back out. Fixed: if a sheet was closed before it finished animating open, for example by hitting a keyboard equivalent immediately, CPWindow would crash with "Uncaught TypeError: Cannot read property 'sheet' of null". --- AppKit/CPWindow/CPWindow.j | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index effa1788c..7e619bd57 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -320,6 +320,8 @@ var CPWindowSaveImage = nil, CPDictionary _sheetContext; CPWindow _parentView; BOOL _isSheet; + + _CPWindowFrameAnimation _frameAnimation; } /* @@ -659,9 +661,10 @@ CPTexturedBackgroundWindowMask if (shouldAnimate) { - var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + [_frameAnimation stopAnimation]; + _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - [animation startAnimation]; + [_frameAnimation startAnimation]; } else { @@ -2074,11 +2077,12 @@ CPTexturedBackgroundWindowMask - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve { - var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - [animation setDelegate:delegate]; - [animation setAnimationCurve:curve]; - [animation setDuration:duration]; - [animation startAnimation]; + [_frameAnimation stopAnimation]; + _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + [_frameAnimation setDelegate:delegate]; + [_frameAnimation setAnimationCurve:curve]; + [_frameAnimation setDuration:duration]; + [_frameAnimation startAnimation]; } /* @ignore */ From 685c3c985318de263ca70ba66e3137f43bf45333 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 13 Jun 2010 02:13:46 -0400 Subject: [PATCH 037/356] Don't add no-ops to the undo stack when using automatic undo manager mode. This is necessary when used together with bindings since controls issue reverse binding updates whenever editing ends, which would add a 'do nothing' undo entry on the stack in cases where nothing changed. --- Foundation/CPUndoManager.j | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index f07247589..9e15c891b 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -726,6 +726,12 @@ if (_currentGroup == nil) change:(CPDictionary)aChange context:(id)aContext { + // Don't add no-ops to the undo stack. + var before = [aChange valueForKey:CPKeyValueChangeOldKey], + after = [aChange valueForKey:CPKeyValueChangeNewKey]; + if (before === after || [before isEqual:after]) + return; + [[self prepareWithInvocationTarget:anObject] applyChange:[aChange inverseChangeDictionary] toKeyPath:aKeyPath]; From c80735821621fd2a5af4b2609ebbec58803fa46c Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:50:31 -0400 Subject: [PATCH 038/356] Support non Objective-J objects in CPUndoManager's no-op check for auto undo. --- Foundation/CPUndoManager.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index 9e15c891b..dea9c74a4 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -729,7 +729,7 @@ if (_currentGroup == nil) // Don't add no-ops to the undo stack. var before = [aChange valueForKey:CPKeyValueChangeOldKey], after = [aChange valueForKey:CPKeyValueChangeNewKey]; - if (before === after || [before isEqual:after]) + if (before === after || (after !== nil && after.isa && [before isEqual:after])) return; [[self prepareWithInvocationTarget:anObject] From f2c01cbbbdf77f8b8c02719e1ea311f49d8d3562 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:59:37 -0400 Subject: [PATCH 039/356] In CPUndoManager, handle the edge cases if an object changes from being an Objective-J object to being just a JS object. Also handle the case where an Objective-J object could theoretically compare equal to nil - CPNull isEqual:. --- Foundation/CPUndoManager.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index dea9c74a4..7f0b58a83 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -729,7 +729,7 @@ if (_currentGroup == nil) // Don't add no-ops to the undo stack. var before = [aChange valueForKey:CPKeyValueChangeOldKey], after = [aChange valueForKey:CPKeyValueChangeNewKey]; - if (before === after || (after !== nil && after.isa && [before isEqual:after])) + if (before === after || (before !== nil && before.isa && (after === nil || after.isa) && [before isEqual:after])) return; [[self prepareWithInvocationTarget:anObject] From 19d5431f609b3cead32590dc1c372746be108d14 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 16 Jun 2010 08:54:30 -0700 Subject: [PATCH 040/356] Revert "slightly delay triggering the action in CPControl performClick: to make sure the click is always visible" This reverts commit eaf4fa240f29755271b6b1890994713b2e137220. --- AppKit/CPControl.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 3a1ec1200..7de6719c4 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -337,13 +337,13 @@ var CPControlBlackColor = [CPColor blackColor]; [self highlight:YES]; [self setState:[self nextState]]; + [self sendAction:[self action] to:[self target]]; [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; } - (void)unhighlightButtonTimerDidFinish:(id)sender { - [self sendAction:[self action] to:[self target]]; [self highlight:NO]; } From 7414d1407ff279b1fc1953024f96b62a2683fde0 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 16 Jun 2010 13:59:25 -0500 Subject: [PATCH 041/356] Moved tracking of last selected row index to selectRowIndexes: in tableview. --- AppKit/CPTableView.j | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index e889cfa28..f67079a90 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -909,6 +909,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _selectedRowIndexes = [rows copy]; + // update last selected row + _lastSelectedRow = ([rows count] > 0) ? [rows lastIndex] : -1; + [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows // but currently -drawRect: is not implemented here @@ -3268,8 +3271,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } } - _lastSelectedRow = ([newSelection count] > 0) ? aRow : -1; - // if empty selection is not allowed and the new selection has nothing selected, abort if (!_allowsEmptySelection && [newSelection count] === 0) return; From bd06b8a86723239a285e39a298ade347ca9a6332 Mon Sep 17 00:00:00 2001 From: nciagra Date: Wed, 16 Jun 2010 22:02:40 -0400 Subject: [PATCH 042/356] Modifier keys will fire flagsChanged: instead of keyDown: and keyUp:, like Cocoa does. --- AppKit/CPResponder.j | 9 +++++++ AppKit/CPWindow/CPWindow.j | 2 ++ AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 28 ++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 4b81635d1..6836194ec 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -236,6 +236,15 @@ CPDeleteForwardKeyCode = 46; [_nextResponder performSelector:_cmd withObject:anEvent]; } +/*! + Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on). + @param anEvent information about the key press +*/ +- (void)flagsChanged:(CPEvent)anEvent +{ + [_nextResponder performSelector:_cmd withObject:anEvent]; +} + /* FIXME This description is bad. Based on \c anEvent, the receiver should simulate the event. diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 7e619bd57..75650792f 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1379,6 +1379,8 @@ CPTexturedBackgroundWindowMask switch (type) { + case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent]; + case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; case CPKeyDown: [[self firstResponder] keyDown:anEvent]; diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 2132d0c80..430341f97 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -156,6 +156,14 @@ KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +var ModifierKeyCodes = [ + CPKeyCodes.META, + CPKeyCodes.MAC_FF_META, + CPKeyCodes.CTRL, + CPKeyCodes.ALT, + CPKeyCodes.SHIFT +]; + var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; @implementation CPPlatformWindow (DOM) @@ -607,8 +615,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; - (void)keyEvent:(DOMEvent)aDOMEvent { var event, - timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), + timestamp = aDOMEvent.timeStamp || new Date(), + sourceElement = aDOMEvent.target || aDOMEvent.srcElement, windowNumber = [[CPApp keyWindow] windowNumber], modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | @@ -627,7 +635,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; switch (aDOMEvent.type) { case "keydown": // Grab and store the keycode now since it is correct and consistent at this point. - if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap) + if (aDOMEvent.keyCode in MozKeyCodeToKeyCodeMap) _keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode]; else _keyCode = aDOMEvent.keyCode; @@ -639,7 +647,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (_keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = YES; - if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) + if ([ModifierKeyCodes containsObject:_keyCode]) + { + // A modifier key will never fire keypress. We don't need to do any other processing so we just fire it here and break. + event = [CPEvent keyEventWithType:CPFlagsChanged location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil + characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:_keyCode]; + + break; + } + else if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) { //we are simply going to skip all keypress events that use cmd/ctrl key //this lets us be consistent in all browsers and send on the keydown @@ -728,6 +745,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = NO; + if ([ModifierKeyCodes containsObject:keyCode]) + break; + var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); From 96fc34c00ea669fa4570178bdd4135097d9f7837 Mon Sep 17 00:00:00 2001 From: nciagra Date: Wed, 16 Jun 2010 22:03:31 -0400 Subject: [PATCH 043/356] CPResponder -interpretKeyEvents: will only call -insertText: if the Command and Control keys are not being held. --- AppKit/CPResponder.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 6836194ec..9760e5449 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -135,7 +135,8 @@ CPDeleteForwardKeyCode = 46; [self doCommandBySelector:@selector(insertBackTab:)]; break; - default: [self insertText:[event characters]]; + default: if (!([event modifierFlags] & (CPCommandKeyMask | CPControlKeyMask))) + [self insertText:[event characters]]; } } } From f09193ce07e60c3d1e4befee793eb8fdb203d3b9 Mon Sep 17 00:00:00 2001 From: nciagra Date: Thu, 17 Jun 2010 00:17:52 -0400 Subject: [PATCH 044/356] Properly differentiate between special keys and normal keys in key handlers. --- AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 430341f97..0a51a76a0 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -640,7 +640,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; else _keyCode = aDOMEvent.keyCode; - var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase(); + var characters; + + // Is this a special key? + if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0) + characters = KeyCodesToFunctionUnicodeMap[_keyCode]; + + if (!characters) + characters = String.fromCharCode(_keyCode).toLowerCase(); + overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters; // check for caps lock state @@ -713,8 +721,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _lastKey = keyCode; _charCodes[keyCode] = charCode; - var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), - charactersIgnoringModifiers = characters.toLowerCase(); + var characters = overrideCharacters; + // Is this a special key? + if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)) + characters = KeyCodesToFunctionUnicodeMap[charCode]; + + if (!characters) + characters = String.fromCharCode(charCode); + + charactersIgnoringModifiers = characters.toLowerCase(); // FIXME: This isn't correct. It SHOULD include Shift. // Safari won't send proper capitalization during cmd-key events if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive)) @@ -722,7 +737,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags timestamp:timestamp windowNumber:windowNumber context:nil - characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode]; + characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:charCode]; if (isNativePasteEvent) { From 997a305d35849fc20969ec2e7d883c5ac1b84ef6 Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 10:40:15 -0400 Subject: [PATCH 045/356] Added CPKeyBinding for a dynamic key binding system. --- AppKit/AppKit.j | 1 + AppKit/CPKeyBinding.j | 233 ++++++++++++++++++++++++++++++++++++++++++ AppKit/CPResponder.j | 44 +++----- 3 files changed, 248 insertions(+), 30 deletions(-) create mode 100644 AppKit/CPKeyBinding.j diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 1feb31525..9c820be65 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -55,6 +55,7 @@ @import "CPGeometry.j" @import "CPImage.j" @import "CPImageView.j" +@import "CPKeyBinding.j" @import "CPMenu.j" @import "CPMenuItem.j" @import "CPOpenPanel.j" diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j new file mode 100644 index 000000000..e68b16c3c --- /dev/null +++ b/AppKit/CPKeyBinding.j @@ -0,0 +1,233 @@ +/* + * CPKeyBinding.j + * AppKit + * + * Created by Nicholas Small. + * Copyright 2010, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 + + +CPStandardKeyBindings = { + @"@.": @"cancelOperation:", + + @"^a": @"moveToBeginningOfParagraph:", + @"^$a": @"moveToBeginningOfParagraphAndModifySelection:", + @"^b": @"moveBackward:", + @"^$b": @"moveBackwardAndModifySelection:", + @"^~$b": @"moveWordBackwardAndModifySelection:", + @"^d": @"deleteForward:", + @"^e": @"moveToEndOfParagraph:", + @"^$e": @"moveToEndOfParagraphAndModifySelection:", + @"^f": @"moveForward:", + @"^$f": @"moveForwardAndModifySelection:", + @"^~f": @"moveWordForward:", + @"^~$f": @"moveWordForwardAndModifySelection:", + @"^h": @"deleteBackward:", + @"^k": @"deleteToEndOfParagraph:", + @"^l": @"centerSelectionInVisibleArea:", + @"^n": @"moveDown:", + @"^$n": @"moveDownAndModifySelection:", + @"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"], + @"^p": @"moveUp:", + @"^$p": @"moveUpAndModifySelection:", + @"^t": @"transpose:", + @"^v": @"pageDown:", + @"^v": @"pageDownAndModifySelection:", + @"^y": @"yank:" +}; + +CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:"; +CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:"; +CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:"; +CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:"; +CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:"; +CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:"; + +CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:"; +CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:"; +CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:"; +CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:"; +CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:"; +CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:"; +CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:"; + +CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:"; +CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:"; + +CPStandardKeyBindings[CPTabCharacter] = @"insertTab:"; +CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:"; +CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:"; +CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:"; +CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:"; + +CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:"; +CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:"; +CPStandardKeyBindings[CPF5FunctionKey] = @"complete:"; + +CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:"; +CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:"; +CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:"; +CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:"; +CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:"; +CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:"; +CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:"; + +CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:"; +CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:"; +CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:"; +CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:"; +CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:"; +CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:"; +CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:"; + +CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:"; +CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"]; +CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:"; +CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:"; +CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:"; + +CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:"; +CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"]; +CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:"; +CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:"; +CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:"; +CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:"; + +CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:"; +CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:"; +CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:"; +CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:"; + +CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:"; +CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:"; +CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:"; +CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:"; +CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:"; +CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:"; + +var CPKeyBindingCache = []; + +@implementation CPKeyBinding : CPObject +{ + CPString _key; + unsigned _modifierFlags; + + CPArray _selectors; +} + ++ (void)initialize +{ + if ([self class] !== CPKeyBinding) + return; + + [self createKeyBindingsFromJSObject:CPStandardKeyBindings]; +} + ++ (void)createKeyBindingsFromJSObject:(JSObject)anObject +{ + var binding; + for (binding in anObject) + { + var components = binding.split(@""), + modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) | + ([components containsObject:@"^"] ? CPControlKeyMask : 0) | + ([components containsObject:@"~"] ? CPAlternateKeyMask : 0) | + ([components containsObject:@"@"] ? CPCommandKeyMask : 0); + + var selectors = anObject[binding]; + if (![selectors isKindOfClass:CPArray]) + selectors = [selectors]; + + var keyBinding = [[self alloc] initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors]; + [self cacheKeyBinding:keyBinding]; + } +} + ++ (void)cacheKeyBinding:(CPKeyBinding)aBinding +{ + if (aBinding) + [CPKeyBindingCache addObject:aBinding]; +} + ++ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag +{ + var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil]; + for (var i = 0, count = CPKeyBindingCache.length; i < count; i++) + { + var binding = CPKeyBindingCache[i]; + if ([binding isEqual:tempBinding]) + return binding; + } +} + ++ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag +{ + return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors]; +} + +- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors +{ + self = [super init]; + + if (self) + { + _key = aKey; + _modifierFlags = aFlag; + + _selectors = selectors; + } + + return self; +} + +- (CPString)key +{ + return _key; +} + +- (unsigned)modifierFlags +{ + return _modifierFlags; +} + +- (CPArray)selectors +{ + return _selectors; +} + +- (BOOL)isEqual:(CPKeyBinding)rhs +{ + return _key === [rhs key] && _modifierFlags === [rhs modifierFlags]; +} + +@end diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 9760e5449..08b27616e 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -104,40 +104,24 @@ CPDeleteForwardKeyCode = 46; for (; index < count; ++index) { - var event = events[index]; + var event = events[index], + modifierFlags = [event modifierFlags], + character = [event charactersIgnoringModifiers], + selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags]; - switch([[event characters] characterAtIndex:0]) + if (selectorNames) { - case CPPageUpFunctionKey: [self doCommandBySelector:@selector(pageUp:)]; - break; - case CPPageDownFunctionKey: [self doCommandBySelector:@selector(pageDown:)]; - break; - case CPLeftArrowFunctionKey: [self doCommandBySelector:@selector(moveLeft:)]; - break; - case CPRightArrowFunctionKey: [self doCommandBySelector:@selector(moveRight:)]; - break; - case CPUpArrowFunctionKey: [self doCommandBySelector:@selector(moveUp:)]; - break; - case CPDownArrowFunctionKey: [self doCommandBySelector:@selector(moveDown:)]; - break; - case CPDeleteCharacter: [self doCommandBySelector:@selector(deleteBackward:)]; - break; - case CPCarriageReturnCharacter: - case CPNewlineCharacter: [self doCommandBySelector:@selector(insertLineBreak:)]; - break; + for (var s = 0, scount = selectorNames.length; s < scount; s++) + { + var selector = selectorNames[s]; + if (!selector) + continue; - case CPEscapeFunctionKey: [self doCommandBySelector:@selector(cancel:)]; - break; - - case CPTabCharacter: if (!([event modifierFlags] & CPShiftKeyMask)) - [self doCommandBySelector:@selector(insertTab:)]; - else - [self doCommandBySelector:@selector(insertBackTab:)]; - break; - - default: if (!([event modifierFlags] & (CPCommandKeyMask | CPControlKeyMask))) - [self insertText:[event characters]]; + [self doCommandBySelector:CPSelectorFromString(selector)]; + } } + else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)]) + [self insertText:[event characters]]; } } From cbb9602f9e3f2a98ceeabe252496915d95fbe80e Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 11:50:33 -0400 Subject: [PATCH 046/356] Better caching of key bindings. --- AppKit/CPKeyBinding.j | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j index e68b16c3c..77cdde0df 100644 --- a/AppKit/CPKeyBinding.j +++ b/AppKit/CPKeyBinding.j @@ -135,7 +135,7 @@ CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:"; CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:"; CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:"; -var CPKeyBindingCache = []; +var CPKeyBindingCache = {}; @implementation CPKeyBinding : CPObject { @@ -143,6 +143,8 @@ var CPKeyBindingCache = []; unsigned _modifierFlags; CPArray _selectors; + + CPString _cacheName; } + (void)initialize @@ -175,19 +177,16 @@ var CPKeyBindingCache = []; + (void)cacheKeyBinding:(CPKeyBinding)aBinding { - if (aBinding) - [CPKeyBindingCache addObject:aBinding]; + if (!aBinding) + return; + + CPKeyBindingCache[[aBinding _cacheName]] = aBinding; } + (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag { var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil]; - for (var i = 0, count = CPKeyBindingCache.length; i < count; i++) - { - var binding = CPKeyBindingCache[i]; - if ([binding isEqual:tempBinding]) - return binding; - } + return CPKeyBindingCache[[tempBinding _cacheName]]; } + (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag @@ -205,6 +204,23 @@ var CPKeyBindingCache = []; _modifierFlags = aFlag; _selectors = selectors; + + // We normalize our key binding string in order to properly cache it. + // We want to ensure the modifiers are always in the same order. + var cacheName = []; + + if (_modifierFlags & CPCommandKeyMask) + cacheName.push(@"@"); + if (_modifierFlags & CPControlKeyMask) + cacheName.push(@"^"); + if (_modifierFlags & CPAlternateKeyMask) + cacheName.push(@"~"); + if (_modifierFlags & CPShiftKeyMask) + cacheName.push(@"$"); + + cacheName.push(_key); + + _cacheName = cacheName.join(@""); } return self; @@ -225,6 +241,11 @@ var CPKeyBindingCache = []; return _selectors; } +- (CPString)_cacheName +{ + return _cacheName; +} + - (BOOL)isEqual:(CPKeyBinding)rhs { return _key === [rhs key] && _modifierFlags === [rhs modifierFlags]; From b37f5b4143509b6f82ccb4bac95da45e41cfe055 Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 14:18:29 -0400 Subject: [PATCH 047/356] Fix CPResponderTest. --- Tests/AppKit/CPResponderTest.j | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j index eab226833..2cfa482f3 100644 --- a/Tests/AppKit/CPResponderTest.j +++ b/Tests/AppKit/CPResponderTest.j @@ -21,16 +21,16 @@ - (void)testInterpretKeyEvents { var tests = [ - CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(pageUp:), - CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(pageDown:), + CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(scrollPageUp:), + CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(scrollPageDown:), CPKeyCodes.LEFT, CPLeftArrowFunctionKey, @selector(moveLeft:), CPKeyCodes.RIGHT, CPRightArrowFunctionKey, @selector(moveRight:), CPKeyCodes.UP, CPUpArrowFunctionKey, @selector(moveUp:), CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), - CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), - 0, CPNewlineCharacter, @selector(insertLineBreak:), - CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), + CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertNewline:), + 0, CPNewlineCharacter, @selector(insertNewline:), + CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancelOperation:), CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) ]; @@ -47,13 +47,16 @@ [responder interpretKeyEvents:[keyEvent]]; [self assert:[selector] equals:responder.doCommandCalls]; } +} +- (void)testInterpretKeyEventsWithModifierFlags +{ responder.doCommandCalls = []; keyEvent = [CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPShiftKeyMask timestamp:nil windowNumber:nil context:nil - characters:CPTabCharacter charactersIgnoringModifiers:CPTabCharacter isARepeat:NO keyCode:CPKeyCodes.TAB]; + characters:CPLeftArrowFunctionKey charactersIgnoringModifiers:CPLeftArrowFunctionKey isARepeat:NO keyCode:CPKeyCodes.LEFT]; [responder interpretKeyEvents:[keyEvent]]; - [self assert:[@selector(insertBackTab:)] equals:responder.doCommandCalls]; + [self assert:[@selector(moveLeftAndModifySelection:)] equals:responder.doCommandCalls]; } @end From 12a49d0ee120a2fe5b67a650649e1ba87a1f85c1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 18 Jun 2010 00:59:40 -0400 Subject: [PATCH 048/356] CPAlert informative text support. --- AppKit/CPAlert.j | 57 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 2d1b11ea1..500d46365 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -83,6 +83,7 @@ var CPAlertWarningImage, CPPanel _alertPanel; CPTextField _messageLabel; + CPTextField _informativeLabel; CPImageView _alertImageView; CPAlertStyle _alertStyle; @@ -140,8 +141,6 @@ var CPAlertWarningImage, [_alertPanel setFloatingPanel:YES]; [_alertPanel center]; - [_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; - var count = [_buttons count]; for(var i=0; i < count; i++) { @@ -156,19 +155,28 @@ var CPAlertWarningImage, if (!_messageLabel) { - var bounds = [[_alertPanel contentView] bounds]; - - _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)]; + _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; [_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]]; [_messageLabel setLineBreakMode:CPLineBreakByWordWrapping]; [_messageLabel setAlignment:CPJustifiedTextAlignment]; [_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; _alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)]; + + _informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + [_informativeLabel setFont:[CPFont systemFontOfSize:12.0]]; + [_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping]; + [_informativeLabel setAlignment:CPJustifiedTextAlignment]; + [_informativeLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; } + [_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; + [_informativeLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; [[_alertPanel contentView] addSubview:_messageLabel]; [[_alertPanel contentView] addSubview:_alertImageView]; + [[_alertPanel contentView] addSubview:_informativeLabel]; + + [self _layoutMessage]; } /*! @@ -231,22 +239,42 @@ var CPAlertWarningImage, } /*! - Set’s the receiver’s message text, or title, to a given text. + Sets the receiver’s message text, or title, to a given text. @param messageText - Message text for the alert. */ - (void)setMessageText:(CPString)messageText { [_messageLabel setStringValue:messageText]; + [self _layoutMessage]; } -/*! - Return's the receiver's message text body. +/*! + Returns the receiver's message text body. */ - (CPString)messageText { return [_messageLabel stringValue]; } +/*! + Sets the receiver's informative text, shown below the message text. + @param informativeText - The informative text. +*/ +- (void)setInformativeText:(CPString)informativeText +{ + [_informativeLabel setStringValue:informativeText]; + // No need to call _layoutMessage - only the length of the messageText + // can affect anything there. +} + +/*! + Returns the receiver's informative text. +*/ +- (CPString)informativeText +{ + return [_informativeLabel stringValue]; +} + /*! Adds a button with a given title to the receiver. Buttons will be added starting from the right hand side of the \c CPAlert panel. @@ -281,6 +309,19 @@ var CPAlertWarningImage, [_buttons addObject:button]; } +- (void)_layoutMessage +{ + var bounds = [[_alertPanel contentView] bounds], + width = CGRectGetWidth(bounds) - 73.0, + size = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel currentValueForThemeAttribute:@"font"] inWidth:width], + contentInset = [_messageLabel currentValueForThemeAttribute:@"content-inset"], + height = size.height + contentInset.top + contentInset.bottom; + + [_messageLabel setFrame:CGRectMake(57.0, 10.0, width, height)]; + + [_informativeLabel setFrame:CGRectMake(57.0, 10.0 + height + 6.0, width, CGRectGetHeight(bounds) - height - 50.0)]; +} + /*! Displays the \c CPAlert panel as a modal dialog. The user will not be able to interact with any other controls until s/he has dismissed the alert From 4b86115d30ed54643310eb4e248b46e30ed9e35a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 17 Jun 2010 00:04:49 -0400 Subject: [PATCH 049/356] Set the alert default button using the CPCarriageReturnCharacter key equivalent to match the recent Cappuccino change for default buttons. --- AppKit/CPAlert.j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 500d46365..9f935f145 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -301,9 +301,11 @@ var CPAlertWarningImage, [[_alertPanel contentView] addSubview:button]; if (_buttonCount == 0) - [_alertPanel setDefaultButton:button]; + [button setKeyEquivalent:CPCarriageReturnCharacter]; else if ([title lowercaseString] === "cancel") [button setKeyEquivalent:CPEscapeFunctionKey]; + else + [button setKeyEquivalent:nil]; _buttonCount++; [_buttons addObject:button]; From 32fb13a9a9a6f8b5bb84e537a3a7caef2f5550a7 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 18 Jun 2010 00:27:28 -0400 Subject: [PATCH 050/356] Fixed: long titles in CPAlert buttons would be cut off. Fix is to use the standard 80 pixels width as a minimum width only. --- AppKit/CPAlert.j | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 9f935f145..9f04ec545 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -145,14 +145,13 @@ var CPAlertWarningImage, for(var i=0; i < count; i++) { var button = _buttons[i]; - - [button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)]; - [button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]]; [[_alertPanel contentView] addSubview:button]; } - + + [self _layoutButtons]; + if (!_messageLabel) { _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; @@ -161,6 +160,7 @@ var CPAlertWarningImage, [_messageLabel setAlignment:CPJustifiedTextAlignment]; [_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; + _alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)]; _informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; @@ -288,8 +288,8 @@ var CPAlertWarningImage, - (void)addButtonWithTitle:(CPString)title { var bounds = [[_alertPanel contentView] bounds], - button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)]; - + button = [[CPButton alloc] initWithFrame:CGRectMakeZero()]; + [button setTitle:title]; [button setTarget:self]; [button setTag:_buttonCount]; @@ -309,6 +309,27 @@ var CPAlertWarningImage, _buttonCount++; [_buttons addObject:button]; + + [self _layoutButtons]; +} + +- (void)_layoutButtons +{ + var bounds = [[_alertPanel contentView] bounds], + count = [_buttons count], + offsetX = CGRectGetWidth(bounds), + offsetY = CGRectGetHeight(bounds) - 34.0; + for(var i=0; i < count; i++) + { + var button = _buttons[i]; + + [button sizeToFit]; + var buttonBounds = [button bounds], + width = MAX(80.0, CGRectGetWidth(buttonBounds)), + height = CGRectGetHeight(buttonBounds); + offsetX -= (width + 10); + [button setFrame:CGRectMake(offsetX, offsetY, width, height)]; + } } - (void)_layoutMessage From 8f040d6ff1d159429bf61d6c8acddb1d0359bb0e Mon Sep 17 00:00:00 2001 From: nciagra Date: Mon, 21 Jun 2010 13:53:17 -0400 Subject: [PATCH 051/356] Fixed a couple of Unix key bindings. --- AppKit/CPKeyBinding.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j index 77cdde0df..5cc46b422 100644 --- a/AppKit/CPKeyBinding.j +++ b/AppKit/CPKeyBinding.j @@ -30,6 +30,7 @@ CPStandardKeyBindings = { @"^$a": @"moveToBeginningOfParagraphAndModifySelection:", @"^b": @"moveBackward:", @"^$b": @"moveBackwardAndModifySelection:", + @"^~b": @"moveWordBackward:", @"^~$b": @"moveWordBackwardAndModifySelection:", @"^d": @"deleteForward:", @"^e": @"moveToEndOfParagraph:", @@ -48,7 +49,7 @@ CPStandardKeyBindings = { @"^$p": @"moveUpAndModifySelection:", @"^t": @"transpose:", @"^v": @"pageDown:", - @"^v": @"pageDownAndModifySelection:", + @"^$v": @"pageDownAndModifySelection:", @"^y": @"yank:" }; From f81e97726a2f08416e90e5694e65d2d9d52ab0cd Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 2 Mar 2010 11:58:44 -0800 Subject: [PATCH 052/356] Fixed setName: in CPImage to return BOOL as in Cocoa --- AppKit/CPImage.j | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/AppKit/CPImage.j b/AppKit/CPImage.j index 0bc69ba60..53a3f1937 100644 --- a/AppKit/CPImage.j +++ b/AppKit/CPImage.j @@ -193,6 +193,9 @@ function CPAppKitImage(aFilename, aSize) var imageOrSize = AppKitImageForNames[aName]; + if (!imageOrSize) + return nil; + if (!imageOrSize.isa) { imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize); @@ -205,17 +208,19 @@ function CPAppKitImage(aFilename, aSize) return imageOrSize; } -- (void)setName:(CPString)aName +- (BOOL)setName:(CPString)aName { if (_name === aName) - return; + return YES; - if (imagesForNames[aName] === self) - imagesForNames[aName] = nil; + if (imagesForNames[aName]) + return NO; _name = aName; imagesForNames[aName] = self; + + return YES; } - (CPString)name From 10c067e44f133c29aa8990d11fa3559b3e32f0e5 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 21 Jun 2010 22:32:18 -0500 Subject: [PATCH 053/356] When dragging over a tableview row we should jump to the next row at the bottom 30% of the row, not 50%... otherwise it gets really really bad with large row heights. --- AppKit/CPTableView.j | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index f67079a90..23127b643 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -3070,15 +3070,16 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { // We don't use rowAtPoint here because the drag indicator can appear below the last row // and rowAtPoint doesn't return rows that are larger than numberOfRows - var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )); - + // FIX ME: this is going to break when we implement variable row heights... + var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )), // Determine if the mouse is currently closer to this row or the row below it - var lowerRow = row + 1, + lowerRow = row + 1, rect = [self rectOfRow:row], - lowerRect = [self rectOfRow:lowerRow]; + bottomPoint = CGRectGetMaxY(rect), + bottomThirty = bottomPoint - ((bottomPoint - CGRectGetMinY(rect)) * 0.3); - if (ABS(CPRectGetMinY(lowerRect) - dragPoint.y) < ABS(dragPoint.y - CPRectGetMinY(rect))) - row = lowerRow; + if (dragPoint.y > MAX(bottomThirty, bottomPoint - 6)) + row = lowerRow; if (row >= [self numberOfRows]) row = [self numberOfRows]; From 10df31cbf977e73e47326f2388eab2f80d86ed95 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 22 Jun 2010 07:47:30 +0200 Subject: [PATCH 054/356] made isEqual: work on CPIndexSet and updated unit tests --- Foundation/CPIndexSet.j | 11 +++++++++++ Tests/Foundation/CPIndexSetTest.j | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 266c7273e..9975c0e11 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -130,6 +130,17 @@ return self; } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (![anObject isKindOfClass:[CPIndexSet class]]) + return NO; + + return [self isEqualToIndexSet:anObject]; +} + // Querying an Index Set /*! Compares the receiver with the provided index set. diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index c38778903..b63ff8cf9 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -368,6 +368,26 @@ function descriptionWithoutEntity(aString) [self assertTrue:[_set containsIndexes:[CPIndexSet indexSetWithIndexesInRange:startRange]]]; } +- (void)testIsEqual +{ + var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], + equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + + [self assertFalse:[_set isEqual:differentSet]]; + [self assertTrue:[_set isEqual:equalSet]]; + [self assertTrue:[_set isEqual:_set]]; +} + +- (void)testIsEqualToIndexSet +{ + var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], + equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + + [self assertFalse:[_set isEqualToIndexSet:differentSet]]; + [self assertTrue:[_set isEqualToIndexSet:equalSet]]; + [self assertTrue:[_set isEqualToIndexSet:_set]]; +} + - (void)tearDown { _set = nil; From 7e25166ce162505489cfe4775498f0291aeb6bf4 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 23 Jun 2010 19:13:24 -0700 Subject: [PATCH 055/356] Revert the fixed frame size assumption for now. --- Tools/nib2cib/NSButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 6bbb426c0..a9adfb9c1 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -93,7 +93,7 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _bezelStyle = CPHUDBezelStyle; } - if ([cell isBordered] && _frame.size.height === 32.0) + if ([cell isBordered]) { CPLog.info("Adjusting CPButton height from " +_frame.size.height+ " / " + _bounds.size.height+" to " + 24); _frame.size.height = 24.0; From 7c5a07f709ec9df8b963b49383ba32f9a3a58767 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 23 Jun 2010 19:58:43 -0700 Subject: [PATCH 056/356] Fix the issue where CPSecureTextField would sometimes cause all other text fields to go crazy afterwards. --- AppKit/CPTextField.j | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index d3873e524..6440017d5 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -807,11 +807,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if ([[self window] firstResponder] === self) window.setTimeout(function() { element.select(); }, 0); - else - { - [[self window] makeFirstResponder:self]; + else if ([self window] !== nil && [[self window] makeFirstResponder:self]) window.setTimeout(function() {[self selectText:sender];}, 0); - } } #endif } From a6b7d456f43f22e0fe737c0b59803c45eebc486a Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 21 Jun 2010 15:12:45 +0200 Subject: [PATCH 057/356] Add isLoaded to CFBundle and CPBundle --- Foundation/CPBundle.j | 12 ++++++++++-- Objective-J/CFBundle.js | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index 39aae0b29..89c082c4b 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -118,6 +118,16 @@ var CPBundlesForURLStrings = { }; return className ? CPClassFromString(className) : Nil; } +- (CPString)bundleIdentifier +{ + return [self objectForInfoDictionaryKey:@"CPBundleIdentifier"]; +} + +- (BOOL)isLoaded +{ + return _bundle.isLoaded(); +} + - (CPString)pathForResource:(CPString)aFilename { return _bundle.pathForResource(aFilename); @@ -133,8 +143,6 @@ var CPBundlesForURLStrings = { }; return _bundle.valueForInfoDictionaryKey(aKey); } -// - - (void)loadWithDelegate:(id)aDelegate { _delegate = aDelegate; diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index 8c7044e73..03639c8b0 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -235,6 +235,11 @@ CFBundle.prototype.isLoading = function() return this._loadStatus & CFBundleLoading; } +CFBundle.prototype.isLoaded = function() +{ + return this._loadStatus & CFBundleLoaded; +} + DISPLAY_NAME(CFBundle.prototype.isLoading); CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) From 07630964c14e4366331b7eed0206a7dc8cdb3202 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:03:17 -0400 Subject: [PATCH 058/356] Reverse bindings support for CPCollectionView selectionIndexes. This enables binding a CPCollectionView's selectionIndexes to a CPArrayController. --- AppKit/CPCollectionView.j | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 084686395..29e875ad1 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -312,6 +312,8 @@ while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) [_items[index] setSelected:YES]; + [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"]; + if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) [_delegate collectionViewDidChangeSelection:self]; } @@ -873,7 +875,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); - + _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0; _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0; @@ -905,7 +907,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey]; [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey]; - + [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; From 6b55c814627e5341beffa31558b3df79f0748ef1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:17:35 -0400 Subject: [PATCH 059/356] Fixed: Shift + Arrow Keys in allowsMultipleSelection CPCollectionViews did not expand the selection anymore after the recent key binding updates. --- AppKit/CPCollectionView.j | 56 +++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 29e875ad1..2a7acb44e 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -739,9 +739,10 @@ @end @implementation CPCollectionView (KeyboardInteraction) -- (CPIndexSet)_selectionForEvent:(CPEvent)anEvent withNewIndex:(int)anIndex direction:(int)aDirection + +- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand { - if (_allowsMultipleSelection && [anEvent modifierFlags] & CPShiftKeyMask) + if (_allowsMultipleSelection && shouldExpand) { var indexes = [_selectionIndexes copy], bottomAnchor = [indexes firstIndex], @@ -756,7 +757,8 @@ else indexes = [CPIndexSet indexSetWithIndex:anIndex]; - return indexes; + [self setSelectionIndexes:indexes]; + [self _scrollToSelection]; } - (void)_scrollToSelection @@ -775,24 +777,46 @@ index = MAX(index - 1, 0); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; +} + +- (void)moveLeftAndModifySelection:(id)sender +{ + var index = [[self selectionIndexes] firstIndex]; + if (index === CPNotFound) + index = [[self items] count]; + + index = MAX(index - 1, 0); + + [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; } - (void)moveRight:(id)sender { var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; +} + +- (void)moveRightAndModifySelection:(id)sender +{ + var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); + + [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; } - (void)moveDown:(id)sender { var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; +} + +- (void)moveDownAndModifySelection:(id)sender +{ + var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); + + [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; } - (void)moveUp:(id)sender @@ -803,8 +827,18 @@ index = MAX(0, index - [self numberOfColumns]); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; +} + +- (void)moveUpAndModifySelection:(id)sender +{ + var index = [[self selectionIndexes] firstIndex]; + if (index == CPNotFound) + index = [[self items] count]; + + index = MAX(0, index - [self numberOfColumns]); + + [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; } - (void)deleteBackward:(id)sender From 2da1dc31fb4c78cbd8f866cbd938b698ed6f9170 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:28:55 -0400 Subject: [PATCH 060/356] Simplify CPCollectionView keyboard selection code, eliminate some redundancy. --- AppKit/CPCollectionView.j | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 2a7acb44e..93022f119 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -742,6 +742,8 @@ - (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand { + anIndex = MIN(MAX(anIndex, 0), [[self items] count]-1); + if (_allowsMultipleSelection && shouldExpand) { var indexes = [_selectionIndexes copy], @@ -775,9 +777,7 @@ if (index === CPNotFound) index = [[self items] count]; - index = MAX(index - 1, 0); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; + [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO]; } - (void)moveLeftAndModifySelection:(id)sender @@ -786,37 +786,27 @@ if (index === CPNotFound) index = [[self items] count]; - index = MAX(index - 1, 0); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; + [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES]; } - (void)moveRight:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO]; } - (void)moveRightAndModifySelection:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES]; } - (void)moveDown:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO]; } - (void)moveDownAndModifySelection:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES]; } - (void)moveUp:(id)sender @@ -825,9 +815,7 @@ if (index == CPNotFound) index = [[self items] count]; - index = MAX(0, index - [self numberOfColumns]); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; + [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO]; } - (void)moveUpAndModifySelection:(id)sender @@ -836,9 +824,7 @@ if (index == CPNotFound) index = [[self items] count]; - index = MAX(0, index - [self numberOfColumns]); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; + [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES]; } - (void)deleteBackward:(id)sender From 74af0dc93a35a3b10bd84e2cbe3743e625c52bec Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:56:35 -0400 Subject: [PATCH 061/356] Fixed: Shift + Arrow Keys in allowsMultipleSelection CPTableViews did not expand the selection anymore after the recent key binding updates. --- AppKit/CPTableView.j | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 23127b643..480c01373 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -3360,6 +3360,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self scrollRowToVisible:i]; } +- (void)moveDownAndModifySelection:(id)sender +{ + [self moveDown:sender]; +} + - (void)moveUp:(id)sender { if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ && @@ -3407,6 +3412,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self scrollRowToVisible:i]; } +- (void)moveUpAndModifySelection:(id)sender +{ + [self moveUp:sender]; +} + - (void)deleteBackward:(id)sender { if([_delegate respondsToSelector: @selector(tableViewDeleteKeyPressed:)]) From cdb1ac32fab318dbff1561704533832404503307 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sat, 26 Jun 2010 23:17:30 -0500 Subject: [PATCH 062/356] Use the new Aristo HUD window art. --- AppKit/CPWindow/_CPHUDWindowView.j | 22 +++++++++--------- .../CPWindow/HUD/CPWindowHUDBackground0.png | Bin 311 -> 1141 bytes .../CPWindow/HUD/CPWindowHUDBackground1.png | Bin 179 -> 1033 bytes .../CPWindow/HUD/CPWindowHUDBackground2.png | Bin 331 -> 1166 bytes .../CPWindow/HUD/CPWindowHUDBackground3.png | Bin 114 -> 1002 bytes .../CPWindow/HUD/CPWindowHUDBackground4.png | Bin 118 -> 997 bytes .../CPWindow/HUD/CPWindowHUDBackground5.png | Bin 114 -> 1002 bytes .../CPWindow/HUD/CPWindowHUDBackground6.png | Bin 182 -> 1017 bytes .../CPWindow/HUD/CPWindowHUDBackground7.png | Bin 115 -> 1000 bytes .../CPWindow/HUD/CPWindowHUDBackground8.png | Bin 185 -> 1019 bytes AppKit/Resources/HUDTheme/WindowClose.png | Bin 349 -> 1580 bytes .../Resources/HUDTheme/WindowCloseActive.png | Bin 663 -> 1765 bytes 12 files changed, 11 insertions(+), 11 deletions(-) diff --git a/AppKit/CPWindow/_CPHUDWindowView.j b/AppKit/CPWindow/_CPHUDWindowView.j index ad0efd630..ab9c283b4 100644 --- a/AppKit/CPWindow/_CPHUDWindowView.j +++ b/AppKit/CPWindow/_CPHUDWindowView.j @@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0; _CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: [ - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)] + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)] ]]]; - _CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)]; - _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)]; + _CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)]; + _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)]; } + (CGRect)contentRectForFrameRect:(CGRect)aFrameRect diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground0.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground0.png index f43a3aad245ef5ce1ba726bcdeca66d9c5ffefe9..49f0f1bbf2edb98e4ab1b57402d809f8e47c132f 100644 GIT binary patch literal 1141 zcmbVMJ#5oT959l~zlCs1|XPW`s#LT%T!kT=$NKZ(1Xmf*Kxjyd3}GpBWxFc8=elDZ!Fo zz{Ae&i2(Oc^j55i5lgZ89os>7LuCXmrY2~(qh6>sa{N56%FfZXz=L@R9m(-cr>dns zP#^&YnIueDP=Y{0Nt8;5v5ll4@R1VaK+6eZ#i#RNkn!f}t9jf5A*TMRl5t-$fALp%^Mnl&;;b3F638G`GV zN{hr^xR5B8GNEDm0!l)`b)&fE(IGA4A8ss(4lCn67RopzV}Zr$F&J+tv)ujKPy}S& zsQUtk6~!FYi8bb8j~4YD&%PvW$5tWALWJZrltn0I5mFFTbls2)O*2xGF19$9(#;z% zlNYm^tmH+6bVEsNNVUpsLPBi-R-EY8_yGY&FbpSvPz4?z^t8uC^6zZBL&*dvvsi__E7Z~s0tv*FnFx%h$D#foWJR{Il%*mW+p_Y*5Vy0-Ti*ExA_^7z}6 z4{DDeF28W~-0K;}@oIAR&B1@qx82EKxiMLM0=}+`Y4CPlMv!+tu=X`ORcp)APa}LvMdjrbLO0bx~}gCR7FwjaI9$>|Kdg9 zVvLbp*LeV7F|b!k@wRPQTnGr{aPIpaK7rAC0>~Zn{|08Mf;ihm+Vq#m+s5LZ7)}w2lorHWJq;;>2RE6S-Ay*3YsqGscEPP>yXYP_n@qc*O(rH&H|?cj zPyPS}51u>;;veXt1@+)b&w}7d6oekUcb)7<^-y{+kjzKk=Xu`Gr|WAgb2B$)BuSd9 zuac%%r^I{n>a_SC-a33OmU+J1<{NC2_uYg_me0Br)I)cRHmU3HJ^V-)CF#m$&}#E` z_;8*1b1iN9$!i8Iy`r>flJJT_Ie-|s8^qQa6b6&Z$+ zb6{K$7KL;#;%-)m(uD~Fp{bVyF%MV-az?kyc6n76o{mBY<3{70I7-Kf5-C$NH&&4X z)iBKC8d|5kN&mWWp>^8Yi>cbADcemvQIE}q30UOra-rN%cw^p60#OuqhcIt9q!F)^ zsx1B}e&CxBRUkro3F;VX6@&}~4MH5vu`H*k5j^3z2wQVtxrQstx>3Uj5yvQ5hOHHK zfi9Qzk}<*7qm;XmM<=?0&>dsRrC8HWsLNT>Vr*y90qZ@+S=wVUus2Ge;d()opY!sJ zq9rs59#P*(SO|vsHG>QEbq(8Ajo_j+io4=yxKhGa*~X5@hVXra_5UYls&Gclo8zBm znOunu%(v&QFAnF!LnARUi5QLNKd${2V`bEd)ylqfJDpDD-M7=z!ONdtkNO8M&IW@| ykBLO*KYuuRe|#`F^PZiwR^D9y_1#UUR%gM9G(Ai2+u188AI|#n8hKmmJoy7`NJmxx delta 128 zcmV-`0Du392(tl@7Ya@Y1^@s6;TwD~ks&8*098puK~xyig^xiFfItWX8;*XFr*rZj z(t21EUBvZ52va6t0Csct%_8D3Nf-qHjHE_aKxU!^lJuBO04*SSt#!HInP$r?vKHJo i7fUDT{#~m+A{CsAhnRl26vEgXx0<5pknW`l4*^VRUbU(Ye72e!vjM7>wz3Ohv@GO?;3s7(40htv(bV7D&$d zpY#9y{@?jvpnu=m)!SB66t%Y4r4vK9AM@t{9~8)k?o)%J%G zU3AS+R7R#fIer!OP}K4fr&7h$(i^hnyR4b$u(2BuG)48~nhb*7Csj%7eZuW zKdkuvSgQjDYCiU(njg@G!3?~nl6!?Ow>3mvk z#+@?+K9}LuY=JjOHi+*{to?s-#t~<@q&c2xmevvJz+}7F`b1b99^{dU3CU<&nav+2 zWA$}WS1a+)U+v$s?px3?@!4zI`aPRp?>HEKbo2b>U%NV9TD8NtG=th+F1~%__jBw} zXS*7o-t@Qf-mtQQ+7;ivG=4X?;rjz^Lqk6v-T2qd{Ort{(hoPTfALGY(S0VGt9;zK z#li=sUwol{jq5(R;dV~D^`ujy>JO(MJkXA<=&N7+t+9FIvh|zt^<%kDPS)<7_%s(C zI{xlmLh%}Z5P?`2tjh{!jP14!Gp`)Qgi&+}DX*KZ=S1=gaf z48veu*C{|z6tBRim>DzszSk_ve^x*xco@f#G))s=BdTgMopY8X34okT_&Cv+dHvzy zD(4(NZ%;%Nw=<|}pvE;<7CT3{tBc~Qicf#lIe1!*5Dj~R#^04Z*6!kV@16*6_jn(1 zT`k`3f+a@0kK4(^?<4%{3$OigyZ;Ipu`2+60aGi`mgR_+F8}}l07*qo1w^hwV1gB> Bf7k#3 diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground3.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground3.png index a38e4dad1b09bac67f1faf1737e41fe30e206010..3ba64c8226c960400416d364bc0e848ec22b0a3b 100644 GIT binary patch literal 1002 zcmbVLyKd7^7&by&ROkR3osQg<_+0GRu~kz!c1+v|(&n}m9Vx^ zsx%j9N!r+~@-RA}9E|8B$!z)j)0qsC*p{EQ0~F*gohI9-1>HN{8APWCkr~UIkHAJ{ z34)aJ5LD@5R$7%U&v`AeudksD<|h2WmKRP9gI(aVf`Yb!S`pF_(6NG5%`l9IfFO(@ zA`p`nHY}A`2!Z7z3$-F1TYb-8YKfCAPdU#m2xqgIGE)^+OdvK*v*sYAB`jLyNyfvf zm6huagGbA#NOGRA4AhL_h#hlV7M?CbNb?}LAkNBVqD0DI73L5t2&QQr*W9|~efrmp zORdYnNlsy(mh8BQL_Nmq4OryvYN6Utcw;>+5>b@!&|}eYN;BT`Y+3wK;v}{Z?jVc} z4H*RK9gIzkOwaRm-*J3Z_ejHW8MfU1G_VSj#PF$XPL9?6B#8-6`X&oU$Cadm0GBD9P$`U7kg>9xamRH1-RYf_Z+e zDC$7`=i0Ulj?)WaI1^*F*7KY}^e delta 83 zcmaFGUZmI=;OEZECB?2 diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground4.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground4.png index 4d450f53a76b047a87705e372f020e39f090d512..eb0bc87f35a18f8dd137702011fd0b8667551976 100644 GIT binary patch literal 997 zcmbVLJ#W)M7&ZkVR8a{bF~HK3%Si0Ii(|)DP38D%8mTT(8broA_NB2}`^@=D+>UIl z6~BX#g@J{IjhWwo#LmPyi3>y30ZaCM_Tpo+vu{dN?F^@P^yo60C=x5O}9nvT{fAfuQE6VL@IvR^{xbMU))1ul&tFl6( z6=i#;Dx&y=3NWF^Y3{1OK7Ua`nz-ugP6)%or?YhLg44r`gHe2O65ENo^BinfjwHya zh(MK{=A~1)>Vnsi`}$f}!NNqGxa!iWaX0`z;}mo>*ovVEfr&KKHZ03}1~5cWhge6r zg)FCy9SFhdQKcGBrp}NAD=m3))tL~5qwDkeT${Hw#*cMm+jh-?aZ6gX%JW=ARVy#I z8U{kkn5TtESq^H(Xu{5ft4dFoA!J1uUJ>WzDp4|JdKDEq(x9GYbzBSUQVi)|H?FlV zN9P6AhqPp8JeKvCZZ%+;yPJh-L+Oq4lBcpL(J5i^Sw?fwC$1|0Xi1tl5OpC!mH{mc z%`QSVf;J(68F*gMHVJMxuEX{M1dT4TEW3vhB7tpqwr{pAiSBeP!)~zsycAI$(?&Oy zx+|=CBi8XbjRfN(#!j0K7|fVp<%|`;KQurX#c5uj>+&q4C6uRcX%cXjfkl3u^csE3 z#J<-fxa}?D?gl3A8rbXjIFQ+pzAv%K|Kv=U&ggY>{L?JWmF&QJd)4~#a5X$MmlMO~ yXv|)%K{-~B`otSmKPDe8FMoek?(E+mC=ZU5hr?Us`)227J$U`y1M;zV^zIK&Y%InA delta 87 zcmaFLUZ&U?;OEZECB?{kU`Gs`lejQc9k68Ihu`OU-p@Dtok#0y8*73fthe`^E?;l* zcjeY9|K7R%;hZmb*>0a5&>@@n84;|I4hU$+{t@XCKb$`QMz#du+A!+%S>JnX1T>cX z(nc!cl%oYX%7L0 z2+9!42-lEi)Ug2}SUw_G%fg}2b=;*EKbhi)vDA>|$z&o;>JrV4WTfkQ$$@c=Th#Jt z!u+C^o-kA7o-RU&Q_s5~PV!}oMG{z&v+X3zdf48{Y0Z^z_%)SF8QQ!?*XhUl#Yk7vVwY`uX_xjk9w4 M+PfX+ee2olKk&3NQvd(} delta 83 zcmaFGUZmI=;OEZECB?>(57A*h( diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground6.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground6.png index a2cebe44fd81c03b9e001e7b37b39fbe7b932a1c..01fe3ad8ad7fb74ab4e4bbcf8a92a1a501823a6e 100644 GIT binary patch literal 1017 zcmbVLJ#W)M7RWd*@$Cb605b(*jM6qs@RbD z0}T8HC^JJP5CaoCf1)EoES%H0AW?O|l6@b3pXYf$U+ru^T3WcXAW71ayGc4?y(!-7 zx8}w7+2`9|#InrWJ-*9^eBx(RYKCk;fgAfH+M#}U`1~tf6M$jV?eU(sWd$r&{L)4# z;#8m|X>Gko{a}xBFrcF-vE{Rmr!t5_TYlQ`ke9aTINChQ=;zc@1SSHQ{@QP5COEkGIq8dh+9RoC_VKt&iq zq(ZFLux`~=3n4IjWTBRYL#soanU*-&@|g3~f^agKD3iLvvJu3lX_g$SS`!wv{4n8u zQA_fbihKVS#kmW8M1A;hWYT@WYvEKwq5u<%oe6$InBjB9G0^A7#v z#--MI_b{cfLvwbJ1)?6ql?p6!cePMyD7>*AXOSq1zfV|j5YvRa#FoV$C5%D~VFO{T zuOeMVnt`#2kx7W7InAb1*N9qiT!wY9)>t(fs&2M0#>6qrw%I0a4XKW1I9k2Jx=GIc zB%qaUBy?w3d?nUuWz^>^>oT@qb->P;ah8u+3R=4j;Q2w6l;^TM=g|_HMK5URWGn{L z{94f^`v1he(a?#5v7wQcX4Fl2h7JEGXHYl;%jWp2S*k11f#vq1^~K?0cxWOfCKIFK ze*1JyjMY7tG`q$3LD=sbD-gc_`Rm8o>EihK#@5LR!u`3|;O(LzJv^S1K0KMf`)1h- O%VBie+vMFw|K)F5YBq)d delta 152 zcmey#zKv0_Gr-TCmrII^fq{Y7)59eQNV9=32Z(%d=Do*6MfE&}2u~Ns5RT~NgoK10 z>({UU-!pOIN5u)fJ(7GYSFN&p`s`Ufe?3zZxrAi}_5y!qHR%@TJuf*+GCN|Wa zfq|8Yje(^L6)Ou8zk!K`iPuS77^)6fvhTz1^E~h8>z(b#t1I_bBuQHBZMl6|ufTil z<_-Avf3Ra%?uyN!*yUp}3vwpe5g#$sOM(gOvmiQr@rA7eU>pyIV(33HL!Kx>Wuufy z253oI-zc*n++zZb*d$IZ`RAw4GKwQhe%AJ}pE+zAZyn`q_h@?%9_@ujByT)I>!k?< z2@?S-ll`fny{~~RT<4q#GWNDoErK&$l*CdZ3Q<%tYM@Pg*02bu0KQ+6RcvY z651fT*`y}MX!*#XmPcc=?|MruI9c*kh|E;g*=(lFnhMV+DlrVB;-Itv7LDRC6+ziZ zi?y1;Wks0BnTUCcD#l>M4}>Lyr;8Ah%=gcU(_)z@NSRs&nMxF_CP@|7+`15b_ScOI zt&727#?(G5_(2{*J;rM_7;<;HP-O_-m{0QEtXBJRfkrUw6RHlnY)=d4`(_X~g@if|LQM>I>53&KiFR;=7})shliyw zF*%IJ`**MI!&u$vx%Qy^K6-O<^857k?Ck8TbbTUSy(QiLcJ;yAkL_R8?DaOc-4EU8 G$A17OUNVOO delta 63 zcmaFCUOYjZi;aVgfq{WZ;EUlzMRjckQBN1g5RT~NgoK2O6Af+>5)wAdn;E>{vfgRB S+j11BlEKr}&t;ucLK6TGvl4Rv diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground8.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground8.png index 60e25e8e0b844ac30a4c926926d4e1757e139e7e..14c5c58e13194640bb2a1d4f11b49882b870cd53 100644 GIT binary patch literal 1019 zcmbVLJ#W)M7&f4ms!~S=SU9;O#J+QCJGSb!X)dObaH-Nrq%3f;FOAjOXY31cs}6_( ziI1s5LJa%`{s2P<%D~8m_yhZ*JdS2nrp4$ zwpcHV_tMO?_}>3;<)c`x@@AKBvOXV?luGr0^(bgXWSh1r3HBa-qKg914?A7n^={if zixg7WD0!3!v?MJq=Lzw5CK^ox1|5WJ`zhVrU+?()JH8dj z%S&J}w*^5&IRSaJ8)tUz$YWkx?2Btv24fSxB}v-y$%)67r9goi8!1taOPA$Mfq=}8Dt;(4dUaW+YmNST_GL`4czqo{~$ zY@P8o{o}@&)>&sSp=z6EY?%6@9{u?eEOK|gP+=&%vG1gzC<@ud%pXQH<}K{V;*S!9 zfeld&B4jQ=Q-ekgAqznZW7lx&b+>9@t>ich>moy6sOg4jH4sABwXCMq#7zTgu2FN1 zYKd*d87Hw%OWjcDPO$p9Si6x@!dcp3Y`5%yjRE5<8?Xd4Hg(_;Ka7iWQJ#}%F-^lq zG;mWEfpLEA@C^Nb;$GEF>>^Y%aKoroEqQ_s{wHUua7HbfA4aKK!MnrSlnYmP<@f-LZ40{K{3U>{vJPFZA&6_O=%k6|Ln-xo&hIq>1I~)vNQ3 zjEv^7bQKy%NJ!W)XR@zs;nFg8U_3E{IpD2~fg{7R4YK}h)1$(H_Az+6`njxgN@xNA Dmr*ZH diff --git a/AppKit/Resources/HUDTheme/WindowClose.png b/AppKit/Resources/HUDTheme/WindowClose.png index 4d3d405cf12637145838d0611dbf8007b986f43c..17ba6f603e5b46abcf9b132e5afcd40e826f3a1f 100644 GIT binary patch literal 1580 zcmbVMdr;GM91n`3ptqa23ApWI^f+HMNegKcTO2f$$1Gy0$cfB_G^H6dDQSdK5fpKQ zI@yU%^c?PV*qbtRoD7)SiQ~jE#kaDROjy4}t54|A9NUf<8>^L_nN zk&+xgJ}@j00D$p{38X<9CwSj6qor@!iONON5Gux{i>bU>ET9Aih%xb5447!8vKa$I znF{kd7&QQlG_%HZF9XJGmtVshc ziqa!`o0hS#2~L4YbtW5WXAX^ihc%b86AleD#7jtX?=}p9LndO5 z272mLx;_Qe@&W@!$&d&d!4MEbWvC)jsZ`Dev;evt!S%E^v3)wJ=19@i6B9`dB%R1itcgHS6@sG5NJJ?| zFcpg8D1wuu4%5ZN=oA9!JJuh+K!MbeO`2P2}t% z#nFsUmz8vfvB(RtgjQfEkr#|SpX=*@6bmo%b_;IR&8C2wIj0g+{OOyzkyym?v_1j zxwY-%TbjP*cRjA%yZ4vm&3LkK`ozHcuG{w?p8aKD=8xM?S|W@6`bMm3UAwp*Q|lA* zh?<__L!W)xX)bykSe$U&9~(D%^$GJnO-}R0h3dMJV8aqwmwwtCZP9+2zm0#iaWG63 z)O+P%TaTmiCs(+;%XszPU|RDn{hiFZW#XkPww|cg>rAnkI66 z{1v~J%=)zRSq+0{vKo3f7&)Lt;OO?S5U*c=PeZfr7&e_pzi-*>D3 zucPx?V;4NQeta_>wob=gD6MFU8tGOX^}qpYf*_n{ap#q~Y9&+mP3 z^4+~kdC0ikr!501Wr*r17QSeu=2Vk=^y-*BZlI|yrS|;$p5*Wi^T%2rOv}EPH2C-9 zx48cEyJ}`sADfe)UU_@MWI*}0zkgZzV1B4_YiGckSgQK#wVCX-fXQ3t-3+Vxqjl8b zQBD3`t`fK=d1-v78!OhAf9bbeRvq-P=-XL_mX7{l%Yl$%=6%$4qLC|}boKDoR{W#x z>ZG0DHKg~-UCokm$hFd{I?Mf%qQ>8oHt!7DS40!|m4<^59qMv+KS_W~+dt{clN~vG gqc&~N(h=i;ulBwZR7gy{>HU8v#wC+`V&5zM2gFWZB>(^b delta 321 zcmV-H0lxmM4BY}DiBL{Q4GJ0x0000DNk~Le0000K0000K2nGNE0F8+q4Ur)ye*phU zL_t(I%gvOr5rZ%cMJZT;2^fU|($cdMC6ya5#RTt<7u-Aka=e{3lfr=qsWE3)fPHH8rvU7Xx{h+WPoDb|21&=-%C zA@19s>4CKd+<>-hBM&Xx1ZaWnw8G-rPYSJ-*2^`NRIMQpPrb5(l TxlyW$00000NkvXXu0mjfQiqZB diff --git a/AppKit/Resources/HUDTheme/WindowCloseActive.png b/AppKit/Resources/HUDTheme/WindowCloseActive.png index f4228235806c3e79259c5bb45be04d142b25ac31..5fa29fed3c88a7401d9ebcce7f9c7da3d54a77ae 100644 GIT binary patch literal 1765 zcmbVNeM}Q)7;i)fkX2?^21C(XA$&O6-nG!L!5H-D=%Cn@3W$P~_OPY2SKFf$2o6{f zQBaV{aDoVms7yp>`P_m;bf6;Q#uN<6CJTrkU;@a8Q+7pgOJ?@RF1dT(=e_6md%o`q z#1Wqn?Op5%1OibQ3QO>nWVvl^@MqMm1JU^M0TvR2MWRVqnoN%nf)r>X0thv-ornaH zDbjcKApQh`Rgy{?gT;u#d2&=klUa0VCXEh96A1o+CY?;KMlc`|*{RY7P$t_uD1b^4 zK#BGffg&9rQK~{S^hjhzgjAlPmU9)9z)t{w6AvfQAeam=X;QQXo+*H`#LL6?mSZ{v zSW>~%0hHHH#fZcJAJrp(9}T3+K^6$GAR5H?|y3@XItF&R7%1ePxf zZcVR9;z?k^vMpQ+peQj+$D`BJ($Z*YOd6`+Nr$*xu7!iapyC=-L%J4|nW$QW+X@4W z8031D4pX68z``g?L{qT<3hwFa5HvcG=nb*fu$(A7WptBFM~7%2U8AwYwWMvpB*@=x zyj9yEP1hlG31UD~^>Vx(Np34(Ja_+X$fAgQ!`rM^;YE?9z^FV`gJ>}!96-U}&=e{K z4}>@%1hIWVHUngFAczZrTo@Lx1VKRpCJSb)aJ&u6V6$Kr$l|iOd?p0J0xma%8v=*0 zK!$+D5wMsmSfSQ{$+U80#jXmsyNu=hCzi+8BQgxtOHnjsr31uD6hjS4R0r@Q{Q!|n zuF_g$OL<;L3nO}!5m5;As0LWdFHiLr`~QkN*pCehAc(_)`792TOIgM${!h;6xHEK1 zbNr)OR*vuvv~1tBJ}$f&9z=^zj2<72443&CeBvC1aFEnA^qn*;Y@Li;86EH8;o%N7 z9a?=!BqUe2l-Ae=#|@A!7H={>mXAe6x21X-w-w*XGe)*`e?IQe2(X-0ROpoZFTRsP zM$gTYW7orPH@MD?9&J6}I$JSCyg!bW=eKZ1b7(o*y1KfBkHgez^$jD2ku~Pn5@Y*Q z&-~7W&~-)Ex~8Y6>w0^8UBX>8kX$Z*C+vhOFJ}K$N>}2Av2kpH+BdbHq+b7%x%wJ>3vR=m3N`%L% zs=hpxt>gS@ztQgLlP5kq;^U2tKRCa1N|*~Ree7yi<7HD3F;>(!R-f*_!E8Xo8^&X{X_A1tf;a`jS+%6x-+x!0L-qRqR zd+gl0`WaH0{-ay*l>(*tfV*|V-4ZdfwW&VJzg}VWknCoc3tWl1Yrf~`Zr$l!9rIqM z8>yhH_?aySQT8(jyX&roCYUoe7oW6FDA`;qDRdXkBwp}Jy!mPC_E)=%#`o*8`}_O9 zS(86vH&5WZa<=B@=P#0Or)_0!*tjt;J}xfHevEi}GAAILcFxMmifB(5E=x9VT9r$F zh`N*P`X(kO`i>kqqF%LaGW1w^xfhK_D|2vgDDo1o$|M;hoZOG4XV(X-iOQa)#zt{v zMTL)8+w3MWdXX6qhONh6%+Ag_x|da-W07}nvz1Oc4`(;5?^k}kBR00p=3btH;XNG5 zdYCe@zjl5;9Z62UZfgaVRhvL zw!qq0^YHPjP2(pM3WjKI=Q9`b+84>a{d>N;R&uGP4VDreHXVPp7`WhhnK0v8l_4OW Q4YB-qgdq`dLvTXwUtlSuc@D@x2`n|m%g{QPe_3mHuxHpOy}>&ylYJjNG5%h3MySwFQDpY`es4a$Zs=Wc$nc{r_vKtE=o7tv38?T>;~avyjV%t3cpu^51bzy;RX@SE z5%+;~W2{>!(l`tl31^4bp&>FJK2>9Uzk`2(pTXwpAMouCe(d;D=bp?#f70(U?Ybz; zzfW$MrXcXaW_g}hSTC_&!It_yV^BHg_FJILv`|rqFvZ_?!V%K~5?-zi`|I#skxuNs z$XF;Xh*^r!atb}uUM#R(8nW0VG~=?g&4R|miqO*AN|rPcB4VBc8X-6 zosy$dL~>!L$ml9ty-cJKxo|`&v6?7==gjwV?%Qsl_qxr1CrLZjQ%#vRzH>l0^{LZ_ zg(GLAN0B8mrOMW{3Fn~(?kUl!N}{&ZwB}(raKrI+p1Rj2wq_7%6Er4vcvk}Q@t^h$ Xn*iFiJF8(400000NkvXXu0mjfRh=nX From 9a302328c63e9f6f89d6ac3efdfb37321b6c4bd3 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sat, 26 Jun 2010 23:35:33 -0500 Subject: [PATCH 063/356] Move the new close button a little to the right to confrom with the Aristo art. --- AppKit/CPWindow/_CPHUDWindowView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPWindow/_CPHUDWindowView.j b/AppKit/CPWindow/_CPHUDWindowView.j index ab9c283b4..f10167577 100644 --- a/AppKit/CPWindow/_CPHUDWindowView.j +++ b/AppKit/CPWindow/_CPHUDWindowView.j @@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0; { var closeSize = [_CPHUDWindowViewCloseImage size]; - _closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)]; + _closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)]; [_closeButton setBordered:NO]; From f73d8a55de62810d61915b0ebdfe72c594c6a2f2 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 29 Jun 2010 17:47:36 +0200 Subject: [PATCH 064/356] implemented isEditable nib2cib support for CPTableColumn --- AppKit/CPTableColumn.j | 10 ++++++---- Tools/nib2cib/NSTableColumn.j | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 91edc5d50..77967f816 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -468,9 +468,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", - CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey", + CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey", CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey"; - CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey"; + CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey"; @implementation CPTableColumn (CPCoding) @@ -492,7 +492,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]]; _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey]; - _isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenkey]; + _isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey]; + _isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey]; _sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey]; } @@ -512,7 +513,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey]; [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey]; - [aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenkey]; + [aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey]; + [aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey]; [aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey]; } diff --git a/Tools/nib2cib/NSTableColumn.j b/Tools/nib2cib/NSTableColumn.j index 8af344031..d85cb70c5 100644 --- a/Tools/nib2cib/NSTableColumn.j +++ b/Tools/nib2cib/NSTableColumn.j @@ -60,6 +60,8 @@ _resizingMask = [aCoder decodeBoolForKey:@"NSIsResizeable"] ? CPTableColumnUserResizingMask : CPTableColumnAutoresizingMask; _isHidden = [aCoder decodeBoolForKey:@"NSHidden"]; + _isEditable = [aCoder decodeBoolForKey:@"NSIsEditable"]; + _sortDescriptorPrototype = [aCoder decodeObjectForKey:@"NSSortDescriptorPrototype"]; } From f34775b038c1c6c5f096c973841934acf47d4660 Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Tue, 29 Jun 2010 14:02:37 -0400 Subject: [PATCH 065/356] CPAttributedString should not call its own -beginEditing or -endEditing. --- Foundation/CPAttributedString.j | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/Foundation/CPAttributedString.j b/Foundation/CPAttributedString.j index f61b5c0e1..85bb3588f 100644 --- a/Foundation/CPAttributedString.j +++ b/Foundation/CPAttributedString.j @@ -505,8 +505,6 @@ */ - (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString { - [self beginEditing]; - if (!aString) aString = ""; @@ -534,8 +532,6 @@ while(endingIndex < _rangeEntries.length) _rangeEntries[endingIndex++].range.location+=additionalLength; - - [self endEditing]; } /*! @@ -561,8 +557,6 @@ */ - (void)setAttributes:(CPDictionary)aDictionary range:(CPRange)aRange { - [self beginEditing]; - var startingEntryIndex = [self _indexOfRangeEntryForIndex:aRange.location splitOnMaxIndex:YES], endingEntryIndex = [self _indexOfRangeEntryForIndex:CPMaxRange(aRange) splitOnMaxIndex:YES], current = startingEntryIndex; @@ -575,8 +569,6 @@ //necessary? [self _coalesceRangeEntriesFromIndex:startingEntryIndex toIndex:endingEntryIndex]; - - [self endEditing]; } /*! @@ -591,8 +583,6 @@ */ - (void)addAttributes:(CPDictionary)aDictionary range:(CPRange)aRange { - [self beginEditing]; - var startingEntryIndex = [self _indexOfRangeEntryForIndex:aRange.location splitOnMaxIndex:YES], endingEntryIndex = [self _indexOfRangeEntryForIndex:CPMaxRange(aRange) splitOnMaxIndex:YES], current = startingEntryIndex; @@ -613,8 +603,6 @@ //necessary? [self _coalesceRangeEntriesFromIndex:startingEntryIndex toIndex:endingEntryIndex]; - - [self endEditing]; } /*! @@ -642,8 +630,6 @@ */ - (void)removeAttribute:(CPString)anAttribute range:(CPRange)aRange { - [self beginEditing]; - var startingEntryIndex = [self _indexOfRangeEntryForIndex:aRange.location splitOnMaxIndex:YES], endingEntryIndex = [self _indexOfRangeEntryForIndex:CPMaxRange(aRange) splitOnMaxIndex:YES], current = startingEntryIndex; @@ -656,8 +642,6 @@ //necessary? [self _coalesceRangeEntriesFromIndex:startingEntryIndex toIndex:endingEntryIndex]; - - [self endEditing]; } //Changing Characters and Attributes @@ -682,8 +666,6 @@ */ - (void)insertAttributedString:(CPAttributedString)aString atIndex:(unsigned)anIndex { - [self beginEditing]; - if (anIndex < 0 || anIndex > [self length]) [CPException raise:CPRangeException reason:"tried to insert attributed string at an invalid index: "+anIndex]; @@ -713,8 +695,6 @@ //necessary? //[self _coalesceRangeEntriesFromIndex:startingEntryIndex toIndex:startingEntryIndex+rangeEntries.length]; - - [self endEditing]; } /*! @@ -727,12 +707,8 @@ */ - (void)replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPAttributedString)aString { - [self beginEditing]; - [self deleteCharactersInRange:aRange]; [self insertAttributedString:aString atIndex:aRange.location]; - - [self endEditing]; } /*! @@ -742,8 +718,6 @@ */ - (void)setAttributedString:(CPAttributedString)aString { - [self beginEditing]; - _string = aString._string; _rangeEntries = []; @@ -752,8 +726,6 @@ for (; i < count; i++) _rangeEntries.push(copyRangeEntry(aString._rangeEntries[i])); - - [self endEditing]; } //Private methods From 6b132c4d3b7eb44daae513001abf27a09fc7fc61 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 30 Jun 2010 11:15:38 +0200 Subject: [PATCH 066/356] added check for nil in CPIndexSet isEqual --- Foundation/CPIndexSet.j | 2 +- Tests/Foundation/CPIndexSetTest.j | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 9975c0e11..af528b169 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -135,7 +135,7 @@ if (self === anObject) return YES; - if (![anObject isKindOfClass:[CPIndexSet class]]) + if (!anObject || ![anObject isKindOfClass:[CPIndexSet class]]) return NO; return [self isEqualToIndexSet:anObject]; diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index b63ff8cf9..49e3194df 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -373,6 +373,7 @@ function descriptionWithoutEntity(aString) var differentSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 11)], equalSet = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(10, 10)]; + [self assertFalse:[_set isEqual:nil]]; [self assertFalse:[_set isEqual:differentSet]]; [self assertTrue:[_set isEqual:equalSet]]; [self assertTrue:[_set isEqual:_set]]; From 83ea50a8360c357893a8adb26efbc152172e60f3 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 30 Jun 2010 11:41:22 +0200 Subject: [PATCH 067/356] don't send windowWillLoad and windowDidLoad if the window is not loaded from cib --- AppKit/CPWindowController.j | 6 ------ 1 file changed, 6 deletions(-) diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index c5496a7e5..2d011af98 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -72,17 +72,11 @@ if (self) { - if (aWindow) - [self windowWillLoad]; - [self setWindow:aWindow]; [self setShouldCloseDocument:NO]; [self setNextResponder:CPApp]; - if (aWindow) - [self windowDidLoad]; - _documents = []; } From af0ca527399825a133895d7e46eb83fa53d65c5c Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 30 Jun 2010 11:50:53 +0200 Subject: [PATCH 068/356] made CPViewController equal cappuccino master --- AppKit/CPViewController.j | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j index ab8c3a22e..3fffe261d 100644 --- a/AppKit/CPViewController.j +++ b/AppKit/CPViewController.j @@ -162,6 +162,8 @@ var CPViewControllerCachedCibs; if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) [cibOwner viewControllerDidLoadCib:self]; + + [self viewDidLoad]; } return _view; @@ -187,13 +189,7 @@ var CPViewControllerCachedCibs; */ - (void)setView:(CPView)aView { - var viewWasLoaded = !_view; - _view = aView; - - // Make sure the viewDidLoad method is called if the view is set directly - if (viewWasLoaded) - [self viewDidLoad]; } @end From 6a689dc3df96cf0c59b3db76166a6be2cea7d0fd Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Wed, 30 Jun 2010 12:00:20 -0400 Subject: [PATCH 069/356] Fix for asking the wrong object for -_replacementKeyPathForBinding: when creating a new binding. --- AppKit/CPKeyValueBinding.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 3aabc98a6..a926cdd2b 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -263,7 +263,7 @@ var CPBindingOperationAnd = 0, // CPLog.warn("No binding exposed on "+self+" for "+aBinding); [self unbind:aBinding]; - [[CPKeyValueBinding alloc] initWithBinding:[anObject _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self]; + [[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self]; } - (CPDictionary)infoForBinding:(CPString)aBinding From 21a9ae4c456993fcfdd93c1ea241472adb1f72ec Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Wed, 30 Jun 2010 12:03:03 -0400 Subject: [PATCH 070/356] Make CPTableView work with selectionIndexes binding. --- AppKit/CPTableView.j | 51 +++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 480c01373..d40747df6 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -882,6 +882,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self _noteSelectionDidChange]; } +- (void)_setSelectedRowIndexes:(CPIndexSet)rows +{ + var previousSelectedIndexes = [_selectedRowIndexes copy]; + + _lastSelectedRow = ([rows count] > 0) ? [rows lastIndex] : -1; + _selectedRowIndexes = [rows copy]; + + [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; + [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows + // but currently -drawRect: is not implemented here + + [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectedRowIndexes"]; + + [self _noteSelectionDidChange]; +} + /*! Sets the row selection using indexes. @param rows a CPIndexSet of rows to select @@ -902,20 +918,16 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [_headerView setNeedsDisplay:YES]; } - var previousSelectedIndexes = [_selectedRowIndexes copy]; - + var newSelectedIndexes; if (shouldExtendSelection) - [_selectedRowIndexes addIndexes:rows]; + { + newSelectedIndexes = [_selectedRowIndexes copy]; + [newSelectedIndexes addIndexes:rows]; + } else - _selectedRowIndexes = [rows copy]; + newSelectedIndexes = [rows copy]; - // update last selected row - _lastSelectedRow = ([rows count] > 0) ? [rows lastIndex] : -1; - - [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; - [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows - // but currently -drawRect: is not implemented here - [self _noteSelectionDidChange]; + [self _setSelectedRowIndexes:newSelectedIndexes]; } - (void)_updateHighlightWithOldRows:(CPIndexSet)oldRows newRows:(CPIndexSet)newRows @@ -3427,14 +3439,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; @implementation CPTableView (Bindings) +- (CPString)_replacementKeyPathForBinding:(CPString)aBinding +{ + if (aBinding === @"selectionIndexes") + return @"selectedRowIndexes"; + + return [super _replacementKeyPathForBinding:aBinding]; +} + - (void)_establishBindingsIfUnbound:(id)destination { if ([[self infoForBinding:@"content"] objectForKey:CPObservedObjectKey] !== destination) - { [self bind:@"content" toObject:destination withKeyPath:@"arrangedObjects" options:nil]; - //[self bind:@"sortDescriptors" toObject:destination withKeyPath:@"sortDescriptors" options:nil]; - //[self bind:@"selectionIndexes" toObject:destination withKeyPath:@"selectionIndexes" options:nil]; - } + + if ([[self infoForBinding:@"selectionIndexes"] objectForKey:CPObservedObjectKey] !== destination) + [self bind:@"selectionIndexes" toObject:destination withKeyPath:@"selectionIndexes" options:nil]; + + //[self bind:@"sortDescriptors" toObject:destination withKeyPath:@"sortDescriptors" options:nil]; } - (void)setContent:(CPArray)content From e385321f95ec76e1c6afa2282b927f2c97b09fb5 Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Wed, 30 Jun 2010 22:28:02 -0400 Subject: [PATCH 071/356] CPArrayController -selectedObjects returns a CPObservableArray. --- AppKit/CPArrayController.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 5fefb58c8..c11206f79 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -335,7 +335,7 @@ { var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]; - return objects || [_CPObservableArray array]; + return [_CPObservableArray arrayWithArray:(objects || [])]; } - (BOOL)setSelectedObjects:(CPArray)objects From 071ab7d5550fc981403ca6c85f4766a006c2bef6 Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Fri, 2 Jul 2010 14:58:23 -0400 Subject: [PATCH 072/356] Only use CPView -display* methods while in DOM. --- AppKit/CPView.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 56025cd47..51356c8d2 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1791,12 +1791,14 @@ setBoundsOrigin: - (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext { +#if PLATFORM(DOM) [self lockFocus]; CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect); [self drawRect:aRect]; [self unlockFocus]; +#endif } - (void)viewWillDraw From 2a2b320be316a1269d19d8c14d20b0921166d457 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Tue, 6 Jul 2010 22:37:58 -0500 Subject: [PATCH 073/356] Added image support for overflow toolbaritems. Also disabled the menu items if the toolbar is disabled. --- AppKit/CPToolbar.j | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/AppKit/CPToolbar.j b/AppKit/CPToolbar.j index b45d70211..e3ef772d0 100644 --- a/AppKit/CPToolbar.j +++ b/AppKit/CPToolbar.j @@ -563,6 +563,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth) [_additionalItemsButton setImagePosition:CPImageOnly]; [[_additionalItemsButton menu] setShowsStateColumn:NO]; + [[_additionalItemsButton menu] setAutoenablesItems:NO]; [_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage]; } @@ -793,14 +794,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth) hasNonSeparatorItem = YES; - [_additionalItemsButton addItemWithTitle:[item label]]; - - var menuItem = [_additionalItemsButton itemArray][index + 1]; + var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil]; [menuItem setImage:[item image]]; - [menuItem setTarget:[item target]]; - [menuItem setAction:[item action]]; + [menuItem setEnabled:[item isEnabled]]; + + [_additionalItemsButton addItem:menuItem]; } } else @@ -1055,6 +1055,8 @@ var TOP_MARGIN = 5.0, [_imageView setAlphaValue:0.5]; [_labelField setAlphaValue:0.5]; } + + [_toolbar tile]; } - (CPColor)FIXME_labelColor From a34dfee752305e876b561c913c1d8de9eec2b083 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Tue, 6 Jul 2010 22:43:30 -0500 Subject: [PATCH 074/356] CPFormatter implementation. --- Foundation/CPFormatter.j | 168 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 Foundation/CPFormatter.j diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j new file mode 100644 index 000000000..7fa3665d5 --- /dev/null +++ b/Foundation/CPFormatter.j @@ -0,0 +1,168 @@ +/* + * CPFormatter.j + * Foundation + * + * Created by Randall Luecke + * Copyright 2010, RCLConcepts, LLC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/*! + @class CPFormatter + @ingroup foundation + @brief CPFormatter is an abstract class that declares an interface for objects that create, interpret, + and validate the textual representation of cell contents. The Foundation framework provides two + concrete subclasses of CPFormatter to generate these objects: CPNumberFormatter and CPDateFormatter. + + CPFormatter is intended for subclassing. A custom formatter can restrict the input and enhance the + display of data in novel ways. For example, you could have a custom formatter that ensures that serial + numbers entered by a user conform to predefined formats. Before you decide to create a custom formatter, + make sure that you cannot configure the public subclasses CPDateFormatter and CPNumberFormatter to satisfy your requirements. +*/ + +@import + +@implementation CPFormatter : CPObject + +/*! + The default implementation of this method raises an exception. + + When implementing a subclass, return the CPString object that textually represents + the view's object for display andif editingStringForObjectValue: is unimplementedfor editing. + First test the passed-in object to see if its of the correct class. If it isnt, return nil; + but if it is of the right class, return a properly formatted and, if necessary, localized string. + (See the specification of the CPString class for formatting and localizing details.) + + @param anObject The object for which a textual representation is returned + @return CPSting a formatted string +*/ +- (CPString)stringForObjectValue:(id)anObject +{ + _CPRaiseInvalidAbstractInvocation(self, @selector(stringForObjectValue:)); + return nil; +} + + +/*- (CPAttributedString)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(CPDictionary)attributes +{ + +}*/ + + +/*! + The default implementation of this method invokes stringForObjectValue:. + + When implementing a subclass, override this method only when the string that users see and the string + that they edit are different. In your implementation, return an CPString object that is used for editing, + following the logic recommended for implementing stringForObjectValue:. As an example, you would implement + this method if you want the dollar signs in displayed strings removed for editing. + + @param anObject the object for which to return an editing string + @return CPString object that is used for editing the textual represntation of an object +*/ +- (CPString)editingStringForObjectValue:(id)anObject +{ + _CPRaiseInvalidAbstractInvocation(self, @selector(editingStringForObjectValue:)); + return nil; +} + + +/*! + 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) + 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 + 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 durring 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. +*/ +- (BOOL)getObjectValue:(id)anObject forString:(CPString)aString errorDescription:(CPString)anError +{ + _CPRaiseInvalidAbstractInvocation(self, @selector(getObjectValue:forString:errorDescription:)); + return NO; +} + + +/*! + Returns a Boolean value that indicates whether a partial string is valid. + + This method is invoked each time the user presses a key while the cell has the keyboard focusit 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:. + 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 + isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:, this method will be called as before + (isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: just calls this one by default). + + @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 desibes the problem. + @return YES if aPartialString is an acceptable value, otherwise NO. +*/ +- (BOOL)isPartialStringValid:(CPString)aPartialString newEditingString:(CPString)aNewString errorDescription:(CPString)anError +{ + _CPRaiseInvalidAbstractInvocation(self, @selector(isPartialStringValid:newEditingString:errorDescription:)); + return NO; +} + +/*! + This method should be implemented in subclasses that want to validate user changes to a string in a field, where the user changes are + 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 + 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 descibes the problem. + @return YES if aPartialString is acceptable, otherwise NO. + +*/ +- (BOOL)isPartialStringValue:(CPString)aPartialString proposedSelectedRange:(CPRange)aProposedSelectedRange originalString:(CPString)originalString originalSelectedRange:(CPRange)originalSelectedRange errorDescription:(CPString)anError +{ + _CPRaiseInvalidAbstractInvocation(self, @selector(isPartialStringValue:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:)); + return nil; +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + return [self init]; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + +} + +@end \ No newline at end of file From 78a75924de13b537ee069de723866931ac8a8168 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 7 Jul 2010 16:46:48 -0500 Subject: [PATCH 075/356] selectedRowIndexes should return a copy, closes #605 --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index d40747df6..465fe7f84 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1040,7 +1040,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (CPIndexSet)selectedRowIndexes { - return _selectedRowIndexes; + return [_selectedRowIndexes copy]; } - (void)deselectColumn:(CPInteger)aColumn From 2a4d3507b800badce6c9ed917a2ae36078071f45 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 7 Jul 2010 19:49:16 -0500 Subject: [PATCH 076/356] Implementation fix for CPFormatter to conform to documentation. --- Foundation/CPFormatter.j | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j index 7fa3665d5..a58f6cdc2 100644 --- a/Foundation/CPFormatter.j +++ b/Foundation/CPFormatter.j @@ -75,8 +75,7 @@ */ - (CPString)editingStringForObjectValue:(id)anObject { - _CPRaiseInvalidAbstractInvocation(self, @selector(editingStringForObjectValue:)); - return nil; + return [self stringForObjectValue:anObject]; } From 478b5eaba36980f286878b9d79de64187dad4cda Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Fri, 9 Jul 2010 12:46:54 +0200 Subject: [PATCH 077/356] make sure CPWindow center never puts it's window origin at a negative coordinate --- AppKit/CPWindow/CPWindow.j | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 75650792f..cb0276791 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1365,7 +1365,15 @@ CPTexturedBackgroundWindowMask var size = [self frame].size, containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size; - [self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)]; + var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0); + + if (origin.x < 0.0) + origin.x = 0.0; + + if (origin.y < 0.0) + origin.y = 0.0; + + [self setFrameOrigin:origin]; } /*! From 7696b300673c2177bbc572a22008192273adc8a0 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sun, 11 Jul 2010 16:57:17 -0500 Subject: [PATCH 078/356] Added tests for CPFormatter and Foundation import. --- Foundation/CPFormatter.j | 2 +- Foundation/Foundation.j | 1 + Tests/Foundation/CPFormatterTest.j | 44 ++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Tests/Foundation/CPFormatterTest.j diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j index a58f6cdc2..a5465aed8 100644 --- a/Foundation/CPFormatter.j +++ b/Foundation/CPFormatter.j @@ -151,7 +151,7 @@ - (BOOL)isPartialStringValue:(CPString)aPartialString proposedSelectedRange:(CPRange)aProposedSelectedRange originalString:(CPString)originalString originalSelectedRange:(CPRange)originalSelectedRange errorDescription:(CPString)anError { _CPRaiseInvalidAbstractInvocation(self, @selector(isPartialStringValue:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:)); - return nil; + return NO; } - (id)initWithCoder:(CPCoder)aCoder diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index a49654dd4..f7a65ae8f 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -28,6 +28,7 @@ @import "CPDictionary.j" @import "CPEnumerator.j" @import "CPException.j" +@import "CPFormatter.j" @import "CPIndexSet.j" @import "CPInvocation.j" @import "CPJSONPConnection.j" diff --git a/Tests/Foundation/CPFormatterTest.j b/Tests/Foundation/CPFormatterTest.j new file mode 100644 index 000000000..232d23645 --- /dev/null +++ b/Tests/Foundation/CPFormatterTest.j @@ -0,0 +1,44 @@ +@import + +@implementation CPFormatterTest : OJTestCase + +- (void)testThatCPFormatterIsConstructed +{ + [self assertNotNull:[[CPFormatter alloc] init]]; +} + +- (void)testStringForObjectValue +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter stringForObjectValue:@"Hello World"]; }]; +} + +- (void)testEditingStringForObjectValue +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter editingStringForObjectValue:@"Hello Wolrd"]; }]; +} + +- (void)testGetObjectValueForString +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter getObjectValue:@"Hello World" forString:@"Hello World" errorDescription:nil]; }]; +} + +- (void)testIsPartialStringValidNewEditingString +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter isPartialStringValid:@"Hello Wolrd" newEditingString:@"Hello World" errorDescription:nil]; }]; +} + +- (void)testIsPartialStringValueProposedSelectedRange +{ + var formatter = [[CPFormatter alloc] init]; + + [self assertThrows:function(){ [formatter isPartialStringValue:@"Hello Wolrd" proposedSelectedRange:CPRangeMake(3,5) originalString:@"Hello World" originalSelectedRange:nil errorDescription:nil]; }]; +} +@end \ No newline at end of file From 914175de70921f31a4b092a950522fa27c27ed40 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 12 Jul 2010 15:41:00 +0200 Subject: [PATCH 079/356] If CPValueTransformerNameBindingOption contains an existing class, allocate and use it in CPKeyValueBinding --- AppKit/CPKeyValueBinding.j | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index a926cdd2b..89fd10c13 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -181,7 +181,22 @@ var CPBindingOperationAnd = 0, valueTransformer; if (valueTransformerName) + { + if (valueTransformerName === @"ESIsEmptyIndexSetValueTransformer") + debugger; + valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; + + if (!valueTransformer) + { + var valueTransformerClass = CPClassFromString(valueTransformerName); + if (valueTransformerClass) + { + valueTransformer = [[valueTransformerClass alloc] init]; + [valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName]; + } + } + } else valueTransformer = [options objectForKey:CPValueTransformerBindingOption]; From 70f2d86b586d0051a40287a0938445fc5891bd5d Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 12 Jul 2010 20:45:30 -0500 Subject: [PATCH 080/356] Fixes for adding and removing columns to the tableview after the tableview has already been displayed... There are still issues though. --- AppKit/CPTableView.j | 22 ++++++- Tests/Manual/TableTest/AppController.j | 83 ++++++++++++++++++++------ 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 465fe7f84..9d766232a 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -220,6 +220,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; CPColor _sourceListActiveBottomLineColor; int _draggedColumnIndex; + CPArray _differedColumnDataToRemove; /* CPGradient _sourceListInactiveGradient; @@ -340,6 +341,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _sourceListInactiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [168.0/255.0,183.0/255.0,205.0/255.0,1.0,157.0/255.0,174.0/255.0,199.0/255.0,1.0], [0,1], 2); _sourceListInactiveTopLineColor = [CPColor colorWithCalibratedRed:(173.0/255.0) green:(187.0/255.0) blue:(209.0/255.0) alpha:1.0]; _sourceListInactiveBottomLineColor = [CPColor colorWithCalibratedRed:(150.0/255.0) green:(161.0/255.0) blue:(183.0/255.0) alpha:1.0];*/ + _differedColumnDataToRemove = [ ]; } /*! @@ -725,6 +727,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _dirtyTableColumnRangeIndex = MIN(NUMBER_OF_COLUMNS() - 1, _dirtyTableColumnRangeIndex); + [self tile]; [self setNeedsLayout]; } @@ -742,8 +745,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (index === CPNotFound) return; + // we differ the actual removal until the end of the runloop in order to keep a reference to the column. + [_differedColumnDataToRemove addObject:{"column":aTableColumn, "shouldBeHidden": [aTableColumn isHidden]}]; + + [aTableColumn setHidden:YES]; [aTableColumn setTableView:nil]; - [_tableColumns removeObjectAtIndex:index]; var tableColumnUID = [aTableColumn UID]; @@ -2244,6 +2250,20 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [dataViews[count] removeFromSuperview]; } + // if we have any columns to remove do that here + if ([_differedColumnDataToRemove count]) + { + for (var i = 0; i < _differedColumnDataToRemove.length; i++) + { + var data = _differedColumnDataToRemove[i], + column = data.column; + + [column setHidden:data.shouldBeHidden]; + [_tableColumns removeObject:column]; + } + [_differedColumnDataToRemove removeAllObjects]; + } + } - (void)_unloadDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns diff --git a/Tests/Manual/TableTest/AppController.j b/Tests/Manual/TableTest/AppController.j index f383bcc8a..2c0d275f1 100644 --- a/Tests/Manual/TableTest/AppController.j +++ b/Tests/Manual/TableTest/AppController.j @@ -10,6 +10,8 @@ tableTestDragType = @"CPTableViewTestDragType"; CPImage iconImage; CPArray dataSet1; CPArray dataSet2; + + CPTableColumn randomColumn; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification @@ -68,6 +70,9 @@ tableTestDragType = @"CPTableViewTestDragType"; [column setEditable:YES]; [tableView addTableColumn:column]; + + if (i === 2) + randomColumn = column; } // we offset this scrollview to make sure all the coordinates are calculated correctly @@ -95,16 +100,34 @@ tableTestDragType = @"CPTableViewTestDragType"; [button setAction:@selector(addRow:)]; [contentView addSubview:button]; - var sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [255.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), - sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], - sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0]; - [tableView setSelectionGradientColors:[CPDictionary dictionaryWithObjects:[sourceListActiveGradient, sourceListActiveTopLineColor, sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]]; - var button = [[CPButton alloc] initWithFrame:CGRectMake(10,70,100, 24)]; [button setTitle:@"Switch Highlight"]; [button setTarget:self]; [button setAction:@selector(switchSelectionHighlightType:)]; [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,100,100, 24)]; + [button setTitle:@"Hide Column"]; + [button setTarget:self]; + [button setAction:@selector(hideColumn:)]; + [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,130,100, 24)]; + [button setTitle:@"Remove Column"]; + [button setTarget:self]; + [button setAction:@selector(removeColumn:)]; + [contentView addSubview:button]; + + var button = [[CPButton alloc] initWithFrame:CGRectMake(10,160,100, 24)]; + [button setTitle:@"Add Column"]; + [button setTarget:self]; + [button setAction:@selector(addColumn:)]; + [contentView addSubview:button]; + + var sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [255.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), + sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], + sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(255.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0]; + [tableView setSelectionGradientColors:[CPDictionary dictionaryWithObjects:[sourceListActiveGradient, sourceListActiveTopLineColor, sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]]; } - (void)switchSelectionHighlightType:(id)sender @@ -124,6 +147,31 @@ tableTestDragType = @"CPTableViewTestDragType"; [tableView reloadData]; } +- (void)hideColumn:(id)sender +{ + [randomColumn setHidden:![randomColumn isHidden]]; +} + +- (void)removeColumn:(id)sender +{ + // if ([[tableView tableColumns] containsObject:randomColumn]) + [tableView removeTableColumn:randomColumn]; + //else + // [tableView addTableColumn:randomColumn]; +} + +- (void)addColumn:(id)sender +{ + var column = [[CPTableColumn alloc] initWithIdentifier:"NewColumn"]; + [[column headerView] setStringValue:"New Column"]; + + [column setMinWidth:50.0]; + [column setMaxWidth:500.0]; + [column setWidth:75.0]; + + [tableView addTableColumn:column]; +} + - (void)newWindow { @@ -237,7 +285,7 @@ tableTestDragType = @"CPTableViewTestDragType"; return iconImage; if (aTableView === tableView) - return String(dataSet1[aRow]); + return String(dataSet1[aRow]* ([[aTableView tableColumns] indexOfObject:aColumn] + 1)); else if (aTableView === tableView2) return String(dataSet2[aRow]); else if(aTableView === tableView3) @@ -246,7 +294,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors { - CPLogConsole(_cmd + [oldDescriptors description]); + //CPLogConsole(_cmd + [oldDescriptors description]); var newDescriptors = [aTableView sortDescriptors]; @@ -257,39 +305,39 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableViewSelectionIsChanging:(CPNotification)aNotification { - CPLog.debug(@"changing! %@", [aNotification description]); + //CPLog.debug(@"changing! %@", [aNotification description]); } - (void)tableViewSelectionDidChange:(CPNotification)aNotification { - CPLog.debug(@"did change! %@", [aNotification description]); + //CPLog.debug(@"did change! %@", [aNotification description]); } - (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex { - CPLog.debug(@"tableView:shouldSelectRow"); + //CPLog.debug(@"tableView:shouldSelectRow"); return true; } - (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView { - CPLog.debug(@"selectionShouldChangeInTableView"); + //CPLog.debug(@"selectionShouldChangeInTableView"); return YES; } - (void)tableViewSelectionDidChange:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (void)tableViewSelectionIsChanging:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (void)_tableViewColumnDidResize:(id)notification { - CPLogConsole(_cmd + [notification description]); + //CPLogConsole(_cmd + [notification description]); } - (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)tableColumn row:(int)row { @@ -301,7 +349,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView willDisplayView:(CPView)aView forTableColumn:(CPTableColumn)tableColumn row:(int)row { - CPLogConsole(_cmd + " column: " + [tableColumn identifier] + " row:" + row) + //CPLogConsole(_cmd + " column: " + [tableColumn identifier] + " row:" + row) } - (void)tableView:(CPTableView)aTableView setObjectValue:(id)aValue forTableColumn:(CPTableColumn)tableColumn row:(int)row @@ -312,7 +360,7 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors { - CPLogConsole(_cmd + [oldDescriptors description]); + //CPLogConsole(_cmd + [oldDescriptors description]); var newDescriptors = [aTableView sortDescriptors]; @@ -403,13 +451,12 @@ tableTestDragType = @"CPTableViewTestDragType"; - (void)tableView:(CPTableView)aTableView didClickTableColumn:(CPTableColumn)aColumn { - CPLog.debug("table: "+aTableView+" clicked column: "+aColumn); + //CPLog.debug("table: "+aTableView+" clicked column: "+aColumn); } @end @implementation CPArray (MoveIndexes) - - (void)moveIndexes:(CPIndexSet)indexes toIndex:(int)insertIndex { var aboveCount = 0, From 0cbdb3b2d1b475a70111337f689ad3f6c688ebe3 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 12 Jul 2010 21:14:48 -0500 Subject: [PATCH 081/356] Fix for redrawing issues in tableview. Closes #627 --- AppKit/CPTableView.j | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 9d766232a..ad854587a 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -880,7 +880,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _selectedColumnIndexes = [columns copy]; [self _updateHighlightWithOldColumns:previousSelectedIndexes newColumns:_selectedColumnIndexes]; - [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected columns + [self setNeedsDisplay:YES]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected columns // but currently -drawRect: is not implemented here if (_headerView) [_headerView setNeedsDisplay:YES]; @@ -896,7 +896,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _selectedRowIndexes = [rows copy]; [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; - [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows + [self setNeedsDisplay:YES]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows // but currently -drawRect: is not implemented here [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectedRowIndexes"]; @@ -2237,7 +2237,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [_tableDrawView setFrame:exposedRect]; - [_tableDrawView display]; + [self setNeedsDisplay:YES]; // Now clear all the leftovers // FIXME: this could be faster! @@ -2474,6 +2474,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview]; } +- (void)setNeedsDisplay:(BOOL)aFlag +{ + [super setNeedsDisplay:aFlag]; + [_tableDrawView setNeedsDisplay:aFlag]; +} + - (void)_drawRect:(CGRect)aRect { // FIX ME: All three of these methods will likely need to be rewritten for 1.0 From 36bb41a9453ccfc44929ddf8f01345bd241f416d Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 15 Jul 2010 12:49:52 +0200 Subject: [PATCH 082/356] implemented isEqual: on CPString --- Foundation/CPString.j | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index abbe70c2d..1ebae87ea 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -512,6 +512,18 @@ var CPStringRegexSpecialCharacters = [ return aString && aString != "" && length >= aString.length && lastIndexOf(aString) == (length - aString.length); } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (![anObject isKindOfClass:[CPString class]]) + return NO; + + return [self isEqualToString:anObject]; +} + + /*! Returns \c YES if the specified string contains the same characters as the receiver. */ From 023cf4604132613527af60140316d3eb878e8807 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 15 Jul 2010 14:39:24 +0200 Subject: [PATCH 083/356] check for nil in CPString isEqual: --- Foundation/CPString.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 1ebae87ea..877604f4c 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -517,7 +517,7 @@ var CPStringRegexSpecialCharacters = [ if (self === anObject) return YES; - if (![anObject isKindOfClass:[CPString class]]) + if (!anObject || ![anObject isKindOfClass:[CPString class]]) return NO; return [self isEqualToString:anObject]; From 564668587c0948da64f72b9cc610b8032db82aa1 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 15 Jul 2010 14:42:48 +0200 Subject: [PATCH 084/356] fix CPDate isEqual: and isEqualToDate: --- Foundation/CPDate.j | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index cba9ec382..07ff8fbb3 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -148,12 +148,21 @@ var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); - (BOOL)isEqual:(CPDate)aDate { + if (self === aDate) + return YES; + + if (!aDate || ![aDate isKindOfClass:[CPDate class]]) + return NO; + return [self isEqualToDate:aDate]; } -- (BOOL)isEqualToDate:(CPDate)anotherDate +- (BOOL)isEqualToDate:(CPDate)aDate { - return self === anotherDate || (anotherDate !== nil && anotherDate.isa && [anotherDate isKindOfClass:CPDate] && !(self < anotherDate || self > anotherDate)); + if (!aDate) + return NO; + + return self === aDate; } - (CPComparisonResult)compare:(CPDate)anotherDate From a2e6f8f96445163cc4d5395760d0ad86e9b4995c Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 15 Jul 2010 22:23:05 -0500 Subject: [PATCH 085/356] Initial theming of TableView header. --- AppKit/CPTableHeaderView.j | 47 +++++++++--------- ...bleview-headerview-highlighted-pressed.png | Bin .../tableview-headerview-highlighted.png | Bin .../tableview-headerview-pressed.png | Bin .../Resources/tableview-headerview.png | Bin .../Aristo/Resources/tableviewselection.png | Bin 0 -> 4120 bytes AppKit/Themes/Aristo/ThemeDescriptors.j | 28 ++++++++++- 7 files changed, 51 insertions(+), 24 deletions(-) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview-highlighted-pressed.png (100%) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview-highlighted.png (100%) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview-pressed.png (100%) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview.png (100%) create mode 100644 AppKit/Themes/Aristo/Resources/tableviewselection.png diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 76f71f426..223cfec2b 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -23,53 +23,59 @@ @import "CPTableColumn.j" @import "CPTableView.j" @import "CPView.j" + +#include "CoreGraphics/CGGeometry.h" @implementation _CPTableColumnHeaderView : CPView { _CPImageAndTextView _textField; } ++ (CPString)themeClass +{ + return @"tableHeader"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()] + forKeys:[@"background-color", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]]; +} + - (void)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) - { [self _init]; - } return self; } - (void)_init { - _textField = [[_CPImageAndTextView alloc] initWithFrame: - CGRectMake(5.0, 0.0, CGRectGetWidth([self bounds]) - 10.0, CGRectGetHeight([self bounds]))]; - + _textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; + [_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_textField setLineBreakMode:CPLineBreakByTruncatingTail]; - [_textField setTextColor:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]]; - [_textField setFont:[CPFont boldSystemFontOfSize:12.0]]; [_textField setAlignment:CPLeftTextAlignment]; [_textField setVerticalAlignment:CPCenterVerticalTextAlignment]; - [_textField setTextShadowColor:[CPColor whiteColor]]; - [_textField setTextShadowOffset:CGSizeMake(0,1)]; [self addSubview:_textField]; } - (void)layoutSubviews { - var themeState = [self themeState]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; - if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 23.0))]]; - else if (themeState & CPThemeStateSelected) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 23.0))]]; - else if (themeState & CPThemeStateHighlighted) - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 23.0))]]; - else - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + var inset = [self currentValueForThemeAttribute:@"text-inset"], + bounds = [self bounds]; + + [_textField setFrame:CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)]; + [_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; + [_textField setFont:[self currentValueForThemeAttribute:@"text-font"]]; + [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]]; + [_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; } - (void)setStringValue:(CPString)string @@ -97,11 +103,6 @@ [_textField setFont:aFont]; } -- (void)setValue:(id)aValue forThemeAttribute:(id)aKey -{ - [_textField setValue:aValue forThemeAttribute:aKey]; -} - - (void)_setIndicatorImage:(CPImage)anImage { if (anImage) diff --git a/AppKit/Resources/tableview-headerview-highlighted-pressed.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted-pressed.png similarity index 100% rename from AppKit/Resources/tableview-headerview-highlighted-pressed.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted-pressed.png diff --git a/AppKit/Resources/tableview-headerview-highlighted.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png similarity index 100% rename from AppKit/Resources/tableview-headerview-highlighted.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-highlighted.png diff --git a/AppKit/Resources/tableview-headerview-pressed.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-pressed.png similarity index 100% rename from AppKit/Resources/tableview-headerview-pressed.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-pressed.png diff --git a/AppKit/Resources/tableview-headerview.png b/AppKit/Themes/Aristo/Resources/tableview-headerview.png similarity index 100% rename from AppKit/Resources/tableview-headerview.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview.png diff --git a/AppKit/Themes/Aristo/Resources/tableviewselection.png b/AppKit/Themes/Aristo/Resources/tableviewselection.png new file mode 100644 index 0000000000000000000000000000000000000000..990a98983429c7bb999e18fdbd2af84166d80bdb GIT binary patch literal 4120 zcmV+z5a;iSP)X0ssI2fAZ5P00009a7bBm000XU z000XU0RWnu7ytkdQ)xp(P*7-ZbZ>KLZ*U+<0a{dABFEm>*9-nfn|%%l06?!EmBV4e|ILWp;E+%NL>B-gqnEKA07ynI;{X7V zOyO~O07wh~NYY}cbO0nB0Cc$l6h{E$8~_lbmvIvS5F?lIJpdpk)1r9*$O`}*iA9fP z0pKS9a5i*CA`O733jlO_A}t<(cmM$95FgK`1Bg8X04*Aa%L5Sm1pw;7A)(}D$x&zk z%Lf3s!GC<4=K$*R0aT{{@u?30NOb~K1^wfjrT_u}i1g#cs5M3a0DuTP0AOG9`O}&J z_#%MCLOy??lFwf}34k5~Xk*fnxXHigg&+?B{gMqAcAH8C|UH=DL_vMjdxWNl-UVtd6Najkh`{r zizm%1)4Rl{dEHw-6lJBqSHR}Lo$D)tZU*;c>q^xKspGhM$Z%m2!IPnY^eXb|Y;;Ynh19Zied5MIYwOL6ZHI1cyB*!`e`jrnW~X@P{N3Su zE%#4%?S8=P4tl8faQ0F4&w)raqv^wc=&|c z#OP$r=aeswUx{Bod~2FIFwLIv`))C-^FwD&Z{GH2%tF;7ajA*V2LLfJ2Oiu;$jB~) zk19f&q9-snut#zG@rMYt0=+_LVNa1l;u|q*@govA$<0y^Wz1!3<>chk6-Jcol+UP$ zsK%&uYZz$etsGjVrOnl8*OSx_SY2!|WTdtx*!ZN$fEk!uS|nRmSlwGYWus#2YZq-_ zzOLT4&F=x_x&K(eRN(CTrC^Z|Qm90j!UmO% z3gPk*@|)zT%8_z3DY^thAPS=9qd&*Ii+vH-z4(X~k#=@#ar%yo*lim!U9t?b<#NzDliP=K`*sZP{F?VGAG=#{k9dLNUfq2r z`)v-`6}lIN{XsoQFXkNDTC(Htp3?ngCyrDctt)Ri)^YsNiRTrsDo0LEocehNeU@;J zcwV+jtJ=86y4L*yr7rj)<5E(6dPDBzeOJmFtFPW@y4~D;?On^*_1RX!O;Ve}E$!P@ z?S6L{9o)|JyIb$k?mKp=bS*yU>AvtV?-A{>?Gx!IA9~uKmiKa=IrYi)eR%{`aDWqVDjgnNUIO$ZGJlVn( z<#P4%w-h=R`;|T^e(T8(;F z^_q;E9j^JcP_HN6*x6cs^KRSlt%Y{=J02ZrotN%@yszH1=|N@p+#~ru0tt z<@ZaxXc$NsTJvggc;Ovp)OD=-qveFC32ta@Zp!6jH`F4Ep^y&ca0^Bd45Ed2Aspl&(u@qFa43CL zASwfO8ubJ{iznb+@jLK$ z2_l5`gfha2fSv$P;Ete_AYHIQ2rm>N)Fez2ju*Zsq9L+JWSSU6ye6t4S}rCmwpHw_ zI7@tz6i@mp!IPMm+%6?7bwFB1`jm{m%r#k0+2Iw*a)NTF0`BNZLD>QO^$7aU9VPhNk;YtzKn}Vo0k(IRj40M!XG(Dy)ws$iy z9pZPfo^a$7V!2lmmy$LmH*OJ0Wu-kyH_14eDW0`0o4=izJGnDHZz4Zt_m=|B-nsp` zg<3`R2R)1XO171{9tkLC9^X-M_2lC-m~-Y;2{orLj9gmL5Ow9))%VxdUQcX&d`qOA z+Hv(B(iPHu{Ly%ib#H!O%L~$g-%$4JJ8z~&Wd3w}Px+WUzHKt&OVYQ{Y2}%*+0r@P z`LhcGzbK30OIdtA02o3P9D)w`hA1KK2oE`qbRn}SGRg~;hB}LShDM`}&{T90x&u9r z(Zg)Q9Kt-r;;|0c4D5C6Pn-oV6?X#5{wYC$5JPAZ5D*9zs1{ff3=+H~BqYQT zx+Sb3oGtuL#8c!Nkxa}Z&Wgs0z7q2j>kzjTzd6o&o@*Mf1N}Q^)>Y!SMdZflmjS0<*E3>rLtx{a| zL;I1=8QooaQTnc{4GiQAafUNSBWs=-x0|$?UN&nmZ?LGhY_@7$+iCsG=8f$qdyE6o zaix=u^9GkR*All{_j->i&uXta?`EI7>w0|q{e~&u0+2wZ^?E_(!GR&X(EPB<4L3Kw zjlgYEqIyQg(e~0C7(>zc7}MCOxYEtHnNuunHjPuB@Gud0R!Papmr|xu&C?RL)~5g1 zW}CS)>p_mlcAwme9aDMwyLRXI?@=n??tQSId?2y#_8+1LBa3gBs2naUvpX_gUUod9 zLaMU&RKXeVbL!{cSJ%}R)NQ(C)}U~Crg5mL`P${{<*nIm^xI)~)^-}-BX>!3i#(ir zJlxaK+t_!mf6q(ipvNnlVd*zh@1Bj;j^%t<|4C_le6rV1k?>T&SfE@GFUS=f777r$BWx|)B%&+QKr|*^6?GJSAQmn*ExwziOX`+LmXww3 zlFE=akbWyuB1>5zxuRdLSUyBSO<_v$no^-Mjl4!hNM%B`Q|**`o(5YpY^9f$%_@Cu z9UWC&H9aMLt<`!4W`=G?VQbjN`%TW8J~sPdp={}DmAJOnddybIZiD?1hhZmO=S-Jp zZgTECk6teg?|nWKz7)S2{}lllfggh0gPTKD!-_T%!qXzAsZo&wbbrR8TlWnR(grIrX`&J09oJcFpfTT41#I*?w-JaM87c zl;Xvbqot&>jn;E*+P7-j_3zYm8r-e9PwXn_7JA5iH1fo+=VCAM8ME(xzs8HKm(K@fhk{=n ze%=2@>MiA6-pGZ~_CE*5_#dP`s(n%&SD8?rRQ$Z+^WvA+Ut7PGPsL0dPEXHV`W`<^ zp6&aQG$%ZFYTkJM=1n#bID$gPVoP0@yw*ZYLEaxm=)=>?l=Cx;rRvtfHVO7OicE71^_VtL@X-S z#r-!X)2U9L0H6SX7^KBG`T&410OA$Jb)hVCk>EJ0hc5sS0T33073ja5A4%sheZ79; zeH@+x1ps6LkQ0nV=f7f_(qaOFesjCHNt8eUPzOL>Y-W2>e%Ja%XE^=Vh9a<-K3>ap zQL?c-_W%Hp1VHJ73s8Xz(ZB#b@B&A0`hAjt3S@8uHgJIfiQodGz=i0)qt?SHa3S{J zSb7izRNz7~Fdz{&!x(TOJ|Z@U3*>*xP6IY10TURI1YCn^gO3Kk{*G}3HZXw=|FAs& z!}C|3e_~^S4($Jyp9yT>M#ScDuZjP_sD!1Dhc001Wja5NtPp#9Rh z|9ERW#ugp`fFqle%8iYV;gRh*9414T?9QU;>ynKO3@qSZ|3*#j6L7Te0000WV@Og> z003>6004820083T004&j004F2007N%001(r000`@>!5p60000#NklJQ z5X7SEC@7eVy_k-T^7hlDAeCj=<9^;;=aD%p+9_NlMaSjfuNgJi0YVux(9!(^z5xLI W6h=jOJE+9~0000 @import +@import @implementation AristoThemeDescriptor : BKThemeDescriptor @@ -772,6 +773,31 @@ return buttonBar; } ++ (_CPTableColumnHeaderView)themedTableHeader +{ + var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMake(0,0,50,24)], + highlightedPressed = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-highlighted-pressed.png" size:CGSizeMake(1.0, 23.0)]], + highlighted = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-highlighted.png" size:CGSizeMake(1.0, 23.0)]], + pressed = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-pressed.png" size:CGSizeMake(1.0, 23.0)]], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + + [header setStringValue:@"Table Header"]; + + [header setValue:normal forThemeAttribute:@"background-color"]; + [header setValue:CGInsetMake(0, 5, 0, 5) forThemeAttribute:@"text-inset"]; + [header setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] forThemeAttribute:@"text-color"]; + [header setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"text-font"]; + [header setValue:[CPColor whiteColor] forThemeAttribute:@"text-shadow-color"]; + [header setValue:CGSizeMake(0,1) forThemeAttribute:@"text-shadow-offset"]; + + [header setValue:pressed forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted]; + [header setValue:highlighted forThemeAttribute:@"background-color" inState:CPThemeStateSelected]; + [header setValue:highlightedPressed forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted|CPThemeStateSelected]; + + return header; +} + @end @implementation AristoHUDThemeDescriptor : BKThemeDescriptor @@ -1179,4 +1205,4 @@ function PatternColor(anImage) { return [CPColor colorWithPatternImage:anImage]; -} +} \ No newline at end of file From 780bdc44213237aecdae9ca2208decd034c4f4a8 Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Sun, 18 Jul 2010 03:05:31 -0400 Subject: [PATCH 086/356] Generate accessors for _CPSegmentInfo. --- AppKit/CPSegmentedControl.j | 103 +++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/AppKit/CPSegmentedControl.j b/AppKit/CPSegmentedControl.j index e7e60d860..4b5f0e3d8 100644 --- a/AppKit/CPSegmentedControl.j +++ b/AppKit/CPSegmentedControl.j @@ -82,7 +82,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (int)selectedTag { - return _segments[_selectedSegment].tag; + return [_segments[_selectedSegment] tag]; } // Specifying the number of segments @@ -183,7 +183,7 @@ CPSegmentSwitchTrackingMomentary = 2; selected = NO; for (; index < _segments.length; ++index) - if (_segments[index].selected) + if ([_segments[index] selected]) if (selected) [self setSelected:NO forSegment:index]; else @@ -195,7 +195,7 @@ CPSegmentSwitchTrackingMomentary = 2; var index = 0; for (; index < _segments.length; ++index) - if (_segments[index].selected) + if ([_segments[index] selected]) [self setSelected:NO forSegment:index]; } } @@ -217,7 +217,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment { - _segments[aSegment].width = aWidth; + [_segments[aSegment] setWidth:aWidth]; [self tileWithChangedSegment:aSegment]; } @@ -229,7 +229,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (float)widthForSegment:(unsigned)aSegment { - return _segments[aSegment].width; + return [_segments[aSegment] width]; } /*! @@ -240,9 +240,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment { - var segment = _segments[aSegment]; - - segment.image = anImage; + [_segments[aSegment] setImage:anImage]; [self tileWithChangedSegment:aSegment]; } @@ -254,7 +252,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (CPImage)imageForSegment:(unsigned)aSegment { - return _segments[aSegment].image; + return [_segments[aSegment] image]; } /*! @@ -265,9 +263,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment { - var segment = _segments[aSegment]; - - _segments[aSegment].label = aLabel; + [_segments[aSegment] setLabel:aLabel]; [self tileWithChangedSegment:aSegment]; } @@ -279,7 +275,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (CPString)labelForSegment:(unsigned)aSegment { - return _segments[aSegment].label; + return [_segments[aSegment] label]; } /*! @@ -290,7 +286,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment { - _segments[aSegment].menu = aMenu; + [_segments[aSegment] setMenu:aMenu]; } /*! @@ -300,7 +296,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (CPMenu)menuForSegment:(unsigned)aSegment { - return _segments[aSegment].menu; + return [_segments[aSegment] menu]; } /*! @@ -315,10 +311,10 @@ CPSegmentSwitchTrackingMomentary = 2; var segment = _segments[aSegment]; // If we're already in this state, bail. - if (segment.selected == isSelected) + if ([segment selected] == isSelected) return; - segment.selected = isSelected; + [segment setSelected:isSelected]; _themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal; @@ -331,7 +327,7 @@ CPSegmentSwitchTrackingMomentary = 2; if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1) { - _segments[oldSelectedSegment].selected = NO; + [_segments[oldSelectedSegment] setSelected:NO]; _themeStates[oldSelectedSegment] = CPThemeStateNormal; [self drawSegmentBezel:oldSelectedSegment highlight:NO]; @@ -352,7 +348,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (BOOL)isSelectedForSegment:(unsigned)aSegment { - return _segments[aSegment].selected; + return [_segments[aSegment] selected]; } /*! @@ -363,6 +359,8 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment { + [_segments[aSegment] setEnabled:isEnabled]; + if (isEnabled) _themeStates[aSegment] &= ~CPThemeStateDisabled; else @@ -379,7 +377,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (BOOL)isEnabledForSegment:(unsigned)aSegment { - return !(_themeStates[aSegment] & CPThemeStateDisabled) + return [_segments[aSegment] enabled]; } /*! @@ -389,7 +387,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (void)setTag:(int)aTag forSegment:(unsigned)aSegment { - _segments[aSegment].tag = aTag; + [_segments[aSegment] setTag:aTag]; } /*! @@ -398,7 +396,7 @@ CPSegmentSwitchTrackingMomentary = 2; */ - (int)tagForSegment:(unsigned)aSegment { - return _segments[aSegment].tag; + return [_segments[aSegment] tag]; } // Drawings @@ -461,7 +459,7 @@ CPSegmentSwitchTrackingMomentary = 2; else if (aName.indexOf("segment-bezel") === 0) { var segment = parseInt(aName.substring("segment-bezel-".length), 10), - frame = CGRectCreateCopy(_segments[segment].frame); + frame = CGRectCreateCopy([_segments[segment] frame]); if (segment === 0) { @@ -556,8 +554,8 @@ CPSegmentSwitchTrackingMomentary = 2; positioned:CPWindowAbove relativeToEphemeralSubviewNamed:@"segment-bezel-"+i]; - [contentView setText:segment.label]; - [contentView setImage:segment.image]; + [contentView setText:[segment label]]; + [contentView setImage:[segment image]]; [contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]]; [contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]]; @@ -568,9 +566,9 @@ CPSegmentSwitchTrackingMomentary = 2; [contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]]; [contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]]; - if (segment.image && segment.label) + if ([segment image] && [segment label]) [contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]]; - else if (segment.image) + else if ([segment image]) [contentView setImagePosition:CPImageOnly]; if (i == count - 1) @@ -609,27 +607,32 @@ CPSegmentSwitchTrackingMomentary = 2; return; var segment = _segments[aSegment], - segmentWidth = segment.width, + segmentWidth = [segment width], themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled), contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState], font = [self valueForThemeAttribute:@"font" inState:themeState]; if (!segmentWidth) { - if (segment.image && segment.label) - segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right; + if ([segment image] && [segment label]) + segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right; else if (segment.image) - segmentWidth = [segment.image size].width + contentInset.left + contentInset.right; + segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right; else if (segment.label) - segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right; + segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right; else segmentWidth = 0.0; } - var delta = segmentWidth - CGRectGetWidth(segment.frame); + var delta = segmentWidth - CGRectGetWidth([segment frame]); if (!delta) + { + [self setNeedsLayout]; + [self setNeedsDisplay:YES]; + return; + } // Update Contorl Size var frame = [self frame]; @@ -637,15 +640,15 @@ CPSegmentSwitchTrackingMomentary = 2; [self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))]; // Update Segment Width - segment.width = segmentWidth; - segment.frame = [self frameForSegment:aSegment];; + [segment setWidth:segmentWidth]; + [segment setFrame:[self frameForSegment:aSegment]]; // Update Following Segments Widths var index = aSegment + 1; for (; index < _segments.length; ++index) { - _segments[index].frame.origin.x += delta; + [_segments[index] frame].origin.x += delta; [self drawSegmentBezel:index highlight:NO]; [self drawSegment:index highlight:NO]; @@ -698,12 +701,12 @@ CPSegmentSwitchTrackingMomentary = 2; count = _segments.length; while (count--) - if (CGRectContainsPoint(_segments[count].frame, aPoint)) + if (CGRectContainsPoint([_segments[count] frame], aPoint)) return count; if (_segments.length) { - var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame); + var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]); adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x; if (CGRectContainsPoint(adjustedLastFrame, aPoint)) @@ -844,7 +847,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey", for (var i = 0; i < _segments.length; i++) { - _themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal; + _themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal; [self tileWithChangedSegment:i]; } @@ -852,7 +855,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey", remainingWidth = FLOOR(difference / _segments.length); for (var i=0; i < _segments.length; i++) - [self setWidth:_segments[i].width + remainingWidth forSegment:i]; + [self setWidth:[_segments[i] width] + remainingWidth forSegment:i]; [self tileWithChangedSegment:0]; } @@ -875,15 +878,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey", @implementation _CPSegmentItem : CPObject { - CPImage image; - CPString label; - CPMenu menu; - BOOL selected; - BOOL enabled; - int tag; - int width; + CPImage image @accessors; + CPString label @accessors; + CPMenu menu @accessors; + BOOL selected @accessors; + BOOL enabled @accessors; + int tag @accessors; + int width @accessors; - CGRect frame; + CGRect frame @accessors; } - (id)init @@ -894,8 +897,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey", label = @""; menu = nil; selected = NO; - enabled = NO; - tag = 0; + enabled = YES; + tag = -1; width = 0; frame = CGRectMakeZero(); From 2ae8d25d188299b2553cbc81aacad59afdb38fa3 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 19 Jul 2010 13:04:30 +0200 Subject: [PATCH 087/356] don't use === for date equality checking Apparently this will return false for equal dates, reverted the actual equality check to what was already in Cappuccino before my fix !(date < otherDate || date > otherDate) --- Foundation/CPDate.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index 07ff8fbb3..3ecdd21a4 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -162,7 +162,7 @@ var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); if (!aDate) return NO; - return self === aDate; + return !(self < aDate || self > aDate); } - (CPComparisonResult)compare:(CPDate)anotherDate From 85f3691432a3559e23b87a7b4d70be0f02c49482 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Mon, 19 Jul 2010 16:27:44 -0700 Subject: [PATCH 088/356] Don't add a "Shift" if it's not required. --- AppKit/CPMenuItem/CPMenuItem.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index fb352ed69..1e14e2f17 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -591,7 +591,8 @@ CPControlKeyMask return @""; var string = _keyEquivalent.toUpperCase(), - needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent; + needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || + (string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase()); if (CPBrowserIsOperatingSystem(CPMacOperatingSystem)) { From c17a3533ecae63d479b285b23ac3a490ebe8bd3c Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 20 Jul 2010 14:59:18 +0200 Subject: [PATCH 089/356] fix #764 Array controller inserts object in wrong arranged object position if there are no sort descriptors defined --- AppKit/CPArrayController.j | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..72aab18f4 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -400,16 +400,23 @@ if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { - var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; + var position; + if ([_sortDescriptors count] > 0) + position = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; + else + { + [_arrangedObjects addObject:object]; + position = [_arrangedObjects count] - 1; + } if (_selectsInsertedObjects) { - [self setSelectionIndex:pos]; + [self setSelectionIndex:position]; } else { [self willChangeValueForKey:@"selectionIndexes"]; - [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; + [_selectionIndexes shiftIndexesStartingAtIndex:position by:1]; [self didChangeValueForKey:@"selectionIndexes"]; } } From 474623feb3c66108ddee7528f41e3add8f05f4cc Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 20 Jul 2010 22:17:10 -0400 Subject: [PATCH 090/356] =?UTF-8?q?Added=20support=20for=20punctuation=20b?= =?UTF-8?q?ased=20key=20equivalents=20such=20as=20Cmd-'=20or=20Cmd-;.=20Fi?= =?UTF-8?q?xed:=20[event=20characters]=20would=20contain=20=C3=9E=20when?= =?UTF-8?q?=20Cmd-'=20was=20pressed=20and=20=C2=BA=20for=20Cmd-;=20since?= =?UTF-8?q?=20the=20key=20codes=20for=20punctuation=20do=20not=20match=20t?= =?UTF-8?q?he=20ASCII=20codes=20and=20String.fromCharCode=20does=20not=20w?= =?UTF-8?q?ork.=20Manual=20test=20included.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 43 +++++--- Tests/Manual/KeyEquivalents/AppController.j | 78 +++++++++++++ Tests/Manual/KeyEquivalents/Info.plist | 12 ++ Tests/Manual/KeyEquivalents/Jakefile | 93 ++++++++++++++++ .../KeyEquivalents/Resources/spinner.gif | Bin 0 -> 1849 bytes Tests/Manual/KeyEquivalents/index-debug.html | 104 ++++++++++++++++++ Tests/Manual/KeyEquivalents/index.html | 79 +++++++++++++ Tests/Manual/KeyEquivalents/main.j | 18 +++ 8 files changed, 411 insertions(+), 16 deletions(-) create mode 100644 Tests/Manual/KeyEquivalents/AppController.j create mode 100644 Tests/Manual/KeyEquivalents/Info.plist create mode 100644 Tests/Manual/KeyEquivalents/Jakefile create mode 100644 Tests/Manual/KeyEquivalents/Resources/spinner.gif create mode 100644 Tests/Manual/KeyEquivalents/index-debug.html create mode 100644 Tests/Manual/KeyEquivalents/index.html create mode 100644 Tests/Manual/KeyEquivalents/main.j diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 0a51a76a0..7af9e9888 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -140,21 +140,32 @@ var KeyCodesToPrevent = {}, 61: 187, // =, equals 59: 186 // ;, semicolon }, - KeyCodesToFunctionUnicodeMap = {}; + KeyCodesToUnicodeMap = {}; KeyCodesToPrevent[CPKeyCodes.A] = YES; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; +KeyCodesToUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +KeyCodesToUnicodeMap[CPKeyCodes.SEMICOLON] = ";"; +KeyCodesToUnicodeMap[CPKeyCodes.DASH] = "-"; +KeyCodesToUnicodeMap[CPKeyCodes.EQUALS] = "="; +KeyCodesToUnicodeMap[CPKeyCodes.COMMA] = ","; +KeyCodesToUnicodeMap[CPKeyCodes.PERIOD] = "."; +KeyCodesToUnicodeMap[CPKeyCodes.SLASH] = "/"; +KeyCodesToUnicodeMap[CPKeyCodes.APOSTROPHE] = "`"; +KeyCodesToUnicodeMap[CPKeyCodes.SINGLE_QUOTE] = "'"; +KeyCodesToUnicodeMap[CPKeyCodes.OPEN_SQUARE_BRACKET] = "["; +KeyCodesToUnicodeMap[CPKeyCodes.BACKSLASH] = "\\"; +KeyCodesToUnicodeMap[CPKeyCodes.CLOSE_SQUARE_BRACKET] = "]"; var ModifierKeyCodes = [ CPKeyCodes.META, @@ -642,9 +653,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var characters; - // Is this a special key? + // Handle key codes for which String.fromCharCode won't work. if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0) - characters = KeyCodesToFunctionUnicodeMap[_keyCode]; + characters = KeyCodesToUnicodeMap[_keyCode]; if (!characters) characters = String.fromCharCode(_keyCode).toLowerCase(); @@ -724,7 +735,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var characters = overrideCharacters; // Is this a special key? if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)) - characters = KeyCodesToFunctionUnicodeMap[charCode]; + characters = KeyCodesToUnicodeMap[charCode]; if (!characters) characters = String.fromCharCode(charCode); @@ -763,7 +774,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if ([ModifierKeyCodes containsObject:keyCode]) break; - var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), + var characters = KeyCodesToUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive) diff --git a/Tests/Manual/KeyEquivalents/AppController.j b/Tests/Manual/KeyEquivalents/AppController.j new file mode 100644 index 000000000..8dcc6c177 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/AppController.j @@ -0,0 +1,78 @@ +/* + * AppController.j + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + + [label setStringValue:@"Press Cmd-X on the keyboard for each button and verify that it reacts."]; + [label setFont:[CPFont boldSystemFontOfSize:24.0]]; + + [label sizeToFit]; + + [label setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin]; + [label setFrameOrigin:CGPointMake(10, 10)]; + + [contentView addSubview:label]; + + var keysToTest = [ + "a", + ";", + "-", + "=", + ",", + ".", + "/", + "`", + "'", + "[", + "\\", + "]" + ]; + + for (var i=0; i + + + + CPApplicationDelegateClass + AppController + CPBundleName + cappuccino-keyequivalents + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/KeyEquivalents/Jakefile b/Tests/Manual/KeyEquivalents/Jakefile new file mode 100644 index 000000000..8fea6e453 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC 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 ("cappuccinoKeyequivalents", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "cappuccinoKeyequivalents.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("cappuccino-keyequivalents"); + task.setIdentifier("com.yourcompany.cappuccinoKeyequivalents"); + task.setVersion("1.0"); + task.setAuthor("WireLoad, LLC"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("cappuccino-keyequivalents"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["cappuccinoKeyequivalents"], 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", "cappuccinoKeyequivalents", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "cappuccinoKeyequivalents", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "cappuccinoKeyequivalents")); + OS.system(["press", "-f", FILE.join("Build", "Release", "cappuccinoKeyequivalents"), FILE.join("Build", "Deployment", "cappuccinoKeyequivalents")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "cappuccinoKeyequivalents")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "cappuccinoKeyequivalents"), FILE.join("Build", "Desktop", "cappuccinoKeyequivalents", "cappuccinoKeyequivalents.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "cappuccinoKeyequivalents", "cappuccinoKeyequivalents.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "cappuccinoKeyequivalents")); + print("----------------------------"); +} diff --git a/Tests/Manual/KeyEquivalents/Resources/spinner.gif b/Tests/Manual/KeyEquivalents/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/KeyEquivalents/index-debug.html b/Tests/Manual/KeyEquivalents/index-debug.html new file mode 100644 index 000000000..cb9946076 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/index-debug.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + cappuccino-keyequivalents + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/KeyEquivalents/index.html b/Tests/Manual/KeyEquivalents/index.html new file mode 100644 index 000000000..2519046d2 --- /dev/null +++ b/Tests/Manual/KeyEquivalents/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + cappuccino-keyequivalents + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/KeyEquivalents/main.j b/Tests/Manual/KeyEquivalents/main.j new file mode 100644 index 000000000..59e978a1b --- /dev/null +++ b/Tests/Manual/KeyEquivalents/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * cappuccino-keyequivalents + * + * Created by Alexander Ljungberg on July 20, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} From 4d1baac4dbb92008d6000bf3eef63213962e2369 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 18 Jul 2010 23:52:57 -0400 Subject: [PATCH 091/356] Fixed: first clearing a \r keqyEquivalent from one button and then setting it on another would result in an exception. --- AppKit/CPButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 3bc21844b..c2f212644 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -574,7 +574,7 @@ CPButtonStateMixed = CPThemeState("mixed"); if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter) [[self window] setDefaultButton:self]; else if ([[self window] defaultButton] === self) - [[self window] setDefaultButton:NO]; + [[self window] setDefaultButton:nil]; _keyEquivalent = aString || @""; } From cffbf863517019862627ae1c8f2f3e3789170cca Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 22 Jul 2010 00:21:02 -0500 Subject: [PATCH 092/356] TableView theming --- AppKit/CPTableColumn.j | 15 +--- AppKit/CPTableHeaderView.j | 35 ++++++-- AppKit/CPTableView.j | 85 +++++++++--------- AppKit/CPTheme.j | 3 +- AppKit/CPView.j | 3 + .../tableview-headerview-ascending.png | Bin .../tableview-headerview-descending.png | Bin AppKit/Themes/Aristo/ThemeDescriptors.j | 73 ++++++++++++++- AppKit/_CPCornerView.j | 29 ++++-- 9 files changed, 174 insertions(+), 69 deletions(-) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview-ascending.png (100%) rename AppKit/{ => Themes/Aristo}/Resources/tableview-headerview-descending.png (100%) diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 91edc5d50..59b44e97e 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -78,18 +78,7 @@ CPTableColumnUserResizingMask = 1 << 1; var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; [self setHeaderView:header]; - var textDataView = [CPTextField new]; - - [textDataView setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] - forThemeAttribute:"text-color"]; - - [textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelectedDataView]; - [textDataView setLineBreakMode:CPLineBreakByTruncatingTail]; - [textDataView setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateSelectedDataView]; - [textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"]; - [textDataView setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset"]; - - [self setDataView:textDataView]; + [self setDataView:[CPTextField new]]; } return self; @@ -259,6 +248,8 @@ CPTableColumnUserResizingMask = 1 << 1; if (_dataView) _dataViewData[[_dataView UID]] = nil; + [aView setThemeState:CPThemeStateTableDataView]; + _dataView = aView; _dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView]; } diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 223cfec2b..be8d64798 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -33,13 +33,13 @@ + (CPString)themeClass { - return @"tableHeader"; + return @"columnHeader"; } + (id)themeAttributes { - return [CPDictionary dictionaryWithObjects:[[CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()] - forKeys:[@"background-color", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]]; + return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()] + forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]]; } - (void)initWithFrame:(CGRect)frame @@ -76,6 +76,7 @@ [_textField setFont:[self currentValueForThemeAttribute:@"text-font"]]; [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]]; [_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; + [_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]]; } - (void)setStringValue:(CPString)string @@ -158,12 +159,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal BOOL _isResizing; BOOL _isDragging; BOOL _isTrackingColumn; + BOOL _drawsColumnLines; float _columnOldWidth; CPTableView _tableView @accessors(property=tableView); } ++ (CPString)themeClass +{ + return @"tableHeaderRow"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null]] + forKeys:[@"background-color"]]; +} + - (void)_init { _mouseDownLocation = CPPointMakeZero(); @@ -177,7 +190,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal _columnOldWidth = 0.0; - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (id)initWithFrame:(CGRect)aFrame @@ -206,6 +219,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal return headerRect; } +- (void)setDrawsColumnLines:(BOOL)aFlag +{ + _drawsColumnLines = aFlag; +} + +- (BOOL)drawsColumnLines +{ + return _drawsColumnLines; +} + - (CGRect)_cursorRectForColumn:(int)column { if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask)) @@ -582,11 +605,13 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal if([headerView superview] != self) [self addSubview:headerView]; } + + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (void)drawRect:(CGRect)aRect { - if (!_tableView) + if (!_tableView || ![self drawsColumnLines]) return; var context = [[CPGraphicsContext currentContext] graphicsPort], diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index ad854587a..24c961792 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -165,6 +165,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _allowsEmptySelection; CPArray _sortDescriptors; + //Setting Display Attributes CGSize _intercellSpacing; float _rowHeight; @@ -174,9 +175,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; unsigned _selectionHighlightStyle; CPTableColumn _currentHighlightedTableColumn; - CPColor _selectionHighlightColor; unsigned _gridStyleMask; - CPColor _gridColor; unsigned _numberOfRows; @@ -215,12 +214,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing); BOOL _lastColumnShouldSnap; - CPGradient _sourceListActiveGradient; - CPColor _sourceListActiveTopLineColor; - CPColor _sourceListActiveBottomLineColor; - int _draggedColumnIndex; - CPArray _differedColumnDataToRemove; + CPArray _differedColumnDataToRemove; /* CPGradient _sourceListInactiveGradient; @@ -229,6 +224,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ } ++ (CPString)themeClass +{ + return @"tableview"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null], [CPNull null]] + forKeys:["alternating-row-colors", "grid-color", "highlighted-grid-color", "selection-color", "sourcelist-selection-color", "sort-image", "sort-image-reversed"]]; +} + - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; @@ -588,17 +594,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)setAlternatingRowBackgroundColors:(CPArray)alternatingRowBackgroundColors { - if ([_alternatingRowBackgroundColors isEqual:alternatingRowBackgroundColors]) - return; - - _alternatingRowBackgroundColors = alternatingRowBackgroundColors; + [self setValue:alternatingRowBackgroundColors forThemeAttribute:"alternating-row-colors"]; [self setNeedsDisplay:YES]; } - (CPArray)alternatingRowBackgroundColors { - return _alternatingRowBackgroundColors; + return [self currentValueForThemeAttribute:@"alternating-row-colors"]; } - (unsigned)selectionHighlightStyle @@ -627,10 +630,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setSelectionHighlightColor:(CPColor)aColor { - if (aColor === _selectionHighlightColor) - return; + [self setValue:aColor forThemeAttribute:"selection-color"]; - _selectionHighlightColor = aColor; [self setNeedsDisplay:YES]; } @@ -639,7 +640,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPColor)selectionHighlightColor { - return _selectionHighlightColor; + return [self currentValueForThemeAttribute:@"selection-color"]; } /*! @@ -652,12 +653,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setSelectionGradientColors:(CPDictionary)aDictionary { - if ([aDictionary valueForKey:"CPSourceListGradient"] === _sourceListActiveGradient && [aDictionary valueForKey:"CPSourceListTopLineColor"] === _sourceListActiveTopLineColor && [aDictionary valueForKey:"CPSourceListBottomLineColor"] === _sourceListActiveBottomLineColor) - return; + [self setValue:aDictionary forThemeAttribute:"sourcelist-selection-color"]; - _sourceListActiveGradient = [aDictionary valueForKey:CPSourceListGradient]; - _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor]; - _sourceListActiveBottomLineColor = [aDictionary valueForKey:CPSourceListBottomLineColor]; [self setNeedsDisplay:YES]; } @@ -669,7 +666,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPDictionary)selectionGradientColors { - return [CPDictionary dictionaryWithObjects:[_sourceListActiveGradient, _sourceListActiveTopLineColor, _sourceListActiveBottomLineColor] forKeys:[CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]; + return [self currentValueForThemeAttribute:@"sourcelist-selection-color"]; } /*! @@ -678,17 +675,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (void)setGridColor:(CPColor)aColor { - if (_gridColor === aColor) - return; - - _gridColor = aColor; + [self setValue:aColor forThemeAttribute:"grid-color"]; [self setNeedsDisplay:YES]; } - (CPColor)gridColor { - return _gridColor; + return [self currentValueForThemeAttribute:@"grid-color"];; } /*! @@ -1914,7 +1908,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [newSortDescriptors insertObject:newMainSortDescriptor atIndex:0]; // Update indicator image & highlighted column before - var image = [newMainSortDescriptor ascending] ? [CPTableView _defaultTableHeaderSortImage] : [CPTableView _defaultTableHeaderReverseSortImage]; + var image = [newMainSortDescriptor ascending] ? [self _tableHeaderSortImage] : [self _tableHeaderReverseSortImage]; [self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn]; [self setIndicatorImage:image inTableColumn:tableColumn]; @@ -1929,14 +1923,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [[aTableColumn headerView] _setIndicatorImage:anImage]; } -+ (CPImage)_defaultTableHeaderSortImage +- (CPImage)_tableHeaderSortImage { - return CPAppKitImage("tableview-headerview-ascending.png", CGSizeMake(9.0, 8.0)); + return [self currentValueForThemeAttribute:"sort-image"]; } -+ (CPImage)_defaultTableHeaderReverseSortImage +- (CPImage)_tableHeaderReverseSortImage { - return CPAppKitImage("tableview-headerview-descending.png", CGSizeMake(9.0, 8.0)); + return [self currentValueForThemeAttribute:"sort-image-reversed"]; } //Highlightable Column Headers @@ -2636,7 +2630,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } CGContextClosePath(context); - CGContextSetStrokeColor(context, _gridColor); + CGContextSetStrokeColor(context, [self gridColor]); CGContextStrokePath(context); } @@ -2679,6 +2673,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; deltaHeight = 0.5 * (_gridStyleMask & CPTableViewSolidHorizontalGridLineMask); CGContextBeginPath(context); + + var gradientCache = [self selectionGradientColors], + topLineColor = [gradientCache objectForKey:CPSourceListTopLineColor], + bottomLineColor = [gradientCache objectForKey:CPSourceListBottomLineColor], + gradientColor = [gradientCache objectForKey:CPSourceListGradient]; + while (count--) { var rowRect = CGRectIntersection(objj_msgSend(self, rectSelector, indexes[count]), aRect); @@ -2691,21 +2691,21 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; maxX = _CGRectGetMaxX(rowRect), maxY = _CGRectGetMaxY(rowRect) - deltaHeight; - CGContextDrawLinearGradient(context, _sourceListActiveGradient, rowRect.origin, CGPointMake(minX, maxY), 0); + CGContextDrawLinearGradient(context, gradientColor, rowRect.origin, CGPointMake(minX, maxY), 0); CGContextClosePath(context); CGContextBeginPath(context); CGContextMoveToPoint(context, minX, minY); CGContextAddLineToPoint(context, maxX, minY); CGContextClosePath(context); - CGContextSetStrokeColor(context, _sourceListActiveTopLineColor); + CGContextSetStrokeColor(context, topLineColor); CGContextStrokePath(context); CGContextBeginPath(context); CGContextMoveToPoint(context, minX, maxY); CGContextAddLineToPoint(context, maxX, maxY - 1); CGContextClosePath(context); - CGContextSetStrokeColor(context, _sourceListActiveBottomLineColor); + CGContextSetStrokeColor(context, bottomLineColor); CGContextStrokePath(context); } } @@ -2714,7 +2714,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!drawGradient) { - [_selectionHighlightColor setFill]; + [[self selectionHighlightColor] setFill]; CGContextFillPath(context); } @@ -2757,7 +2757,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } CGContextClosePath(context); - CGContextSetStrokeColor(context, [CPColor colorWithHexString:@"e5e5e5"]); + CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:"highlighted-grid-color"]); CGContextStrokePath(context); } @@ -3537,12 +3537,11 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(0.0, 0.0); - _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]; + [self setGridColor:[aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]; - _alternatingRowBackgroundColors = - [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]]; + [self setAlternatingRowBackgroundColors:[aCoder decodeObjectForKey:CPTableViewAlternatingRowColorsKey]]; _headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey]; _cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey]; @@ -3576,11 +3575,11 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [aCoder encodeObject:_tableColumns forKey:CPTableViewTableColumnsKey]; - [aCoder encodeObject:_gridColor forKey:CPTableViewGridColorKey]; + [aCoder encodeObject:[self gridColor] forKey:CPTableViewGridColorKey]; [aCoder encodeInt:_gridStyleMask forKey:CPTableViewGridStyleMaskKey]; [aCoder encodeBool:_usesAlternatingRowBackgroundColors forKey:CPTableViewUsesAlternatingBackgroundKey]; - [aCoder encodeObject:_alternatingRowBackgroundColors forKey:CPTableViewAlternatingRowColorsKey] + [aCoder encodeObject:[self alternatingRowBackgroundColors] forKey:CPTableViewAlternatingRowColorsKey] [aCoder encodeObject:_cornerView forKey:CPTableViewCornerViewKey]; [aCoder encodeObject:_headerView forKey:CPTableViewHeaderViewKey]; diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j index 4b37e6d7a..a1d27c8e5 100644 --- a/AppKit/CPTheme.j +++ b/AppKit/CPTheme.j @@ -242,7 +242,8 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0; CPThemeStateDisabled = CPThemeState("disabled"); CPThemeStateHighlighted = CPThemeState("highlighted"); CPThemeStateSelected = CPThemeState("selected"); -CPThemeStateSelectedDataView = CPThemeState("selectedDataView"); +CPThemeStateTableDataView = CPThemeState("tableDataView"); +CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView"); CPThemeStateBezeled = CPThemeState("bezeled"); CPThemeStateBordered = CPThemeState("bordered"); CPThemeStateEditable = CPThemeState("editable"); diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 51356c8d2..7b1c193d6 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1364,6 +1364,9 @@ var CPViewFlags = { }, if (_backgroundColor == aColor) return; + if (aColor == [CPNull null]) + aColor = nil; + _backgroundColor = aColor; #if PLATFORM(DOM) diff --git a/AppKit/Resources/tableview-headerview-ascending.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-ascending.png similarity index 100% rename from AppKit/Resources/tableview-headerview-ascending.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-ascending.png diff --git a/AppKit/Resources/tableview-headerview-descending.png b/AppKit/Themes/Aristo/Resources/tableview-headerview-descending.png similarity index 100% rename from AppKit/Resources/tableview-headerview-descending.png rename to AppKit/Themes/Aristo/Resources/tableview-headerview-descending.png diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 9d8b9954e..7950ac5ba 100755 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -356,6 +356,16 @@ [textfield setStringValue:""]; [textfield setEditable:YES]; + + // tableview dataview stuff + [textfield setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0] forThemeAttribute:"text-color" inState:CPThemeStateTableDataView]; + [textfield setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset" inState:CPThemeStateTableDataView|CPThemeStateTableDataView]; + [textfield setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateTableDataView|CPThemeStateSelectedTableDataView]; + [textfield setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateTableDataView|CPThemeStateSelectedTableDataView]; + + return textfield; } @@ -773,7 +783,7 @@ return buttonBar; } -+ (_CPTableColumnHeaderView)themedTableHeader ++ (_CPTableColumnHeaderView)themedColumnHeader { var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMake(0,0,50,24)], highlightedPressed = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview-highlighted-pressed.png" size:CGSizeMake(1.0, 23.0)]], @@ -790,6 +800,7 @@ [header setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"text-font"]; [header setValue:[CPColor whiteColor] forThemeAttribute:@"text-shadow-color"]; [header setValue:CGSizeMake(0,1) forThemeAttribute:@"text-shadow-offset"]; + [header setValue:CPLeftTextAlignment forThemeAttribute:@"text-alignment"]; [header setValue:pressed forThemeAttribute:@"background-color" inState:CPThemeStateHighlighted]; [header setValue:highlighted forThemeAttribute:@"background-color" inState:CPThemeStateSelected]; @@ -798,6 +809,66 @@ return header; } ++ (CPTableHeaderView)themedTableHeaderRow +{ + var header = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0,0,50,24)], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + [header setValue:normal forThemeAttribute:@"background-color"]; + + return header; +} + ++ (_CPCornerView)themedCornerview +{ + var corner = [[_CPCornerView alloc] initWithFrame:CGRectMake(0,0,25, 23)], + normal = [CPColor colorWithPatternImage:[_CPCibCustomResource imageResourceWithName:"tableview-headerview.png" size:CGSizeMake(1.0, 23.0)]]; + + [corner setValue:normal forThemeAttribute:"background-color"]; + + return corner; +} + ++ (CPTableView)themedTableView +{ + // This is a bit more complicated than the rest because we actually set theme values for several different (table related) controls in this method + + var tableview = [[CPTableView alloc] initWithFrame:CGRectMake(0,0,200,200)]; + + // Now theme the tableview + var sortImage = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-ascending.png" size:CGSizeMake(9.0, 8.0)], + sortImageReversed = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-descending.png" size:CGSizeMake(9.0, 8.0)], + alternatingRowColors = [[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]], + gridColor = [CPColor colorWithHexString:@"dce0e2"], + selectionColor = [CPColor colorWithHexString:@"5f83b9"], + sourceListSelectionColor = [CPDictionary dictionaryWithObjects: [ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), + [CPColor colorWithCalibratedRed:(61.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0], + [CPColor colorWithCalibratedRed:(31.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0] + ] + forKeys: [CPSourceListGradient, CPSourceListTopLineColor, CPSourceListBottomLineColor]]; + + [tableview setValue:alternatingRowColors forThemeAttribute:"alternating-row-colors"]; + [tableview setValue:gridColor forThemeAttribute:"grid-color"]; + [tableview setValue:[CPColor whiteColor] forThemeAttribute:"highlighted-grid-color"]; + [tableview setValue:selectionColor forThemeAttribute:"selection-color"]; + [tableview setValue:sourceListSelectionColor forThemeAttribute:"sourcelist-selection-color"]; + [tableview setValue:sortImage forThemeAttribute:"sort-image"]; + [tableview setValue:sortImageReversed forThemeAttribute:"sort-image-reversed"]; + + return tableview; +} + ++ (CPTextField)themedTableDataView +{ + var view = [self themedStandardTextField]; + + [view setBezeled:NO]; + [view setEditable:NO]; + [view setThemeState:CPThemeStateTableDataView]; + + return view; +} + @end @implementation AristoHUDThemeDescriptor : BKThemeDescriptor diff --git a/AppKit/_CPCornerView.j b/AppKit/_CPCornerView.j index a5e4f9a65..33925e5c2 100644 --- a/AppKit/_CPCornerView.j +++ b/AppKit/_CPCornerView.j @@ -1,21 +1,36 @@ - @import "CPView.j" @implementation _CPCornerView : CPView { } ++ (CPString)themeClass +{ + return @"cornerview"; +} + ++ (id)themeAttributes +{ + return [CPDictionary dictionaryWithObjects:[[CPNull null]] + forKeys:[@"background-color"]]; +} + +- (void)layoutSubviews +{ + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; +} + - (void)_init { - [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]]; + [self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; } - (id)initWithFrame:(CGRect)aFrame { - if (self = [super initWithFrame:aFrame]) - { + self = [super initWithFrame:aFrame] + + if (self) [self _init]; - } return self; } @@ -23,9 +38,9 @@ - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - { + + if (self) [self _init]; - } return self; } From 138888e6201d4efee04e55b159dac6122c341895 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 14:04:05 +0200 Subject: [PATCH 093/356] implement CPArrayController insertObject:atArrangedObjectIndex: --- AppKit/CPArrayController.j | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..fed04b4b1 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -417,6 +417,33 @@ [self rearrangeObjects]; } +- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex +{ + if (![self canAdd]) + return; + + [self willChangeValueForKey:@"content"]; + [_contentObject insertObject:anObject atIndex:anIndex]; + [self didChangeValueForKey:@"content"]; + + if (_clearsFilterPredicateOnInsertion) + [self setFilterPredicate:nil]; + + [[self arrangedObjects] insertObject:anObject atIndex:anIndex]; + + if ([self selectsInsertedObjects]) + [self setSelectionIndex:anIndex]; + else + { + [self willChangeValueForKey:@"selectionIndexes"] + [[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1]; + [self didChangeValueForKey:@"selectionIndexes"]; + } + + if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0) + [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]]; +} + - (void)removeObject:(id)object { if (![self canRemove]) From bb3c08ce0ba6b6a52164c131b6d22b02e39f74e1 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 14:04:26 +0200 Subject: [PATCH 094/356] add CPArrayController test --- Tests/AppKit/CPArrayControllerTest.j | 86 ++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Tests/AppKit/CPArrayControllerTest.j diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j new file mode 100644 index 000000000..4ea774920 --- /dev/null +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -0,0 +1,86 @@ +@implementation CPArrayControllerTest : OJTestCase +{ + CPArrayController _arrayController @accessors(property=arrayController); + CPArray _contentArray @accessors(property=contentArray); +} + +- (void)setUp +{ + _contentArray = []; + + [_contentArray addObject:[Person personWithName:@"Francisco" age:21]]; + [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; + [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; + + _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; +} + +- (void)testInitWithContent +{ + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testSetContent +{ + otherContent = [@"5", @"6"]; + [[self arrayController] setContent:otherContent]; + + [self assert:otherContent equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testInsertObjectAtArrangedObjectIndex +{ + var object = [Person personWithName:@"Klaas Pieter" age:24], + arrayController = [self arrayController]; + + [arrayController setSortDescriptors:[[CPSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]]]; + [arrayController insertObject:object atArrangedObjectIndex:1]; + + [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; +} + +- (void)testContentBinding +{ + [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; + + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; + + [[self mutableArrayValueForKey:@"contentArray"] addObject:@"4"]; + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + + [[self arrayController] insertObject:@"2" atArrangedObjectIndex:1]; + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; +} + +@end + +@implementation Person : CPObject +{ + CPString _name @accessors(property=name); + int _age @accessors(property=age); +} + ++ (id)personWithName:(CPString)aName age:(int)anAge +{ + return [[self alloc] initWithName:aName age:anAge]; +} + +- (id)initWithName:(CPString)aName age:(int)anAge +{ + if (self = [super init]) + { + _name = aName; + _age = anAge; + } + + return self; +} + +- (CPString)description +{ + return [CPString stringWithFormat:@"%@ : %@", [self name], [self age]]; +} + +@end \ No newline at end of file From 4f946f267ef7a4c94a05dd88acdc41a8ade2ba19 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 18:34:13 +0200 Subject: [PATCH 095/356] fix CPArrayController removeObject: removeObject: only shifted the selection, it never actually removes the object --- AppKit/CPArrayController.j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..ad40efcd2 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -426,12 +426,14 @@ [_contentObject removeObject:object]; [self didChangeValueForKey:@"content"]; - if ([_filterPredicate evaluateWithObject:object]) + if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { [self willChangeValueForKey:@"selectionIndexes"]; var pos = [_arrangedObjects indexOfObject:object]; + [_arrangedObjects removeObjectAtIndex:pos]; [_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1]; + [self didChangeValueForKey:@"selectionIndexes"]; } } From acf5e5b75f37393318e2554ab8a93219efe281b4 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 18:44:50 +0200 Subject: [PATCH 096/356] call super in _CPObservableArray removeObjectAtIndex: The current implementation calls self, which causes an infinite loop --- AppKit/CPObjectController.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPObjectController.j b/AppKit/CPObjectController.j index 65815caf2..f070d33bf 100644 --- a/AppKit/CPObjectController.j +++ b/AppKit/CPObjectController.j @@ -452,7 +452,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb [self didChangeValueForKey:keyPath]; } - [self removeObjectAtIndex:anIndex]; + [super removeObjectAtIndex:anIndex]; } - (void)addObject:(id)anObject From ff8e5ae42e2f2f141ff2a3ba80a397bafd08d785 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 7 Jul 2010 15:35:12 +0200 Subject: [PATCH 097/356] save _replacedKeys on the class in stead of the object instance reviewed: Ross --- Foundation/CPKeyValueObserving.j | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 0ff9fdd26..6ea9c9a42 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -213,7 +213,6 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, _targetObject = aTarget; _nativeClass = [aTarget class]; - _replacedKeys = [CPSet set]; _observersForKey = {}; _changesForKey = {}; _observersForKeyLength = 0; @@ -230,6 +229,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (existingKVOClass) { _targetObject.isa = existingKVOClass; + _replacedKeys = existingKVOClass._replacedKeys; return; } @@ -237,6 +237,9 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, objj_registerClassPair(kvoClass); + _replacedKeys = [CPSet set]; + kvoClass._replacedKeys = _replacedKeys; + //copy in the methods from our model subclass var methodList = _CPKVOModelSubclass.method_list, count = methodList.length, @@ -293,6 +296,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, var theMethod = class_getInstanceMethod(_nativeClass, theSelector); class_addMethod(_targetObject.isa, theSelector, theReplacementMethod(aKey, theMethod), ""); + [_replacedKeys addObject:aKey]; } } From 0306c35b54e6233911f45f31fd4254af28ab8fbe Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 7 Jul 2010 18:24:24 +0200 Subject: [PATCH 098/356] don't copy the selection indexes in setContent: --- AppKit/CPArrayController.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index c11206f79..4953c3016 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -154,7 +154,7 @@ value = [value]; var oldSelection = nil, - oldSelectionIndexes = [[self selectionIndexes] copy]; + oldSelectionIndexes = [self selectionIndexes]; if ([self preservesSelection]) oldSelection = [self selectedObjects]; From 8ce63a244cabef7cb2038b3a5afe2ca7e5ba8b50 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 7 Jul 2010 18:24:44 +0200 Subject: [PATCH 099/356] store accessors in a javascript object not a CPDictionary, for slight performance improvement --- Foundation/CPKeyValueCoding.j | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 104a6931f..c2691bd47 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -33,6 +33,9 @@ CPUndefinedKeyException = @"CPUndefinedKeyException"; CPTargetObjectUserInfoKey = @"CPTargetObjectUserInfoKey"; CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; +var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", + CPObjectModifiersForClassKey = @"$CPObjectModifiersForClassKey"; + @implementation CPObject (CPKeyValueCoding) + (BOOL)accessInstanceVariablesDirectly @@ -43,26 +46,18 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; /* @ignore */ + (SEL)_accessorForKey:(CPString)aKey { - if (!CPObjectAccessorsForClass) - CPObjectAccessorsForClass = [CPDictionary dictionary]; - - var UID = [isa UID], - selector = nil, - accessors = [CPObjectAccessorsForClass objectForKey:UID]; + var selector = nil, + accessors = isa[CPObjectAccessorsForClassKey]; if (accessors) { - selector = [accessors objectForKey:aKey]; + selector = accessors[aKey]; if (selector) return selector === [CPNull null] ? nil : selector; } else - { - accessors = [CPDictionary dictionary]; - - [CPObjectAccessorsForClass setObject:accessors forKey:UID]; - } + accessors = isa[CPObjectAccessorsForClassKey] = {}; var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); @@ -73,12 +68,12 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; [self instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || [self instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) { - [accessors setObject:selector forKey:aKey]; + accessors[aKey] = selector; return selector; } - [accessors setObject:[CPNull null] forKey:aKey]; + accessors[aKey] = [CPNull null]; return nil; } From d947c849c87598921b860d399fd5e11cc31349bd Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 8 Jul 2010 16:26:17 +0200 Subject: [PATCH 100/356] made _accessorForKey slightly faster by inlining it as a function --- Foundation/CPKeyValueCoding.j | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index c2691bd47..1449899e4 100644 --- a/Foundation/CPKeyValueCoding.j +++ b/Foundation/CPKeyValueCoding.j @@ -151,7 +151,7 @@ var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", - (id)valueForKey:(CPString)aKey { var theClass = [self class], - selector = [theClass _accessorForKey:aKey]; + selector = _accessorForKey(theClass, aKey); if (selector) return objj_msgSend(self, selector); @@ -259,6 +259,41 @@ var CPObjectAccessorsForClassKey = @"$CPObjectAccessorsForClassKey", @end +var Null = [CPNull null]; +var _accessorForKey = function(theClass, aKey) +{ + var selector = nil, + accessors = theClass.isa[CPObjectAccessorsForClassKey]; + + if (accessors) + { + selector = accessors[aKey]; + + if (selector) + return selector === Null ? nil : selector; + } + else + accessors = theClass.isa[CPObjectAccessorsForClassKey] = {}; + + var capitalizedKey = aKey.charAt(0).toUpperCase() + aKey.substr(1); + + if ([theClass instancesRespondToSelector:selector = CPSelectorFromString("get" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString(aKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("is" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_get" + capitalizedKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_" + aKey)] || + [theClass instancesRespondToSelector:selector = CPSelectorFromString("_is" + capitalizedKey)]) + { + accessors[aKey] = selector; + + return selector; + } + + accessors[aKey] = Null; + + return nil; +} + @implementation CPDictionary (KeyValueCoding) - (id)valueForKey:(CPString)aKey From 78fd9723120e6bc3dc96a7e1fd8cad1083d8c3d1 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 2 Jun 2010 15:50:21 +0200 Subject: [PATCH 101/356] only reverse set the binding on end editing --- AppKit/CPControl.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 7de6719c4..db8a22cd9 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -545,6 +545,7 @@ var CPControlBlackColor = [CPColor blackColor]; return; [self _reverseSetBinding]; + [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; } From 560ea75a253e44d8242f7314ebe795e8ceec34d0 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Fri, 4 Jun 2010 15:41:12 +0200 Subject: [PATCH 102/356] added CPArrayController to AppKit.j --- AppKit/AppKit.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 9c820be65..95bbe6201 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -88,3 +88,4 @@ @import "CPWebView.j" @import "CPWindow.j" @import "CPWindowController.j" +@import "CPArrayController.j" From 90e9b86497ef767015f08f0043fca9965cace6de Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 26 Jul 2010 14:23:52 +0200 Subject: [PATCH 103/356] match CPTableView's alternating row colors with Aristo's --- AppKit/Themes/Aristo/ThemeDescriptors.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 7950ac5ba..ec1245de8 100755 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -838,7 +838,7 @@ // Now theme the tableview var sortImage = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-ascending.png" size:CGSizeMake(9.0, 8.0)], sortImageReversed = [_CPCibCustomResource imageResourceWithName:"tableview-headerview-descending.png" size:CGSizeMake(9.0, 8.0)], - alternatingRowColors = [[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]], + alternatingRowColors = [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]], gridColor = [CPColor colorWithHexString:@"dce0e2"], selectionColor = [CPColor colorWithHexString:@"5f83b9"], sourceListSelectionColor = [CPDictionary dictionaryWithObjects: [ CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2), From b9c2becd3e6e9eb1ed82e37d440fc6a528e19af0 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 27 Jul 2010 09:09:59 +0200 Subject: [PATCH 104/356] implement CPIndexSet isEqual: --- Foundation/CPIndexSet.j | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 266c7273e..af528b169 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -130,6 +130,17 @@ return self; } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + if (!anObject || ![anObject isKindOfClass:[CPIndexSet class]]) + return NO; + + return [self isEqualToIndexSet:anObject]; +} + // Querying an Index Set /*! Compares the receiver with the provided index set. From 48a5d55af714a89f88269a4ced9828c1e03fcd4f Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Tue, 27 Jul 2010 09:10:41 +0200 Subject: [PATCH 105/356] fix CPArrayController selectPrevious: and selectNext: Also added unit-tests for canSelectPrevious, canSelectNext, selectPrevious: and selectNext: --- AppKit/CPArrayController.j | 24 +++++------ Tests/AppKit/CPArrayControllerTest.j | 59 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index a799b296d..189485a8c 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -358,29 +358,29 @@ //Moving selection --(BOOL)canSelectPrevious +- (BOOL)canSelectPrevious { return [[self selectionIndexes] firstIndex] > 0 } --(BOOL)canSelectNext +-(void)selectPrevious:(id)sender { - return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1; -} + var index = [[self selectionIndexes] firstIndex] - 1; --(void)selectNext:(id)sender -{ - var index = [[self selectionIndexes] firstIndex] + 1 || 0; - - if (index < [[self arrangedObjects] count]) + if (index >= 0) [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; } --(void)selectPrevious:(id)sender +- (BOOL)canSelectNext { - var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1; + return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1; +} - if (index >= 0) +- (void)selectNext:(id)sender +{ + var index = [[self selectionIndexes] firstIndex] + 1; + + if (index < [[self arrangedObjects] count]) [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]]; } diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 4ea774920..532771848 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -41,6 +41,65 @@ [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; } +- (void)testSelectPrevious +{ + var arrayController = [self arrayController]; + + // Selection index: 1 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]]; + [self assertTrue:[arrayController canSelectPrevious] message:@"index > 0; canSelectPrevious should return YES"] + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; + + // Selection index: 0 + [self assertFalse:[arrayController canSelectPrevious] message:@"index <= 0; canSelectPrevious should return NO"]; + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +} + +- (void)testSelectNext +{ + var arrayController = [self arrayController], + count = [[arrayController arrangedObjects] count]; + + // Selection index: count - 2 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:count - 2]]; + [self assertTrue:[arrayController canSelectNext] message:@"index < (count - 1); canSelectNext should return YES"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; + + // Selection index: count - 1 + [self assertFalse:[arrayController canSelectNext] message:@"index >= (count - 1) canSelectNext should return NO"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; +} +// - (void)testSelectNext +// { +// var arrayController = [self arrayController], +// arrangedObjects = [arrayController arrangedObjects], +// startIndex = 0, +// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; +// +// [arrayController setSelectionIndexes:selectionIndexes]; +// [arrayController selectNext:self]; +// +// [selectionIndexes shiftIndexesStartingAtIndex:startIndex by:1] +// [self assert:selectionIndexes equals:[arrayController selectionIndexes]]; +// +// // Test that the selection wraps around +// startIndex = [arrangedObjects count] - 1; +// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; +// +// [arrayController setSelectionIndexes:selectionIndexes]; +// [arrayController selectNext:self]; +// +// [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +// } + - (void)testContentBinding { [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; From 75ceeffab8068b4d136a6af8ccc575bb24a8abd5 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 28 Jul 2010 13:28:53 +0200 Subject: [PATCH 106/356] remove commented code from CPArrayControllerTest --- Tests/AppKit/CPArrayControllerTest.j | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 532771848..c7bf08a96 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -77,28 +77,6 @@ [arrayController selectNext:self]; [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; } -// - (void)testSelectNext -// { -// var arrayController = [self arrayController], -// arrangedObjects = [arrayController arrangedObjects], -// startIndex = 0, -// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; -// -// [arrayController setSelectionIndexes:selectionIndexes]; -// [arrayController selectNext:self]; -// -// [selectionIndexes shiftIndexesStartingAtIndex:startIndex by:1] -// [self assert:selectionIndexes equals:[arrayController selectionIndexes]]; -// -// // Test that the selection wraps around -// startIndex = [arrangedObjects count] - 1; -// selectionIndexes = [CPIndexSet indexSetWithIndex:startIndex]; -// -// [arrayController setSelectionIndexes:selectionIndexes]; -// [arrayController selectNext:self]; -// -// [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; -// } - (void)testContentBinding { From ff98a9be5a011a8c754455c383e0503dd6b869d4 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 28 Jul 2010 15:02:48 +0200 Subject: [PATCH 107/356] fix preserve selection in removeObjects and added unit test --- AppKit/CPArrayController.j | 31 +++++- Tests/AppKit/CPArrayControllerTest.j | 153 +++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 Tests/AppKit/CPArrayControllerTest.j diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 4953c3016..3830758db 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -489,13 +489,34 @@ - (void)_removeObjects:(CPArray)objects { - var contentArray = [self contentArray], - count = [objects count]; + [self willChangeValueForKey:@"content"]; + [_contentObject removeObjectsInArray:objects]; + [self didChangeValueForKey:@"content"]; - for (var i=0; i= objectsCount) + selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1]; + } + + [self willChangeValueForKey:@"selectionIndexes"]; + _selectionIndexes = selectionIndexes; + [self didChangeValueForKey:@"selectionIndexes"]; } - (BOOL)canInsert diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j new file mode 100644 index 000000000..dd2415e56 --- /dev/null +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -0,0 +1,153 @@ +@implementation CPArrayControllerTest : OJTestCase +{ + CPArrayController _arrayController @accessors(property=arrayController); + CPArray _contentArray @accessors(property=contentArray); +} + +- (void)setUp +{ + _contentArray = []; + + [_contentArray addObject:[Person personWithName:@"Francisco" age:21]]; + [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; + [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; + + _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; +} + +- (void)testInitWithContent +{ + [self assert:[self contentArray] equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testSetContent +{ + otherContent = [@"5", @"6"]; + [[self arrayController] setContent:otherContent]; + + [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; + [self assert:otherContent equals:[[self arrayController] contentArray]]; + [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; +} + +- (void)testInsertObjectAtArrangedObjectIndex +{ + var object = [Person personWithName:@"Klaas Pieter" age:24], + arrayController = [self arrayController]; + + [arrayController setSortDescriptors:[[CPSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]]]; + [arrayController insertObject:object atArrangedObjectIndex:1]; + + [self assert:object equals:[[arrayController arrangedObjects] objectAtIndex:1]]; +} + +- (void)testSelectPrevious +{ + var arrayController = [self arrayController]; + + // Selection index: 1 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:1]]; + [self assertTrue:[arrayController canSelectPrevious] message:@"index > 0; canSelectPrevious should return YES"] + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; + + // Selection index: 0 + [self assertFalse:[arrayController canSelectPrevious] message:@"index <= 0; canSelectPrevious should return NO"]; + + [arrayController selectPrevious:self]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes]]; +} + +- (void)testSelectNext +{ + var arrayController = [self arrayController], + count = [[arrayController arrangedObjects] count]; + + // Selection index: count - 2 + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndex:count - 2]]; + [self assertTrue:[arrayController canSelectNext] message:@"index < (count - 1); canSelectNext should return YES"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; + + // Selection index: count - 1 + [self assertFalse:[arrayController canSelectNext] message:@"index >= (count - 1) canSelectNext should return NO"]; + + [arrayController selectNext:self]; + [self assert:[CPIndexSet indexSetWithIndex:count - 1] equals:[arrayController selectionIndexes]]; +} + +- (void)testRemoveObjects +{ + var arrayController = [self arrayController]; + [arrayController setPreservesSelection:NO]; + + [arrayController setSelectionIndexes:[CPIndexSet indexSetWithIndexesInRange:CPMakeRange(1, 2)]]; + [arrayController removeObjects:[arrayController selectedObjects]] + + [self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes] + message:@"selection should be empty if arraycontroller doesn't preserve selection"]; + + arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; + [arrayController setPreservesSelection:YES]; + print([self contentArray]); + + // Remove from middle + var selectionIndexes = [CPIndexSet indexSetWithIndex:1]; + [arrayController setSelectionIndexes:selectionIndexes]; + [arrayController removeObjects:[arrayController selectedObjects]]; + [self assert:selectionIndexes equals:[arrayController selectionIndexes] message:@"selection should stay the same"]; + + // Remove from end + [arrayController removeObjects:[[[arrayController content] objectAtIndex:1]]]; + [self assert:[CPIndexSet indexSetWithIndex:0] equals:[arrayController selectionIndexes] + message:@"last object removed; selection should shift to first available index"]; + + // Remove from all + [arrayController removeObjects:[[[arrayController content] objectAtIndex:0]]]; + [self assert:[CPIndexSet indexSet] equals:[arrayController selectionIndexes] message:@"no objects left, selection should disappear"]; +} + +- (void)testContentBinding +{ + [[self arrayController] bind:@"contentArray" toObject:self withKeyPath:@"contentArray" options:0]; + + [self assert:[[self arrayController] contentArray] equals:[self contentArray]]; + + [[self mutableArrayValueForKey:@"contentArray"] addObject:@"4"]; + [self assert:[self contentArray] equals:[[self arrayController] contentArray] + message:@"object 4 was added; contentArray should reflect this"]; +} + +@end + +@implementation Person : CPObject +{ + CPString _name @accessors(property=name); + int _age @accessors(property=age); +} + ++ (id)personWithName:(CPString)aName age:(int)anAge +{ + return [[self alloc] initWithName:aName age:anAge]; +} + +- (id)initWithName:(CPString)aName age:(int)anAge +{ + if (self = [super init]) + { + _name = aName; + _age = anAge; + } + + return self; +} + +- (CPString)description +{ + return [CPString stringWithFormat:@"%@ : %@", [self name], [self age]]; +} + +@end \ No newline at end of file From c3c996f1f765f7c58e42dbb686fe34fe8f484494 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 27 Jul 2010 16:48:54 -0400 Subject: [PATCH 108/356] Don't substitute the font if the textfield is not editable (a label) --- Tools/nib2cib/NSTextField.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSTextField.j b/Tools/nib2cib/NSTextField.j index 8b1b1eeda..8ded6c08e 100644 --- a/Tools/nib2cib/NSTextField.j +++ b/Tools/nib2cib/NSTextField.j @@ -36,7 +36,7 @@ { var cell = [aCoder decodeObjectForKey:@"NSCell"]; - if ([[cell font] isEqual:[CPFont boldSystemFontOfSize:12.0]]) + if ([cell isEditable] && [[cell font] isEqual:[CPFont boldSystemFontOfSize:12.0]]) [self setFont:[CPFont systemFontOfSize:12.0]]; [self sendActionOn:CPKeyUpMask|CPKeyDownMask]; From 6ff3fa0e523325c0097b12be5de37611aaeadcec Mon Sep 17 00:00:00 2001 From: Mike Fellows Date: Tue, 27 Jul 2010 17:44:05 -0700 Subject: [PATCH 109/356] Fix for issue #769, allow ctrl/cmd keys and F1-F12 keys to propagate to the browser unless they are blacklisted --- AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 43 ++++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 7af9e9888..ea8badbbe 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -136,6 +136,7 @@ var CPDOMEventGetClickCount, //might be mac only, we should investigate futher later. var KeyCodesToPrevent = {}, CharacterKeysToPrevent = {}, + KeyCodesToAllow = {}, MozKeyCodeToKeyCodeMap = { 61: 187, // =, equals 59: 186 // ;, semicolon @@ -144,6 +145,19 @@ var KeyCodesToPrevent = {}, KeyCodesToPrevent[CPKeyCodes.A] = YES; +KeyCodesToAllow[CPKeyCodes.F1] = YES; +KeyCodesToAllow[CPKeyCodes.F2] = YES; +KeyCodesToAllow[CPKeyCodes.F3] = YES; +KeyCodesToAllow[CPKeyCodes.F4] = YES; +KeyCodesToAllow[CPKeyCodes.F5] = YES; +KeyCodesToAllow[CPKeyCodes.F6] = YES; +KeyCodesToAllow[CPKeyCodes.F7] = YES; +KeyCodesToAllow[CPKeyCodes.F8] = YES; +KeyCodesToAllow[CPKeyCodes.F9] = YES; +KeyCodesToAllow[CPKeyCodes.F10] = YES; +KeyCodesToAllow[CPKeyCodes.F11] = YES; +KeyCodesToAllow[CPKeyCodes.F12] = YES; + KeyCodesToUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; KeyCodesToUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; KeyCodesToUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; @@ -634,10 +648,31 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist - StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || - CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || - KeyCodesToPrevent[aDOMEvent.keyCode]); + // With a few exceptions, all key events are blocked from propagating to + // the browser. Here the following exceptions are being allowed: + // + // - All keys pressed along with a ctrl or cmd key _unless_ they are in + // one of the two blacklists. + // - Any key listed in the whitelist. + // + // The ctrl/cmd keys are used for browser hotkeys as are the keys listed in + // the whitelist (F1-F12 at the time of writing). + // + // If a key is listed in both the blacklist and whitelist, the blacklist is + // checked first. The key will be blocked from propagating in that case. + + StopDOMEventPropagation = YES; + + // Make sure it is not in the blacklists. + if(! (CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || KeyCodesToPrevent[aDOMEvent.keyCode])) + { + // It is not in the blacklist, let it through if the ctrl/cmd key is + // also down or it's in the whitelist. + if((modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || KeyCodesToAllow[aDOMEvent.keyCode]) + { + StopDOMEventPropagation = NO; + } + } var isNativePasteEvent = NO, isNativeCopyOrCutEvent = NO, From 05e435633ff7ef1dd77fb028b8887a311706cb2d Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 27 Jul 2010 16:50:24 -0400 Subject: [PATCH 110/356] Fixed: if a custom CPTableView header view was used for a column, such as a CPImageView, sorting by that column would cause an exception as CPTableView tried to send _setIndicatorImage: to the view. The fix is to only send the message if the view supports it. --- AppKit/CPTableView.j | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 24c961792..cda709b43 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1920,7 +1920,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)setIndicatorImage:(CPImage)anImage inTableColumn:(CPTableColumn)aTableColumn { if (aTableColumn) - [[aTableColumn headerView] _setIndicatorImage:anImage]; + { + var headerView = [aTableColumn headerView]; + if ([headerView respondsToSelector:@selector(_setIndicatorImage:)]) + [headerView _setIndicatorImage:anImage]; + } } - (CPImage)_tableHeaderSortImage From cce13b4b45768fb1954f31a34785494f458b2485 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 27 Jul 2010 16:49:30 -0400 Subject: [PATCH 111/356] NSMenuItem is not reading the tag for some reason --- Tools/nib2cib/NSMenuItem.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSMenuItem.j b/Tools/nib2cib/NSMenuItem.j index 292cbb815..0076382d7 100644 --- a/Tools/nib2cib/NSMenuItem.j +++ b/Tools/nib2cib/NSMenuItem.j @@ -46,7 +46,7 @@ _isEnabled = ![aCoder decodeBoolForKey:"NSIsDisabled"]; _isHidden = [aCoder decodeBoolForKey:"NSIsHidden"]; -// _tag = [aCoder decodeIntForKey:"NSTag"]; + _tag = [aCoder decodeIntForKey:"NSTag"]; _state = [aCoder decodeIntForKey:"NSState"]; // _image = [aCoder decodeObjectForKey:"NSImage"]; From 8cfba4c2424d3a185ff394b84c606bcb0bad1d36 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Thu, 8 Jul 2010 16:42:57 +0200 Subject: [PATCH 112/356] only offset a nib2cib'ed textfield if it has a bezel --- Tools/nib2cib/NSTextField.j | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Tools/nib2cib/NSTextField.j b/Tools/nib2cib/NSTextField.j index 8ded6c08e..d9d935085 100644 --- a/Tools/nib2cib/NSTextField.j +++ b/Tools/nib2cib/NSTextField.j @@ -58,8 +58,16 @@ var frame = [self frame]; - [self setFrameOrigin:CGPointMake(frame.origin.x - 4.0, frame.origin.y - 4.0)]; - [self setFrameSize:CGSizeMake(frame.size.width + 8.0, frame.size.height + 8.0)]; + [self setFrameOrigin:CGPointMake(frame.origin.x, frame.origin.y)]; + [self setFrameSize:CGSizeMake(frame.size.width, frame.size.height)]; + + // Only adjust the origin and size if this is a bezeled textfield + // this makes sure that labels positioned in IB are properly positioned after nibcib + if ([self isBezeled]) + { + [self setFrameOrigin:CGPointMake(frame.origin.x - 4.0, frame.origin.y - 4.0)]; + [self setFrameSize:CGSizeMake(frame.size.width + 8.0, frame.size.height + 8.0)]; + } CPLog.debug([self stringValue] + " => isBordered=" + [self isBordered] + ", isBezeled=" + [self isBezeled] + ", bezelStyle=" + [self bezelStyle] + "("+[cell stringValue]+", " + [cell placeholderString] + ")"); } From e586273a3f65778fd8fd5c59cdcb228b435e7a06 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 28 Jul 2010 14:13:12 -0700 Subject: [PATCH 113/356] Fix accidental global. --- AppKit/CPTableColumn.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 04e2b4fdf..17b731d18 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -460,8 +460,8 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey", - CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey"; - CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey"; + CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey", + CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey"; @implementation CPTableColumn (CPCoding) From 675e9829bd50332a7adcc60e6bb3436de05e0e4f Mon Sep 17 00:00:00 2001 From: cacaodev Date: Sun, 18 Jul 2010 00:28:20 +0200 Subject: [PATCH 114/356] CPSearchField: Fixes (per cocoa) - Do not override search button action, catch mouse events in mouseDown: instead. - Do not resign first responder on searchfield when showing the context menu - Give more space between search button and insertion point - Do not add search string to recents searches when typing and sendsWholeString == NO, only on enter. - Select all text when showing the menu or after selecting a recent search in the menu - Support custom search/cancel buttons and custom layout - Allow images in template menu items - Updated Test App with custom buttons --- AppKit/CPSearchField.j | 179 ++++++++++++--------- Tests/Manual/CPSearchField/AppController.j | 21 ++- 2 files changed, 122 insertions(+), 78 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index f5fdea74a..d77bb4c9c 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -34,6 +34,10 @@ var CPSearchFieldSearchImage = nil, CPSearchFieldCancelImage = nil, CPSearchFieldCancelPressedImage = nil; +var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, + CANCEL_BUTTON_DEFAULT_WIDTH = 22.0, + BUTTON_DEFAULT_HEIGHT = 22.0; + /*! @ingroup appkit @class CPSearchField @@ -54,6 +58,7 @@ var CPSearchFieldSearchImage = nil, int _maximumRecents; BOOL _sendsWholeSearchString; BOOL _sendsSearchStringImmediately; + BOOL _canResignFirstResponder; CPTimer _partialStringTimer; } @@ -63,10 +68,10 @@ var CPSearchFieldSearchImage = nil, return; var bundle = [CPBundle bundleForClass:self]; - CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)]; - CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)]; - CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)]; - CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)]; + CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; } - (id)initWithFrame:(CGRect)frame @@ -91,21 +96,22 @@ var CPSearchFieldSearchImage = nil, - (void)_initWithFrame:(CGRect)frame { + var bounds = [self bounds]; + [self setBezeled:YES]; [self setBezelStyle:CPTextFieldRoundedBezel]; [self setBordered:YES]; [self setEditable:YES]; [self setDelegate:self]; + [self setContinuous:YES]; - _cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)]; + var cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]]; + [self setCancelButton:cancelButton]; [self resetCancelButton]; - [_cancelButton setHidden:YES]; - [_cancelButton setAutoresizingMask:CPViewMinXMargin]; - [self addSubview:_cancelButton]; - _searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)]; + var searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]]; + [self setSearchButton:searchButton]; [self resetSearchButton]; - [self addSubview:_searchButton]; } // Managing Buttons @@ -115,7 +121,15 @@ var CPSearchFieldSearchImage = nil, */ - (void)setSearchButton:(CPButton)button { - _searchButton = button; + if (button != _searchButton) + { + [_searchButton removeFromSuperview]; + _searchButton = button; + + [_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]]; + [_searchButton setAutoresizingMask:CPViewMaxXMargin]; + [self addSubview:_searchButton]; + } } /*! @@ -133,30 +147,13 @@ var CPSearchFieldSearchImage = nil, */ - (void)resetSearchButton { - var searchButtonImage, - action, - target, - button = [self searchButton]; - - if (_searchMenuTemplate === nil) - { - searchButtonImage = CPSearchFieldSearchImage; - action = @selector(_sendAction:); - target = self; - } - else - { - searchButtonImage = CPSearchFieldFindImage; - action = @selector(_showMenu:); - target = self; - } + var button = [self searchButton], + searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage; [button setBordered:NO]; [button setImageScaling:CPScaleToFit]; [button setImage:searchButtonImage]; [button setAutoresizingMask:CPViewMaxXMargin]; - [button setTarget:target]; - [button setAction:action]; } /*! @@ -165,7 +162,18 @@ var CPSearchFieldSearchImage = nil, */ - (void)setCancelButton:(CPButton)button { - _cancelButton = button; + if (button != _cancelButton) + { + [_cancelButton removeFromSuperview]; + _cancelButton = button; + + [_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]]; + [_cancelButton setAutoresizingMask:CPViewMinXMargin]; + [_cancelButton setTarget:self]; + [_cancelButton setAction:@selector(_searchFieldCancel:)]; + [self _updateCancelButtonVisibility]; + [self addSubview:_cancelButton]; + } } /*! @@ -200,23 +208,24 @@ var CPSearchFieldSearchImage = nil, @return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter. Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control. */ -- (CPRect)searchTextRectForBounds:(CPRect)rect +- (CGRect)searchTextRectForBounds:(CGRect)rect { - var leftOffset = 0, width = rect.size.width; + var leftOffset = 0, + width = CGRectGetWidth(rect); if (_searchButton) { - var searchRect = [_searchButton frame]; - leftOffset = searchRect.origin.x + searchRect.size.width; + var searchBounds = [self searchButtonRectForBounds:rect]; + leftOffset = CGRectGetWidth(searchBounds) + 6; } if (_cancelButton) { - var cancelRect = [_cancelButton frame]; - width = cancelRect.origin.x - leftOffset; + var cancelRect = [self cancelButtonRectForBounds:rect]; + width = CGRectGetMinX(cancelRect) - leftOffset; } - return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height); + return CGRectMake(leftOffset, CGRectGetMinY(rect), width, CGRectGetHeight(rect)); } /*! @@ -224,9 +233,9 @@ var CPSearchFieldSearchImage = nil, @param rect The current bounding rectangle for the search button. Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control. */ -- (CPRect)searchButtonRectForBounds:(CPRect)rect +- (CGRect)searchButtonRectForBounds:(CGRect)rect { - return [_searchButton frame]; + return CGRectMake(5, (CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT); } /*! @@ -234,9 +243,9 @@ var CPSearchFieldSearchImage = nil, @param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter. Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control. */ -- (CPRect)cancelButtonRectForBounds:(CPRect)rect -{ - return [_cancelButton frame]; +- (CGRect)cancelButtonRectForBounds:(CGRect)rect +{ + return CGRectMake(CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT); } // Managing Menu Templates @@ -373,7 +382,7 @@ var CPSearchFieldSearchImage = nil, // Private methods and subclassing -- (CPRect)contentRectForBounds:(CPRect)bounds +- (CGRect)contentRectForBounds:(CGRect)bounds { var superbounds = [super contentRectForBounds:bounds]; return [self searchTextRectForBounds:superbounds]; @@ -447,32 +456,38 @@ var CPSearchFieldSearchImage = nil, [self _updateSearchMenu]; } -- (BOOL)trackMouse:(CPEvent)event +- (CPView)hitTest:(CGPoint)aPoint { - var rect, - point, - location = [event locationInWindow]; - - point = [self convertPoint:location fromView:nil]; - - rect = [self searchButtonRectForBounds:[self frame]]; - if (CPRectContainsPoint(rect,point)) + return self; +} + +- (BOOL)resignFirstResponder +{ + return _canResignFirstResponder; +} + +- (void)mouseDown:(CPEvent)anEvent +{ + var location = [anEvent locationInWindow], + point = [self convertPoint:location fromView:nil]; + + if (CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point)) { - return [[self searchButton] trackMouse:event]; - } - - rect = [self cancelButtonRectForBounds:[self frame]]; - if (CPRectContainsPoint(rect,point)) - { - return [[self cancelButton] trackMouse:event]; - } - - return [super trackMouse:event]; + if (_searchMenuTemplate == nil) + [self _sendAction]; + else + [self _showMenu]; + } + else if (CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point)) + [_cancelButton mouseDown:anEvent]; + else + [super mouseDown:anEvent]; } - (CPMenu)_defaultSearchMenuTemplate { - var template, item; + var template, + item; template = [[CPMenu alloc] init]; @@ -512,7 +527,8 @@ var CPSearchFieldSearchImage = nil, if (_searchMenuTemplate === nil) return; - var i, menu = [[CPMenu alloc] init], + var i, + menu = [[CPMenu alloc] init], countOfRecents = [_recentSearches count], numberOfItems = [_searchMenuTemplate numberOfItems]; @@ -548,6 +564,7 @@ var CPSearchFieldSearchImage = nil, [templateItem setTarget:itemTarget]; [templateItem setEnabled:([item isEnabled] && itemAction != NULL)]; [templateItem setTag:tag]; + [templateItem setImage:[item image]]; [menu addItem:templateItem]; } else if (tag === CPSearchFieldRecentsMenuItemTag) @@ -555,18 +572,31 @@ var CPSearchFieldSearchImage = nil, var j; for (j = 0; j < countOfRecents; j++) { - var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] + var recentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] action:@selector(_searchFieldSearch:) keyEquivalent:[item keyEquivalent]]; - [rencentItem setTarget:self]; - [menu addItem:rencentItem]; + [recentItem setTarget:self]; + [menu addItem:recentItem]; } } - } + } + + [menu setDelegate:self]; + _searchMenu = menu; } -- (void)_showMenu:(id)sender +- (void)menuWillOpen:(CPMenu)menu +{ + _canResignFirstResponder = NO; +} + +- (void)menuDidClose:(CPMenu)menu +{ + _canResignFirstResponder = YES; +} + +- (void)_showMenu { if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled]) return; @@ -576,12 +606,14 @@ var CPSearchFieldSearchImage = nil, var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0]; - [CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender]; + [self selectAll:nil]; + [CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self]; } - (void)_sendPartialString { - [self _sendAction:self]; + [super sendAction:[self action] to:[self target]]; + [_partialStringTimer invalidate]; } - (void)_searchFieldCancel:(id)sender @@ -600,7 +632,8 @@ var CPSearchFieldSearchImage = nil, [self setObjectValue:searchString]; [self _sendPartialString]; - + [self selectAll:nil]; + [self _updateCancelButtonVisibility]; } diff --git a/Tests/Manual/CPSearchField/AppController.j b/Tests/Manual/CPSearchField/AppController.j index 5d47dbca2..a637de37b 100644 --- a/Tests/Manual/CPSearchField/AppController.j +++ b/Tests/Manual/CPSearchField/AppController.j @@ -12,13 +12,13 @@ var categories = ["firstName","lastName"]; @implementation AppController : CPObject { - var searchField; - var table; + CPSearchField searchField; + CPTableView table; - var tableArray; - var filteredArray; + CPArray tableArray; + CPArray filteredArray; - var searchCategoryIndex; + CPInteger searchCategoryIndex; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification @@ -74,6 +74,17 @@ var categories = ["firstName","lastName"]; [template addItem:item]; [searchField setSearchMenuTemplate:template]; + + var button = [[CPButton alloc] initWithFrame:CGRectMakeZero()]; + [button setBackgroundColor:[CPColor greenColor]]; + [button setBordered:NO]; + [searchField setSearchButton:button]; + + button = [[CPButton alloc] initWithFrame:CGRectMakeZero()]; + [button setBackgroundColor:[CPColor blueColor]]; + [button setBordered:NO]; + [searchField setCancelButton:button]; + [searchFieldContainer addSubview:searchField]; [contentView addSubview:searchFieldContainer]; From f3b92c7445afef7890be139126e1b9a444316762 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 11:49:46 -0400 Subject: [PATCH 115/356] Fixes to cacaodev/searchfield/ffb8f99603d96b903b6bb39bc4dcb15ad09465be... - Replaced CG functions with inline _CG functions - _canResignFirstResponder was not being initialized to YES - -resignFirstResponder has to call super if _canResignFirstResponder == YES --- AppKit/CPSearchField.j | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index d77bb4c9c..e0c605024 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -22,6 +22,7 @@ @import "CPTextField.j" +#include "CoreGraphics/CGGeometry.h" #include "Platform/Platform.h" CPSearchFieldRecentsTitleMenuItemTag = 1000; @@ -68,10 +69,10 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, return; var bundle = [CPBundle bundleForClass:self]; - CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; - CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; - CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; - CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; + CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; } - (id)initWithFrame:(CGRect)frame @@ -112,6 +113,8 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, var searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]]; [self setSearchButton:searchButton]; [self resetSearchButton]; + + _canResignFirstResponder = YES; } // Managing Buttons @@ -211,21 +214,21 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (CGRect)searchTextRectForBounds:(CGRect)rect { var leftOffset = 0, - width = CGRectGetWidth(rect); + width = _CGRectGetWidth(rect); if (_searchButton) { var searchBounds = [self searchButtonRectForBounds:rect]; - leftOffset = CGRectGetWidth(searchBounds) + 6; + leftOffset = _CGRectGetWidth(searchBounds) + 6; } if (_cancelButton) { var cancelRect = [self cancelButtonRectForBounds:rect]; - width = CGRectGetMinX(cancelRect) - leftOffset; + width = _CGRectGetMinX(cancelRect) - leftOffset; } - return CGRectMake(leftOffset, CGRectGetMinY(rect), width, CGRectGetHeight(rect)); + return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect)); } /*! @@ -235,7 +238,7 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, */ - (CGRect)searchButtonRectForBounds:(CGRect)rect { - return CGRectMake(5, (CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT); + return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT); } /*! @@ -245,7 +248,7 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, */ - (CGRect)cancelButtonRectForBounds:(CGRect)rect { - return CGRectMake(CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT); + return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT); } // Managing Menu Templates @@ -463,6 +466,9 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (BOOL)resignFirstResponder { + if (_canResignFirstResponder) + [super resignFirstResponder]; + return _canResignFirstResponder; } @@ -471,14 +477,14 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, var location = [anEvent locationInWindow], point = [self convertPoint:location fromView:nil]; - if (CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point)) + if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point)) { if (_searchMenuTemplate == nil) - [self _sendAction]; + [self _sendAction:self]; else [self _showMenu]; } - else if (CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point)) + else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point)) [_cancelButton mouseDown:anEvent]; else [super mouseDown:anEvent]; From 4c562048dc3df56a3778e82b1b9e1d5712162189 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 22:37:28 -0400 Subject: [PATCH 116/356] More fixes to CPSearchField (Cocoa compliance and bugs): - Added the ability to specify a separator in the template by using the tag CPSearchFieldSeparatorMenuItemTag. - _recentSearches was not being initialized by -initWithCoder, moved that code into -_init. - -setSearchMenuTemplate was not being invoked. Since having a recents menu is the default behavior in Cocoa, it should probably be the default behavior in cappuccino. To turn it off, set _maximumRecents to >= 254. - -searchTextRectForBounds was using the wrong rect for -searchButtonRectForBounds and -cancelButtonRectForBounds, resulting in a rect that was too narrow and did not fill the space. - Tightened up the spacing between the magnifying glass and the text to exactly Cocoa distance. - Overhauled - updateSearchMenu to fix some logic bugs. - Made sure the search field becomes first responder after closing the search menu. - Cleared the search string when clearing recent searches, this is what Safari does. - Removed redundant invoking of -setDelegate in -initWithCoder. - -_init has to be called last in _initWithCoder. --- AppKit/CPSearchField.j | 189 +++++++++++++++++++++++++++-------------- 1 file changed, 126 insertions(+), 63 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index e0c605024..30790a600 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -29,6 +29,7 @@ CPSearchFieldRecentsTitleMenuItemTag = 1000; CPSearchFieldRecentsMenuItemTag = 1001; CPSearchFieldClearRecentsMenuItemTag = 1002; CPSearchFieldNoRecentsMenuItemTag = 1003; +CPSearchFieldSeparatorMenuItemTag = 1004; var CPSearchFieldSearchImage = nil, CPSearchFieldFindImage = nil, @@ -39,6 +40,9 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, CANCEL_BUTTON_DEFAULT_WIDTH = 22.0, BUTTON_DEFAULT_HEIGHT = 22.0; +var RECENT_SEARCH_PREFIX = @" "; + + /*! @ingroup appkit @class CPSearchField @@ -79,7 +83,6 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, { if (self = [super initWithFrame:frame]) { - _recentSearches = [CPArray array]; _maximumRecents = 10; _sendsWholeSearchString = NO; _sendsSearchStringImmediately = NO; @@ -97,8 +100,8 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (void)_initWithFrame:(CGRect)frame { - var bounds = [self bounds]; - + _recentSearches = [CPArray array]; + [self setBezeled:YES]; [self setBezelStyle:CPTextFieldRoundedBezel]; [self setBordered:YES]; @@ -106,15 +109,20 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, [self setDelegate:self]; [self setContinuous:YES]; - var cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]]; + var bounds = [self bounds], + cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]], + searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]]; + [self setCancelButton:cancelButton]; [self resetCancelButton]; - var searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]]; [self setSearchButton:searchButton]; [self resetSearchButton]; _canResignFirstResponder = YES; + + if (_maximumRecents < 254 && !_searchMenuTemplate) + [self setSearchMenuTemplate:[self _defaultSearchMenuTemplate]]; } // Managing Buttons @@ -214,17 +222,18 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (CGRect)searchTextRectForBounds:(CGRect)rect { var leftOffset = 0, - width = _CGRectGetWidth(rect); + width = _CGRectGetWidth(rect), + bounds = [self bounds]; if (_searchButton) { - var searchBounds = [self searchButtonRectForBounds:rect]; - leftOffset = _CGRectGetWidth(searchBounds) + 6; + var searchBounds = [self searchButtonRectForBounds:bounds]; + leftOffset = _CGRectGetMaxX(searchBounds) + 2; } if (_cancelButton) { - var cancelRect = [self cancelButtonRectForBounds:rect]; + var cancelRect = [self cancelButtonRectForBounds:bounds]; width = _CGRectGetMinX(cancelRect) - leftOffset; } @@ -266,9 +275,9 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, @param menu The menu template to use. The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template. */ -- (void)setSearchMenuTemplate:(CPMenu)menu +- (void)setSearchMenuTemplate:(CPMenu)aMenu { - _searchMenuTemplate = menu; + _searchMenuTemplate = aMenu; [self resetSearchButton]; [self _loadRecentSearchList]; @@ -492,13 +501,11 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (CPMenu)_defaultSearchMenuTemplate { - var template, + var template = [[CPMenu alloc] init], item; - - template = [[CPMenu alloc] init]; - + item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" - action:NULL + action:nil keyEquivalent:@""]; [item setTag:CPSearchFieldRecentsTitleMenuItemTag]; [item setEnabled:NO]; @@ -519,12 +526,28 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, [template addItem:item]; item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" - action:NULL + action:nil keyEquivalent:@""]; [item setTag:CPSearchFieldNoRecentsMenuItemTag]; [item setEnabled:NO]; [template addItem:item]; + /* + To add a separator: + + [self _addSeparatorToMenu:template]; + + + To add a custom item: + + item = [[CPMenuItem alloc] initWithTitle:@"google" + action:@selector(_google:) + keyEquivalent:@""]; + [item setTag:@"google"]; + [item setTarget:self]; + [template addItem:item]; + */ + return template; } @@ -533,58 +556,85 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, if (_searchMenuTemplate === nil) return; - var i, - menu = [[CPMenu alloc] init], + var menu = [[CPMenu alloc] init], countOfRecents = [_recentSearches count], numberOfItems = [_searchMenuTemplate numberOfItems]; - for (i = 0; i < numberOfItems; i++) + for (var i = 0; i < numberOfItems; i++) { var item = [_searchMenuTemplate itemAtIndex:i], - tag = [item tag]; - - if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) && - !(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) && - !(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) && - !(tag === CPSearchFieldRecentsMenuItemTag)) - { - var itemAction, itemTarget; - switch (tag) - { - case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break; - case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break; - case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break; - default: itemAction = [item action]; itemTarget = [item target]; break; - } + tag = [item tag], + itemAction = [item action], + itemTarget = [item target]; - if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag) - { - var separator = [CPMenuItem separatorItem]; - [separator setEnabled:NO]; - [menu addItem:separator]; - } - - var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] - action:itemAction - keyEquivalent:[item keyEquivalent]]; - [templateItem setTarget:itemTarget]; - [templateItem setEnabled:([item isEnabled] && itemAction != NULL)]; - [templateItem setTag:tag]; - [templateItem setImage:[item image]]; - [menu addItem:templateItem]; - } - else if (tag === CPSearchFieldRecentsMenuItemTag) + switch (tag) { - var j; - for (j = 0; j < countOfRecents; j++) + case CPSearchFieldRecentsTitleMenuItemTag: + if (countOfRecents === 0) + continue; + + if ([menu numberOfItems] > 0) + [self _addSeparatorToMenu:menu]; + break; + + case CPSearchFieldRecentsMenuItemTag: { - var recentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] - action:@selector(_searchFieldSearch:) - keyEquivalent:[item keyEquivalent]]; - [recentItem setTarget:self]; - [menu addItem:recentItem]; + var recentItemTemplate = [_searchMenuTemplate itemWithTag:CPSearchFieldRecentsMenuItemTag], + recentItemAction, recentItemTarget, recentItemKeyEquivalent; + + if (recentItemTemplate) + { + recentItemAction = [recentItemTemplate action]; + recentItemTarget = [recentItemTemplate target]; + recentItemKeyEquivalent = [recentItemTemplate keyEquivalent]; + } + else + { + recentItemAction = @selector(_searchFieldSearch:); + recentItemTarget = self; + recentItemKeyEquivalent = @""; + } + + for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex) + { + var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex] + action:recentItemAction + keyEquivalent:recentItemKeyEquivalent]; + [recentItem setTarget:recentItemTarget]; + [menu addItem:recentItem]; + } + + continue; } + + case CPSearchFieldClearRecentsMenuItemTag: + if (countOfRecents === 0) + continue; + + if ([menu numberOfItems] > 0) + [self _addSeparatorToMenu:menu]; + break; + + case CPSearchFieldNoRecentsMenuItemTag: + if (countOfRecents !== 0) + continue; + break; + + case CPSearchFieldSeparatorMenuItemTag: + item = [CPMenuItem separatorItem]; + [item setEnabled:NO]; + [menu addItem:item]; + continue; } + + var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] + action:itemAction + keyEquivalent:[item keyEquivalent]]; + [templateItem setTarget:itemTarget]; + [templateItem setEnabled:([item isEnabled] && itemAction != nil)]; + [templateItem setTag:tag]; + [templateItem setImage:[item image]]; + [menu addItem:templateItem]; } [menu setDelegate:self]; @@ -592,6 +642,13 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, _searchMenu = menu; } +- (void)_addSeparatorToMenu:(CPMenu)aMenu +{ + var separator = [CPMenuItem separatorItem]; + [separator setEnabled:NO]; + [aMenu addItem:separator]; +} + - (void)menuWillOpen:(CPMenu)menu { _canResignFirstResponder = NO; @@ -600,6 +657,8 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (void)menuDidClose:(CPMenu)menu { _canResignFirstResponder = YES; + + [self becomeFirstResponder]; } - (void)_showMenu @@ -631,7 +690,7 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, - (void)_searchFieldSearch:(id)sender { - var searchString = [sender title]; + var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]]; if ([sender tag] != CPSearchFieldRecentsMenuItemTag) [self _addStringToRecentSearches:searchString]; @@ -647,6 +706,8 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0, { [self setRecentSearches:[CPArray array]]; [self _updateSearchMenu]; + [self setStringValue:@""]; + [self _updateCancelButtonVisibility]; } - (void)_registerForAutosaveNotification @@ -707,7 +768,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey", CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey", CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey", CPMaximumRecentsKey = @"CPMaximumRecentsKey", - CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey"; + CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey"; @implementation CPSearchField (CPCoding) @@ -729,6 +790,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey", if (_recentsAutosaveName) [coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey]; + if (_searchMenuTemplate) [coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey]; } @@ -743,12 +805,13 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey", _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey]; _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey]; - + var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey]; + if (template) [self setSearchMenuTemplate:template]; - [self setDelegate:self]; + [self _init]; } return self; From 44a958d3f867b26174dadd9b1cc6c49c48143e44 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 24 Jul 2010 09:44:57 -0400 Subject: [PATCH 117/356] -hitTest was always returning self, which did not allow any other views to receive a mouse down --- AppKit/CPSearchField.j | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 30790a600..166821d88 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -470,7 +470,11 @@ var RECENT_SEARCH_PREFIX = @" "; - (CPView)hitTest:(CGPoint)aPoint { - return self; + // Make sure a hit anywhere within the search field returns the search field itself + if (_CGRectContainsPoint([self frame], aPoint)) + return self; + else + return nil; } - (BOOL)resignFirstResponder From 7caf5fe20aaced38aaa45aea95cf24940e6aa7ce Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 28 Jul 2010 14:54:07 -0700 Subject: [PATCH 118/356] Must return from this method. --- AppKit/CPSearchField.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 166821d88..d5ffe2198 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -480,7 +480,7 @@ var RECENT_SEARCH_PREFIX = @" "; - (BOOL)resignFirstResponder { if (_canResignFirstResponder) - [super resignFirstResponder]; + return [super resignFirstResponder]; return _canResignFirstResponder; } From 6426c8aee289d0c1273658cf7462b880d5bf0f51 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 17:18:08 -0400 Subject: [PATCH 119/356] Fix for issue #778 --- AppKit/CPMenuItem/_CPMenuItemStandardView.j | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/AppKit/CPMenuItem/_CPMenuItemStandardView.j b/AppKit/CPMenuItem/_CPMenuItemStandardView.j index 63777e96f..f41a42150 100644 --- a/AppKit/CPMenuItem/_CPMenuItemStandardView.j +++ b/AppKit/CPMenuItem/_CPMenuItemStandardView.j @@ -257,10 +257,13 @@ var SUBMENU_INDICATOR_COLOR = nil, [_keyEquivalentView setTextShadowColor:[self textShadowColor]]; } - if (shouldHighlight) - [_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil]; - else - [_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil]; + if ([[_menuItem menu] showsStateColumn]) + { + if (shouldHighlight) + [_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil]; + else + [_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil]; + } } @end From 3070634aabd0eb15da4f0bea748fd6192e07e28d Mon Sep 17 00:00:00 2001 From: Nicholas Small Date: Wed, 28 Jul 2010 18:06:08 -0400 Subject: [PATCH 120/356] Make -center on a bridge window into a no-op. --- AppKit/CPWindow/CPWindow.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 75650792f..9e7eac0dc 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1362,6 +1362,9 @@ CPTexturedBackgroundWindowMask */ - (void)center { + if (_isFullPlatformWindow) + return; + var size = [self frame].size, containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size; From 8702b1421f88b9e39011e82ade9b50172042e656 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 17:06:23 -0400 Subject: [PATCH 121/356] Fix for issue #777, also fixed a declared type while I was at it --- AppKit/CPMenu/CPMenu.j | 2 +- AppKit/CPPopUpButton.j | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 39203dfa7..4cdcd7a16 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -75,7 +75,7 @@ var _CPMenuBarVisible = NO, id _delegate; - CPMenuItem _highlightedIndex; + int _highlightedIndex; _CPMenuWindow _menuWindow; } diff --git a/AppKit/CPPopUpButton.j b/AppKit/CPPopUpButton.j index b5ac0e1e1..6072501dd 100644 --- a/AppKit/CPPopUpButton.j +++ b/AppKit/CPPopUpButton.j @@ -662,6 +662,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0); minimumWidth += standardLeftMargin; + + // To ensure the selected item is highlighted correctly, unset the highlighted item + [menu _highlightItemAtIndex:CPNotFound]; } [menu setMinimumWidth:minimumWidth]; From f5322b39bc95ad50c1bd3f8579f101b92b6192d6 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 28 Jul 2010 15:13:21 -0700 Subject: [PATCH 122/356] Fix a debug mode bug in IE. Closes #768. --- Objective-J/Runtime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objective-J/Runtime.js b/Objective-J/Runtime.js index 7a88ebb9a..7c4566b4e 100644 --- a/Objective-J/Runtime.js +++ b/Objective-J/Runtime.js @@ -70,7 +70,7 @@ GLOBAL(objj_class) = function(displayName) #if DEBUG // naming the allocator allows the WebKit heap snapshot tool to display object class names correctly // HACK: displayName property is not respected so we must eval a function to name it - this.allocator = eval("(function " + (displayName || "OBJJ_OBJECT").replace(/\W/g, "_") + "() { })"); + eval("this.allocator = function " + (displayName || "OBJJ_OBJECT").replace(/\W/g, "_") + "() { }"); #else this.allocator = function() { }; #endif From 006f709d3704103b27ffcd566e885791f60b5b24 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 28 Jul 2010 14:30:20 -0400 Subject: [PATCH 123/356] Fixes to commit 69273259a56ae8e5d276a1d4da515322a39e553f: - No longer setting the search menu template to the default, but -defaultSearchMenuTemplate was made public. - Action and target for clear recents item is always set to CPSearchField -_searchFieldClearRecents: since that is a built-in type. - Action and target for recents item is always set to CPSearchField -_searchFieldSearch: since that is a built-in type. - Template menu items are copied via CPMenuItem -copy (which is now implemented), so all state is maintained. --- AppKit/CPMenuItem/CPMenuItem.j | 44 ++++++++++++++++++++++++++++-- AppKit/CPSearchField.j | 50 ++++++++++------------------------ 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index 1e14e2f17..0f173c7da 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -782,7 +782,48 @@ CPControlKeyMask return [[self menu] highlightedItem] == self; } -// +#pragma mark CPObject Overrides + +/*! + Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied. +*/ +- (id)copy +{ + var item = [[CPMenuItem alloc] init]; + + // No point in going through accessors and doing lots of unnecessary state checking/updating + item._isSeparator = _isSeparator; + + [item setTitle:_title]; + [item setFont:_font]; + [item setTarget:_target]; + [item setAction:_action]; + [item setEnabled:_isEnabled]; + [item setHidden:_isHidden] + [item setTag:_tag]; + [item setState:_state]; + [item setImage:_image]; + [item setAlternateImage:_alternateImage]; + [item setOnStateImage:_onStateImage]; + [item setOffStateImage:_offStateImage]; + [item setMixedStateImage:_mixedStateImage]; + [item setKeyEquivalent:_keyEquivalent]; + [item setKeyEquivalentModifierMask:_keyEquivalentModifierMask]; + [item setMnemonicLocation:_mnemonicLocation]; + [item setAlternate:_isAlternate]; + [item setIndentationLevel:_indentationLevel]; + [item setToolTip:_toolTip]; + [item setRepresentedObject:_representedObject]; + + return item; +} + +- (id)mutableCopy +{ + return [self copy]; +} + +#pragma mark Internal /* @ignore @@ -861,7 +902,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", _isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO); _tag = DEFAULT_VALUE(CPMenuItemTagKey, 0); _state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState); -// int _state; _image = DEFAULT_VALUE(CPMenuItemImageKey, nil); _alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil); diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index d5ffe2198..ba052c281 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -120,9 +120,6 @@ var RECENT_SEARCH_PREFIX = @" "; [self resetSearchButton]; _canResignFirstResponder = YES; - - if (_maximumRecents < 254 && !_searchMenuTemplate) - [self setSearchMenuTemplate:[self _defaultSearchMenuTemplate]]; } // Managing Buttons @@ -503,7 +500,7 @@ var RECENT_SEARCH_PREFIX = @" "; [super mouseDown:anEvent]; } -- (CPMenu)_defaultSearchMenuTemplate +- (CPMenu)defaultSearchMenuTemplate { var template = [[CPMenu alloc] init], item; @@ -566,12 +563,9 @@ var RECENT_SEARCH_PREFIX = @" "; for (var i = 0; i < numberOfItems; i++) { - var item = [_searchMenuTemplate itemAtIndex:i], - tag = [item tag], - itemAction = [item action], - itemTarget = [item target]; + var item = [[_searchMenuTemplate itemAtIndex:i] copy]; - switch (tag) + switch ([item tag]) { case CPSearchFieldRecentsTitleMenuItemTag: if (countOfRecents === 0) @@ -583,28 +577,15 @@ var RECENT_SEARCH_PREFIX = @" "; case CPSearchFieldRecentsMenuItemTag: { - var recentItemTemplate = [_searchMenuTemplate itemWithTag:CPSearchFieldRecentsMenuItemTag], - recentItemAction, recentItemTarget, recentItemKeyEquivalent; - - if (recentItemTemplate) - { - recentItemAction = [recentItemTemplate action]; - recentItemTarget = [recentItemTemplate target]; - recentItemKeyEquivalent = [recentItemTemplate keyEquivalent]; - } - else - { - recentItemAction = @selector(_searchFieldSearch:); - recentItemTarget = self; - recentItemKeyEquivalent = @""; - } - + var itemAction = @selector(_searchFieldSearch:); + for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex) { + // RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex] - action:recentItemAction - keyEquivalent:recentItemKeyEquivalent]; - [recentItem setTarget:recentItemTarget]; + action:itemAction + keyEquivalent:[item keyEquivalent]]; + [item setTarget:self]; [menu addItem:recentItem]; } @@ -617,6 +598,9 @@ var RECENT_SEARCH_PREFIX = @" "; if ([menu numberOfItems] > 0) [self _addSeparatorToMenu:menu]; + + [item setAction:@selector(_searchFieldClearRecents:)]; + [item setTarget:self]; break; case CPSearchFieldNoRecentsMenuItemTag: @@ -631,14 +615,8 @@ var RECENT_SEARCH_PREFIX = @" "; continue; } - var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] - action:itemAction - keyEquivalent:[item keyEquivalent]]; - [templateItem setTarget:itemTarget]; - [templateItem setEnabled:([item isEnabled] && itemAction != nil)]; - [templateItem setTag:tag]; - [templateItem setImage:[item image]]; - [menu addItem:templateItem]; + [item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)]; + [menu addItem:item]; } [menu setDelegate:self]; From eb99b7d7ca9ba091a09ec3794b716f5e2e01c95f Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 28 Jul 2010 15:02:51 -0400 Subject: [PATCH 124/356] CPSearchField fixes/enhancements to commit 5b763928fe6ddc204a8c85f67160846c62ce45fe: - Added more documentation for -defaultSearchTemplate. - Capitalized the text of the menu items in the default template. - Adding a separator before no recents menu item if there are items before it. - Updated the test app to use the default template and then modify it. - Updated the test app to maintain the state of the custom items. --- AppKit/CPSearchField.j | 58 +++++++++++----- Tests/Manual/CPSearchField/AppController.j | 80 ++++++++++++---------- 2 files changed, 81 insertions(+), 57 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index ba052c281..5597b6a6c 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -500,12 +500,45 @@ var RECENT_SEARCH_PREFIX = @" "; [super mouseDown:anEvent]; } +/*! + Provides the common case items for a recent searches menu. If there are not recent searches, + displays a single disabled item: + + No Recent Searches + + If there are 1 more recent searches, it displays: + + Recent Searches + recent search 1 + recent search 2 + etc. + --------------------- + Clear Recent Searches + + If you wish to add items before or after the template, you can. If you put items + before, a separator will automatically be placed before the default template item. + If you add items after the default template, it is your responsibility to add a separator. + + To add a custom item: + + item = [[CPMenuItem alloc] initWithTitle:@"google" + action:@selector(google:) + keyEquivalent:@""]; + [item setTag:700]; + [item setTarget:self]; + [template addItem:item]; + + Be sure that your custom items do not use tags in the range 1000-1004 inclusive. + If you wish to maintain state in custom menu items that you add, you will need to maintain + the item state yourself, then in the action method of the custom items, modify the items + in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu. +*/ - (CPMenu)defaultSearchMenuTemplate { var template = [[CPMenu alloc] init], item; - item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" + item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches" action:nil keyEquivalent:@""]; [item setTag:CPSearchFieldRecentsTitleMenuItemTag]; @@ -519,36 +552,20 @@ var RECENT_SEARCH_PREFIX = @" "; [item setTarget:self]; [template addItem:item]; - item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches" + item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches" action:@selector(_searchFieldClearRecents:) keyEquivalent:@""]; [item setTag:CPSearchFieldClearRecentsMenuItemTag]; [item setTarget:self]; [template addItem:item]; - item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" + item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches" action:nil keyEquivalent:@""]; [item setTag:CPSearchFieldNoRecentsMenuItemTag]; [item setEnabled:NO]; [template addItem:item]; - /* - To add a separator: - - [self _addSeparatorToMenu:template]; - - - To add a custom item: - - item = [[CPMenuItem alloc] initWithTitle:@"google" - action:@selector(_google:) - keyEquivalent:@""]; - [item setTag:@"google"]; - [item setTarget:self]; - [template addItem:item]; - */ - return template; } @@ -606,6 +623,9 @@ var RECENT_SEARCH_PREFIX = @" "; case CPSearchFieldNoRecentsMenuItemTag: if (countOfRecents !== 0) continue; + + if ([menu numberOfItems] > 0) + [self _addSeparatorToMenu:menu]; break; case CPSearchFieldSeparatorMenuItemTag: diff --git a/Tests/Manual/CPSearchField/AppController.j b/Tests/Manual/CPSearchField/AppController.j index a637de37b..d4d4abd24 100644 --- a/Tests/Manual/CPSearchField/AppController.j +++ b/Tests/Manual/CPSearchField/AppController.j @@ -8,22 +8,28 @@ @import @import -var categories = ["firstName","lastName"]; +var categories = ["firstName","lastName"], + MenuItemPrefix = @" "; @implementation AppController : CPObject { - CPSearchField searchField; - CPTableView table; + CPSearchField searchField; + CPTableView table; - CPArray tableArray; - CPArray filteredArray; + CPArray tableArray; + CPArray filteredArray; - CPInteger searchCategoryIndex; + CPMenu searchMenuTemplate; + + CPArray searchCategoryIndexes; + CPInteger searchCategoryIndex; } - (void)applicationDidFinishLaunching:(CPNotification)aNotification { searchCategoryIndex = 0; + searchCategoryIndexes = [CPArray arrayWithArray:[1, 2]]; + var theWindow = [[CPWindow alloc] initWithContentRect:CPMakeRect(0,10,500,300) styleMask:CPTitledWindowMask|CPResizableWindowMask], contentView = [theWindow contentView]; @@ -37,43 +43,32 @@ var categories = ["firstName","lastName"]; [searchField setTarget:self]; [searchField setAction:@selector(updateFilter:)]; [searchField setAutoresizingMask:CPViewWidthSizable]; - - var template = [[CPMenu alloc] initWithTitle:@"Search Menu"]; + + searchMenuTemplate = [searchField defaultSearchMenuTemplate]; - var item; - item = [[CPMenuItem alloc] initWithTitle:@"Search by" - action:nil - keyEquivalent:@""]; - [item setEnabled:NO]; - [template addItem:item]; + [searchMenuTemplate insertItemWithTitle:@"Search By" + action:nil + keyEquivalent:@"" + atIndex:0]; - item = [[CPMenuItem alloc] initWithTitle:@"First Name" - action:@selector(changeCategory:) - keyEquivalent:@""]; + var item = [[CPMenuItem alloc] initWithTitle:MenuItemPrefix + @"First Name" + action:@selector(changeCategory:) + keyEquivalent:@""]; + [item setTarget:self]; [item setTag:1]; - [template addItem:item]; + [item setState:CPOnState]; + [searchMenuTemplate insertItem:item atIndex:1]; - item = [[CPMenuItem alloc] initWithTitle:@"Last Name" - action:@selector(changeCategory:) + item = [[CPMenuItem alloc] initWithTitle:MenuItemPrefix + @"Last Name" + action:@selector(changeCategory:) keyEquivalent:@""]; [item setTarget:self]; [item setTag:2]; - [template addItem:item]; - - item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" action:NULL keyEquivalent:@""]; - [item setTag:CPSearchFieldRecentsTitleMenuItemTag]; - [template addItem:item]; - - item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""]; - [item setTag:CPSearchFieldRecentsMenuItemTag]; - [template addItem:item]; + [item setState:CPOffState]; + [searchMenuTemplate insertItem:item atIndex:2]; - item = [[CPMenuItem alloc] initWithTitle:@"Clear recents" action:NULL keyEquivalent:@""]; - [item setTag:CPSearchFieldClearRecentsMenuItemTag]; - [template addItem:item]; - - [searchField setSearchMenuTemplate:template]; + [searchField setSearchMenuTemplate:searchMenuTemplate]; var button = [[CPButton alloc] initWithFrame:CGRectMakeZero()]; [button setBackgroundColor:[CPColor greenColor]]; @@ -133,16 +128,25 @@ var categories = ["firstName","lastName"]; - (void)changeCategory:(CPMenuItem)menuItem { - [[[searchField menu] itemArray] makeObjectsPerformSelector:@selector(setState:) withObject:0]; - [menuItem setState:1]; searchCategoryIndex = [menuItem tag] - 1; - [searchField setPlaceholderString:[menuItem title]]; + [searchField setPlaceholderString:[[menuItem title] substringFromIndex:[MenuItemPrefix length]]]; + + [self _updateSearchMenuTemplate]; +} + +- (void)_updateSearchMenuTemplate +{ + for (var i = 0; i < searchCategoryIndexes.length; ++i) + [[searchMenuTemplate itemAtIndex:i + 1] setState:CPOffState]; + + [[searchMenuTemplate itemAtIndex:searchCategoryIndex + 1] setState:CPOnState]; + [searchField setSearchMenuTemplate:searchMenuTemplate]; } - (void)updateFilter:(id)sender { var searchString = [searchField stringValue]; - + filteredArray = [self filteredArrayWithString:searchString]; [table reloadData]; } From edc5542ee6c1aa2fbe46403715712e5dabdfe1d2 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 18:02:51 -0400 Subject: [PATCH 125/356] Fix for issue #748 --- AppKit/CPTableColumn.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 17b731d18..a6ebed652 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -289,6 +289,9 @@ CPTableColumnUserResizingMask = 1 << 1; var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]]; newDataView.identifier = dataViewUID; + // make sure only we have control over the size and placement + [newDataView setAutoresizingMask:CPViewNotSizable]; + return newDataView; } From aea19c5cd085e57a6a26fa742767d6f1d21274ce Mon Sep 17 00:00:00 2001 From: Andreas Date: Tue, 29 Jun 2010 15:00:19 +0200 Subject: [PATCH 126/356] Add modal stylemask in nib2cib --- Tools/nib2cib/NSWindowTemplate.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/nib2cib/NSWindowTemplate.j b/Tools/nib2cib/NSWindowTemplate.j index 97afbe8ce..ea89c162e 100644 --- a/Tools/nib2cib/NSWindowTemplate.j +++ b/Tools/nib2cib/NSWindowTemplate.j @@ -29,6 +29,7 @@ var NSBorderlessWindowMask = 0x00, NSMiniaturizableWindowMask = 0x04, NSResizableWindowMask = 0x08, NSUtilityWindowMask = 0x10, + NSDocModalWindowMask = 0x40, NSTexturedBackgroundWindowMask = 0x100, NSHUDBackgroundWindowMask = 0x2000; @@ -70,6 +71,7 @@ var NSBorderlessWindowMask = 0x00, (_windowStyleMask & NSMiniaturizableWindowMask ? CPMiniaturizableWindowMask : 0) | (_windowStyleMask & NSResizableWindowMask ? CPResizableWindowMask : 0) | (_windowStyleMask & NSTexturedBackgroundWindowMask ? NSTexturedBackgroundWindowMask : 0) | + (_windowStyleMask & NSDocModalWindowMask ? CPDocModalWindowMask : 0) | (_windowStyleMask & NSHUDBackgroundWindowMask ? CPHUDBackgroundWindowMask : 0); _windowIsFullBridge = [aCoder decodeObjectForKey:"NSFrameAutosaveName"] === "CPBorderlessBridgeWindowMask"; From b4dbe422ff8d0902733f6b632e1fb051198cd637 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 28 Jul 2010 15:48:25 -0700 Subject: [PATCH 127/356] Revert to addObject if there are no sort descriptors in insert...sortedby. Closes #764. --- Foundation/CPArray.j | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 27acbd1f2..7a0851c29 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -507,6 +507,12 @@ - (unsigned)insertObject:(id)anObject inArraySortedByDescriptors:(CPArray)descriptors { + if (!descriptors || ![descriptors count]) + { + [self addObject:anObject]; + return [self count] - 1; + } + var index = [self _insertObject:anObject sortedByFunction:function(lhs, rhs) { var i = 0, From cb7f60aba8ddc41be1171fb3777733113c8374af Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 12:13:49 -0400 Subject: [PATCH 128/356] Added -indexOfObjectPassingTest: and related methods --- Foundation/CPArray.j | 95 ++++++++++++++++++++++++++++++++++ Tests/Foundation/CPArrayTest.j | 50 ++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 7a0851c29..654eacb99 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -26,6 +26,9 @@ @import "CPRange.j" @import "CPSortDescriptor.j" +CPEnumerationNormal = 0; +CPEnumerationConcurrent = 1 << 0; +CPEnumerationReverse = 1 << 1; /* @ignore */ @implementation _CPArrayEnumerator : CPEnumerator @@ -397,6 +400,98 @@ return CPNotFound; } +/*! + Returns the index of the first object in the receiver that passes a test in a given Javascript function. + @param predicate The function to apply to elements of the array. The function receives two arguments: + object The element in the array. + index The index of the element in the array. + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @return The index of the first matching object, or \c CPNotFound if there is no matching object. +*/ +- (unsigned)indexOfObjectPassingTest:(Function)predicate +{ + return [self indexOfObjectWithOptions:CPEnumerationNormal passingTest:predicate context:nil]; +} + +/*! + Returns the index of the first object in the receiver that passes a test in a given Javascript function. + @param predicate The function to apply to elements of the array. The function receives two arguments: + object The element in the array. + index The index of the element in the array. + context The object passed to the receiver in the aContext parameter. + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @param context An object that contains context information you want passed to the predicate function. + @return The index of the first matching object, or \c CPNotFound if there is no matching object. +*/ +- (unsigned)indexOfObjectPassingTest:(Function)predicate context:(id)aContext +{ + return [self indexOfObjectWithOptions:CPEnumerationNormal passingTest:predicate context:aContext]; +} + +/*! + Returns the index of the first object in the receiver that passes a test in a given Javascript function. + @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + or CPEnumerationReverse to search in reverse. + @param predicate The function to apply to elements of the array. The function receives two arguments: + object The element in the array. + index The index of the element in the array. + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @return The index of the first matching object, or \c CPNotFound if there is no matching object. +*/ +- (unsigned)indexOfObjectWithOptions:(CPEnumerationOptions)opts passingTest:(Function)predicate +{ + return [self indexOfObjectWithOptions:opts passingTest:predicate context:nil]; +} + +/*! + Returns the index of the first object in the receiver that passes a test in a given Javascript function. + @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + or CPEnumerationReverse to search in reverse. + @param predicate The function to apply to elements of the array. The function receives two arguments: + object The element in the array. + index The index of the element in the array. + context The object passed to the receiver in the aContext parameter. + The predicate function should either return a Boolean value that indicates whether the object passed the test, + or nil to stop the search, which will return CPNotFound to the sender. + @param context An object that contains context information you want passed to the predicate function. + @return The index of the first matching object, or \c CPNotFound if there is no matching object. +*/ +- (unsigned)indexOfObjectWithOptions:(CPEnumerationOptions)opts passingTest:(Function)predicate context:(id)aContext +{ + // We don't use an enumerator because they return nil to indicate end of enumeration, + // but nil may actually be the value we are looking for, so we have to loop over the array. + + var start, stop, increment; + + if (opts & CPEnumerationReverse) + { + start = [self count] - 1; + stop = -1; + increment = -1; + } + else + { + start = 0; + stop = [self count]; + increment = 1; + } + + for (var i = start; i != stop; i += increment) + { + var result = predicate([self objectAtIndex:i], i, aContext); + + if (typeof result === 'boolean' && result) + return i; + else if (typeof result === 'object' && result == nil) + return CPNotFound; + } + + return CPNotFound; +} + /*! Returns the index of \c anObject in the array, which must be sorted in the same order as calling sortUsingSelector: with the selector passed to this method would result in. diff --git a/Tests/Foundation/CPArrayTest.j b/Tests/Foundation/CPArrayTest.j index 455399ab7..6b2688e5f 100644 --- a/Tests/Foundation/CPArrayTest.j +++ b/Tests/Foundation/CPArrayTest.j @@ -93,6 +93,56 @@ [self assert:array equals:[@"one", @"two", @"four", nil]]; } +- (void)testIndexOfObjectPassingTest +{ + var array = [CPArray arrayWithObjects:{name:@"Tom", age:7}, {name:@"Dick", age:13}, {name:@"Harry", age:27}, {name:@"Zelda", age:7}], + namePredicate = function(object, index) { return [object.name isEqual:@"Harry"]; }, + agePredicate = function(object, index) { return object.age === 13; }, + failPredicate = function(object, index) { return [object.name isEqual:@"Horton"]; }, + noPredicate = function(object, index) { return NO; }, + stopPredicate = function(object, index) { return nil; }; + + [self assert:[array indexOfObjectPassingTest:namePredicate] equals:2]; + [self assert:[array indexOfObjectPassingTest:agePredicate] equals:1]; + [self assert:[array indexOfObjectPassingTest:failPredicate] equals:CPNotFound]; + [self assert:[array indexOfObjectPassingTest:noPredicate] equals:CPNotFound]; + [self assert:[array indexOfObjectPassingTest:stopPredicate] equals:CPNotFound]; +} + +- (void)testIndexOfObjectPassingTestContext +{ + var array = [CPArray arrayWithObjects:{name:@"Tom", age:7}, {name:@"Dick", age:13}, {name:@"Harry", age:27}, {name:@"Zelda", age:7}], + namePredicate = function(object, index, context) { return [object.name isEqual:context]; }, + agePredicate = function(object, index, context) { return object.age === context; }; + + [self assert:[array indexOfObjectPassingTest:namePredicate context:@"Harry"] equals:2]; + [self assert:[array indexOfObjectPassingTest:agePredicate context:13] equals:1]; +} + +- (void)testIndexOfObjectWithOptionsPassingTest +{ + var array = [CPArray arrayWithObjects:{name:@"Tom", age:7}, {name:@"Dick", age:13}, {name:@"Harry", age:27}, {name:@"Zelda", age:7}], + namePredicate = function(object, index) { return [object.name isEqual:@"Harry"]; }, + agePredicate = function(object, index) { return object.age === 7; }; + + [self assert:[array indexOfObjectWithOptions:CPEnumerationNormal passingTest:namePredicate] equals:2]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationReverse passingTest:namePredicate] equals:2]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationNormal passingTest:agePredicate] equals:0]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationReverse passingTest:agePredicate] equals:3]; +} + +- (void)testIndexOfObjectWithOptionsPassingTestContext +{ + var array = [CPArray arrayWithObjects:{name:@"Tom", age:7}, {name:@"Dick", age:13}, {name:@"Harry", age:27}, {name:@"Zelda", age:7}], + namePredicate = function(object, index, context) { return [object.name isEqual:context]; }, + agePredicate = function(object, index, context) { return object.age === context; }; + + [self assert:[array indexOfObjectWithOptions:CPEnumerationNormal passingTest:namePredicate context:@"Harry"] equals:2]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationReverse passingTest:namePredicate context:@"Harry"] equals:2]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationNormal passingTest:agePredicate context:7] equals:0]; + [self assert:[array indexOfObjectWithOptions:CPEnumerationReverse passingTest:agePredicate context:7] equals:3]; +} + - (void)testIndexOfObjectSortedByFunction { var array = [0, 1, 2, 3, 4, 7]; From 8ecac8d03c512b17729f74e96b71483c81e9ea7d Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 28 Jul 2010 19:03:43 -0400 Subject: [PATCH 129/356] Fix and test case for issue #746 --- Foundation/CPIndexSet.j | 4 ++-- Tests/Foundation/CPIndexSetTest.j | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 266c7273e..91855dc9b 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -698,12 +698,12 @@ var range = _ranges[i], maximum = CPMaxRange(range); - if (anIndex > maximum) + if (anIndex >= maximum) break; // If our index is within our range, but not the first index, // then this range will be split. - if (anIndex > range.location && anIndex < maximum) + if (anIndex > range.location) { // Split the range into shift and unshifted. shifted = CPMakeRange(anIndex + aDelta, maximum - anIndex); diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index c38778903..b244b8e1d 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -366,6 +366,13 @@ function descriptionWithoutEntity(aString) // negative delta for downward shift [_set shiftIndexesStartingAtIndex:1 by:-1]; [self assertTrue:[_set containsIndexes:[CPIndexSet indexSetWithIndexesInRange:startRange]]]; + + // test for fix to issue #746 (last item is mistakenly shifted) + _set = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, 1)]; + [self assertTrue:[_set lastIndex] === 0]; + + [_set shiftIndexesStartingAtIndex:[_set lastIndex] + 1 by:1]; + [self assertTrue:[_set lastIndex] === 0]; } - (void)tearDown From cea663f4eb56e3561eda31b3cbb8d96d120b2dab Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Wed, 28 Jul 2010 16:16:37 -0700 Subject: [PATCH 130/356] Fix for isEqual: not being implemented in CPIndexSet. Closes #785. Reviewed by rossco. --- Foundation/CPIndexSet.j | 7 +++++++ Tests/Foundation/CPIndexSetTest.j | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Foundation/CPIndexSet.j b/Foundation/CPIndexSet.j index 91855dc9b..bd3be224e 100644 --- a/Foundation/CPIndexSet.j +++ b/Foundation/CPIndexSet.j @@ -160,6 +160,13 @@ return YES; } +- (BOOL)isEqual:(id)anObject +{ + return self === anObject || + [anObject isKindOfClass:[self class]] && + [self isEqualToIndexSet:anObject]; +} + /*! Returns \c YES if the index set contains the specified index. @param anIndex the index to check for in the set diff --git a/Tests/Foundation/CPIndexSetTest.j b/Tests/Foundation/CPIndexSetTest.j index b244b8e1d..fed4726b9 100644 --- a/Tests/Foundation/CPIndexSetTest.j +++ b/Tests/Foundation/CPIndexSetTest.j @@ -252,12 +252,26 @@ function descriptionWithoutEntity(aString) var set1 = [CPIndexSet indexSetWithIndex:7]; var set2 = [CPIndexSet indexSetWithIndex:7]; var set3 = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(7, 2)]; - + + [self assertFalse:[set1 isEqualToIndexSet:nil]]; [self assertTrue:[set1 isEqualToIndexSet:set2]]; [self assertTrue:[set1 isEqualToIndexSet:set1]]; [self assertFalse:[set1 isEqualToIndexSet:set3]]; } +- (void)testIsEqual +{ + var set1 = [CPIndexSet indexSetWithIndex:7]; + var set2 = [CPIndexSet indexSetWithIndex:7]; + var set3 = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(7, 2)]; + + [self assertFalse:[set1 isEqual:nil]]; + [self assertFalse:[set1 isEqual:7]]; + [self assertTrue:[set1 isEqual:set2]]; + [self assertTrue:[set1 isEqual:set1]]; + [self assertFalse:[set1 isEqual:set3]]; +} + - (void)testCount { var set = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(7, 2)]; From fc51bead8ea90b7d8b6d9df615eff4191e6d38ec Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 26 Jul 2010 19:58:13 -0400 Subject: [PATCH 131/356] Another try at fixing issue #782 --- AppKit/CPImageView.j | 8 +++++++- AppKit/Resources/empty.png | Bin 0 -> 110 bytes 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 AppKit/Resources/empty.png diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index 017b59ad3..e8997a25e 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -71,6 +71,8 @@ var LEFT_SHADOW_INSET = 3.0, CGRect _imageRect; CPImageAlignment _imageAlignment; + + CPImage _emptyImage; } - (id)initWithFrame:(CGRect)aFrame @@ -95,6 +97,10 @@ var LEFT_SHADOW_INSET = 3.0, _DOMImageElement.style.visibility = "hidden"; #endif + + var bundle = [CPBundle bundleForClass:[CPView class]]; + + _emptyImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]]; } return self; @@ -131,7 +137,7 @@ var LEFT_SHADOW_INSET = 3.0, var newImage = [self objectValue]; #if PLATFORM(DOM) - _DOMImageElement.src = newImage ? [newImage filename] : ""; + _DOMImageElement.src = newImage ? [newImage filename] : [_emptyImage filename]; #endif var size = [newImage size]; diff --git a/AppKit/Resources/empty.png b/AppKit/Resources/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..f38e9f9100c290bd0e9a0419810c2d0149562c8e GIT binary patch literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}bl$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1G0-i38Ar-fhe*FJ$&+O2^$iVT3>EG=|zG6T*22WQ%mvv4F FO#p>79=iYl literal 0 HcmV?d00001 From 1002f80617edbedb2c91c45a6cce0f9fe475fe99 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 28 Jul 2010 18:45:55 -0400 Subject: [PATCH 132/356] Another fix for issue #782, uses class variable for the empty image placeholder. --- AppKit/CPImageView.j | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index e8997a25e..25189100d 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -45,7 +45,8 @@ CPImageAlignBottomLeft = 6; CPImageAlignBottomRight = 7; CPImageAlignRight = 8; -var CPImageViewShadowBackgroundColor = nil; +var CPImageViewShadowBackgroundColor = nil, + CPImageViewEmptyPlaceholderImage = nil; var LEFT_SHADOW_INSET = 3.0, RIGHT_SHADOW_INSET = 3.0, @@ -71,8 +72,13 @@ var LEFT_SHADOW_INSET = 3.0, CGRect _imageRect; CPImageAlignment _imageAlignment; +} + ++ (void)initialize +{ + var bundle = [CPBundle bundleForClass:[CPView class]]; - CPImage _emptyImage; + CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]]; } - (id)initWithFrame:(CGRect)aFrame @@ -97,10 +103,6 @@ var LEFT_SHADOW_INSET = 3.0, _DOMImageElement.style.visibility = "hidden"; #endif - - var bundle = [CPBundle bundleForClass:[CPView class]]; - - _emptyImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]]; } return self; @@ -137,7 +139,7 @@ var LEFT_SHADOW_INSET = 3.0, var newImage = [self objectValue]; #if PLATFORM(DOM) - _DOMImageElement.src = newImage ? [newImage filename] : [_emptyImage filename]; + _DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename]; #endif var size = [newImage size]; From 48a89fd8286be632312f8b9adba63e5e76c16a86 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 23 Jul 2010 16:28:10 -0400 Subject: [PATCH 133/356] frame parameter is not being used in _initWithFrame, might as well leave it out, fixed typo in comment --- AppKit/CPSearchField.j | 8 ++++---- Tools/nib2cib/NSSearchField.j | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 5597b6a6c..053ad3247 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -88,7 +88,7 @@ var RECENT_SEARCH_PREFIX = @" "; _sendsSearchStringImmediately = NO; _recentsAutosaveName = nil; - [self _initWithFrame:frame]; + [self _init]; #if PLATFORM(DOM) _cancelButton._DOMElement.style.cursor = "default"; _searchButton._DOMElement.style.cursor = "default"; @@ -98,7 +98,7 @@ var RECENT_SEARCH_PREFIX = @" "; return self; } -- (void)_initWithFrame:(CGRect)frame +- (void)_init { _recentSearches = [CPArray array]; @@ -479,7 +479,7 @@ var RECENT_SEARCH_PREFIX = @" "; if (_canResignFirstResponder) return [super resignFirstResponder]; - return _canResignFirstResponder; + return NO; } - (void)mouseDown:(CPEvent)anEvent @@ -801,7 +801,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey", { if (self = [super initWithCoder:coder]) { - [self _initWithFrame:[self frame]]; + [self _init]; _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey]; _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; diff --git a/Tools/nib2cib/NSSearchField.j b/Tools/nib2cib/NSSearchField.j index a68d5ede3..086d560d7 100644 --- a/Tools/nib2cib/NSSearchField.j +++ b/Tools/nib2cib/NSSearchField.j @@ -79,7 +79,7 @@ _maximumRecents = [aCoder decodeIntForKey:@"NSMaximumRecents"]; _sendsWholeSearchString = [aCoder decodeBoolForKey:@"NSSendsWholeSearchString"] ? YES : NO; - // These bytes don't seem to be used for anything else but the send immediatly flag + // These bytes don't seem to be used for anything else but the send immediately flag _sendsSearchStringImmediately = [aCoder decodeBytesForKey:@"NSSearchFieldFlags"] ? YES: NO; } From 9ca80df67ae95d30983b1eec8e80f3957348254d Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 26 Jul 2010 14:44:40 -0400 Subject: [PATCH 134/356] Cleaned up the state indicator (it was a little uneven) and centered it more horizontally in the state column. --- .../Resources/CPMenuItem/CPMenuItemOnState.png | Bin 177 -> 186 bytes .../CPMenuItem/CPMenuItemOnStateHighlighted.png | Bin 167 -> 181 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/AppKit/Resources/CPMenuItem/CPMenuItemOnState.png b/AppKit/Resources/CPMenuItem/CPMenuItemOnState.png index 7ea275e0724848ec35f6192dcea8f5d93d8a9f71..614ae28f1d2b85e2b837b0707746f1a20e1759a1 100644 GIT binary patch delta 158 zcmV;P0Ac^J0lEQ@B!3BTNLh0L01FcU01FcV0GgZ_0001NNkl70+K@Pwm2n0(H ze4TIjJDx#z6HSmFnh*~q870b!tVG1siMu1B<|jfCQDDF)%yk=!=2TE%fUadM*S$p3 zWiKK=;8}RwoPiEC#&(d~uN(z5f^+iAgt@MJ?!u)L$7lTfL>If`1H&g@y^;PDr~m)} M07*qoM6N<$f)U_8I{*Lx delta 149 zcmV;G0BZlb0kHv)B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0000} zNklZ~|NlP&IhbJxYlMPwAbtnLAc2`cEC>=Lq_G^T0U7TmM&mmy8bR2YkjDQw zunQrLGqGs8ON>(mp?*TvWK4`k7yv1DK^7RIDF*;bT-C6KnGQ8500000NkvXXu0mjf DD84n( diff --git a/AppKit/Resources/CPMenuItem/CPMenuItemOnStateHighlighted.png b/AppKit/Resources/CPMenuItem/CPMenuItemOnStateHighlighted.png index 78f90eddb5d2f68091aa41ba99e6095970241256..f1a9c8360f9ce5b6d044c60441436873d273bdb1 100644 GIT binary patch delta 153 zcmV;K0A~NE0kr{;B!3BTNLh0L01FcU01FcV0GgZ_0001INkl70+Q3}8y3`2Dv zUfpZ#b{?ba1Fc&b2*nQrffx;@%_5Q_xFR7k=LCzksmj)g#+zU{KdkC`;MrRfZ&P*i zsqWeP?aR66Fs8nqt2n9@^_hvv5REtPQ|1uC_8FHY!aqK|rV^EP`unG900000NkvXX Hu0mjf{Bl4T delta 139 zcmV;60CfMg0jB|wB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0000< zNklZ~|NlP&IhbMSYb*!icmE+^CJ+k}qp|!yCfH4k#&`d*17kuOaRC=X8fRkB tbe9;X3PSyatjU;^=rBfi-VjYW0A Date: Thu, 29 Jul 2010 11:26:13 -0700 Subject: [PATCH 135/356] Better method of expressing this condition. --- AppKit/CPSearchField.j | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 053ad3247..66260ecf7 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -476,10 +476,7 @@ var RECENT_SEARCH_PREFIX = @" "; - (BOOL)resignFirstResponder { - if (_canResignFirstResponder) - return [super resignFirstResponder]; - - return NO; + return _canResignFirstResponder && [super resignFirstResponder]; } - (void)mouseDown:(CPEvent)anEvent From 3eea14abe48e835ff59cc99bc04837e951279ae5 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sun, 25 Jul 2010 16:55:55 -0400 Subject: [PATCH 136/356] For the methods that don't have context: in their signature, the predicate will receive undefined in the context parameter instead of nil. --- Foundation/CPArray.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 654eacb99..54081fdf0 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -411,7 +411,7 @@ CPEnumerationReverse = 1 << 1; */ - (unsigned)indexOfObjectPassingTest:(Function)predicate { - return [self indexOfObjectWithOptions:CPEnumerationNormal passingTest:predicate context:nil]; + return [self indexOfObjectWithOptions:CPEnumerationNormal passingTest:predicate context:undefined]; } /*! @@ -443,7 +443,7 @@ CPEnumerationReverse = 1 << 1; */ - (unsigned)indexOfObjectWithOptions:(CPEnumerationOptions)opts passingTest:(Function)predicate { - return [self indexOfObjectWithOptions:opts passingTest:predicate context:nil]; + return [self indexOfObjectWithOptions:opts passingTest:predicate context:undefined]; } /*! From 0e5b5c844c6d1f5b49257ef805dfad62c8ebffd8 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 18:44:59 -0400 Subject: [PATCH 137/356] Split view cursor improvements. If a split view divider is at its minimum position but a collapse is possible, show that a smaller size is possible through the cursor. If a split view has a collapsed view and the cursor moves over the divider, show a 'larger size is possible' cursor. --- AppKit/CPSplitView.j | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 4a90dcf99..e650774ae 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -293,7 +293,7 @@ var CPSplitViewHorizontalImage = nil, if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)]) additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex]; - return CGRectContainsPoint(effectiveRect, aPoint) || + return CGRectContainsPoint(effectiveRect, aPoint) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint)) || (buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint)); } @@ -444,11 +444,19 @@ var CPSplitViewHorizontalImage = nil, if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i])) { var frame = [_subviews[i] frame], - startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent], + size = frame.size[_sizeComponent], + startPosition = frame.origin[_originComponent] + size, canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition, canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition, cursor = [CPCursor arrowCursor]; + if (size === 0) + canGrow = YES; // Subview is collapsed. + else if (!canShrink && + [_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] && + [_delegate splitView:self canCollapseSubview:_subviews[i]]) + canShrink = YES; // Subview is collapsible. + if (_isVertical && canShrink && canGrow) cursor = [CPCursor resizeLeftRightCursor]; else if (_isVertical && canShrink) @@ -641,14 +649,14 @@ var CPSplitViewHorizontalImage = nil, /*! Set the button bar who's resize control should act as a control for this splitview. - Each divider can have at most one button bar assigned to it, and that button bar must be + Each divider can have at most one button bar assigned to it, and that button bar must be a subview of one of the split view's subviews. Calling this method with nil as the button bar will remove any currently assigned button bar for the divider at that index. Indexes will not be adjusted as new subviews are added, so you should usually call this method after adding all the desired subviews to the split view. - This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned + This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned parameters of the button bar, and will override any currently set values. */ - (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex @@ -669,7 +677,7 @@ var CPSplitViewHorizontalImage = nil, } if (view !== self) - [CPException raise:CPInvalidArgumentException + [CPException raise:CPInvalidArgumentException reason:@"CPSplitView button bar must be a subview of the split view."]; var viewIndex = [[self subviews] indexOfObject:subview]; @@ -677,7 +685,7 @@ var CPSplitViewHorizontalImage = nil, [aButtonBar setHasResizeControl:YES]; [aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex]; - _buttonBars[dividerIndex] = aButtonBar; + _buttonBars[dividerIndex] = aButtonBar; } - (void)_postNotificationWillResize @@ -714,7 +722,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey", _DOMDividerElements = []; _buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || []; - + _delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey]; _isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey]; From d1c7dab356edc852643c25e5773caf0a51510add Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 18:59:37 -0400 Subject: [PATCH 138/356] If a CPSplitView view is collapsed through means of double click and then later restored in the same manner, preserve the original position of the divider. If the view was collapsed through dragging, double clicking to expand still positions the divider in the center of its available space. --- AppKit/CPSplitView.j | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index e650774ae..c8df4e707 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -47,6 +47,7 @@ var CPSplitViewHorizontalImage = nil, int _currentDivider; float _initialOffset; + float _preCollapsePosition; CPString _originComponent; CPString _sizeComponent; @@ -358,14 +359,14 @@ var CPSplitViewHorizontalImage = nil, if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i]) { if ([self isSubviewCollapsed:_subviews[i]]) - [self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; + [self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; else [self setPosition:minPosition ofDividerAtIndex:i]; } else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i]) { if ([self isSubviewCollapsed:_subviews[i+1]]) - [self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; + [self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; else [self setPosition:maxPosition ofDividerAtIndex:i]; } @@ -539,10 +540,18 @@ var CPSplitViewHorizontalImage = nil, viewB = _subviews[dividerIndex + 1], frameB = [viewB frame]; + _preCollapsePosition = 0; + + var preSize = frameA.size[_sizeComponent]; frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent]; + if (preSize !== 0 && frameA.size[_sizeComponent] === 0) + _preCollapsePosition = preSize; [_subviews[dividerIndex] setFrame:frameA]; + preSize = frameB.size[_sizeComponent]; frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness]; + if (preSize !== 0 && frameB.size[_sizeComponent] === 0) + _preCollapsePosition = preSize; frameB.origin[_originComponent] = realPosition + [self dividerThickness]; [_subviews[dividerIndex + 1] setFrame:frameB]; From dcfb916d30721beb86f20b1e5d7a5aada1e8f0d5 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 30 Jul 2010 15:56:20 -0400 Subject: [PATCH 139/356] Fix for issue #803 (jake docs doesn't use Doxygen.app on Mac OS X) --- Jakefile | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/Jakefile b/Jakefile index d90e5989b..9c7c523ce 100644 --- a/Jakefile +++ b/Jakefile @@ -4,6 +4,7 @@ require("./common.jake"); var FILE = require("file"), SYSTEM = require("system"), OS = require("os"), + UTIL = require("util"), jake = require("jake"), stream = require("term").stream; @@ -89,12 +90,42 @@ task ("docs", ["documentation"]); task ("documentation", function() { - if (executableExists("doxygen")) + var doxygen = null, + DoxygenAppPath = "/Applications/Doxygen.app/Contents/Resources"; + + // If the Doxygen application is installed on Mac OS X, use that + if (executableExists("mdfind")) { + OS.system("mdfind \"kMDItemContentType == 'com.apple.application-bundle' && kMDItemCFBundleIdentifier == 'org.doxygen'\" > doxygen_app"); + + if (FILE.exists("doxygen_app")) + { + doxygen = FILE.join(UTIL.trimEnd(FILE.read("doxygen_app")), "Contents/Resources/doxygen"); + FILE.remove("doxygen_app"); + } + } + else + { + SYSTEM.env["PATH"].split(':').some(function(/*String*/ aPath) + { + var path = FILE.join(aPath, "doxygen"); + + if (FILE.exists(path)) + { + doxygen = path; + return true; + } + }); + } + + if (doxygen) + { + print("Using " + doxygen + " for doxygen binary."); + if (OS.system(["ruby", FILE.join("Tools", "Documentation", "make_headers")])) OS.exit(1); //rake abort if ($? != 0) - if (OS.system(["doxygen", FILE.join("Tools", "Documentation", "Cappuccino.doxygen")])) + if (OS.system([doxygen, FILE.join("Tools", "Documentation", "Cappuccino.doxygen")])) OS.exit(1); //rake abort if ($? != 0) rm_rf($DOCUMENTATION_BUILD); @@ -102,7 +133,7 @@ task ("documentation", function() mv("Documentation", $DOCUMENTATION_BUILD); } else - print("doxygen not installed. skipping documentation generation."); + print("doxygen not installed, skipping documentation generation."); }); // Downloads From 0a26288d88c576cce57cdc6115c17d3ee3c04cd1 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 30 Jul 2010 16:29:58 -0400 Subject: [PATCH 140/356] Fix for issue #804 (doxygen fails to generate class references), also did a bit of formatting cleanup in CPColor.j --- AppKit/CPColor.j | 127 ++++++++++++++--------------- AppKit/Cib/CPCibControlConnector.j | 12 ++- 2 files changed, 70 insertions(+), 69 deletions(-) diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index 3203257bf..0be27ab44 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -56,18 +56,12 @@ var cachedBlackColor, /*! @ingroup appkit - @code CPColor \c CPColor can be used to represent color in an RGB or HSB model with an optional transparency value.

It also provides some class helper methods that returns instances of commonly used colors.

- -

The class does not have a \c -set: method - like NextStep based frameworks to change the color of - the current context. To change the color of the current - context, use CGContextSetFillColor(). */ @implementation CPColor : CPObject { @@ -82,12 +76,12 @@ var cachedBlackColor, Each component should be between the range of 0.0 to 1.0. For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent. - + @param red the red component of the color @param green the green component of the color @param blue the blue component of the color @param alpha the alpha component - + @return a color initialized to the values specified */ + (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha @@ -97,17 +91,17 @@ var cachedBlackColor, /*! @deprecated in favor of colorWithRed:green:blue:alpha: - + Creates a color in the RGB color space, with an alpha value. Each component should be between the range of 0.0 to 1.0. For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent. - + @param red the red component of the color @param green the green component of the color @param blue the blue component of the color @param alpha the alpha component - + @return a color initialized to the values specified */ + (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha @@ -119,10 +113,10 @@ var cachedBlackColor, /*! Creates a new color object with \c white for the RGB components. For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent. - + @param white a float between 0.0 and 1.0 @param alpha the alpha component between 0.0 and 1.0 - + @return a color initialized to the values specified */ + (CPColor)colorWithWhite:(float)white alpha:(float)alpha @@ -132,13 +126,13 @@ var cachedBlackColor, /*! @deprecated in favor of colorWithWhite:apha: - + Creates a new color object with \c white for the RGB components. For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent. - + @param white a float between 0.0 and 1.0 @param alpha the alpha component between 0.0 and 1.0 - + @return a color initialized to the values specified */ + (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha @@ -148,11 +142,11 @@ var cachedBlackColor, /*! Creates a new color in HSB space. - + @param hue the hue value @param saturation the saturation value @param brightness the brightness value - + @return the initialized color */ + (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness @@ -162,16 +156,16 @@ var cachedBlackColor, + (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha { - if(saturation === 0.0) + if (saturation === 0.0) return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha]; - + var f = hue % 60, p = (brightness * (100 - saturation)) / 10000, q = (brightness * (6000 - saturation * f)) / 600000, t = (brightness * (6000 - saturation * (60 -f))) / 600000, b = brightness / 100.0; - - switch(FLOOR(hue / 60)) + + switch (FLOOR(hue / 60)) { case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha]; case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha]; @@ -397,7 +391,7 @@ var cachedBlackColor, /*! Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)". - + @param aString a CSS color string @return a color initialized to the value in the css string */ @@ -409,23 +403,23 @@ var cachedBlackColor, /* @ignore */ - (id)_initWithCSSString:(CPString)aString { - if(aString.indexOf("rgb") == CPNotFound) + if (aString.indexOf("rgb") == CPNotFound) return nil; - + self = [super init]; - + var startingIndex = aString.indexOf("("); var parts = aString.substring(startingIndex+1).split(','); - + _components = [ parseInt(parts[0], 10) / 255.0, parseInt(parts[1], 10) / 255.0, parseInt(parts[2], 10) / 255.0, parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0 ]; - + _cssString = aString; - + return self; } @@ -433,7 +427,7 @@ var cachedBlackColor, - (id)_initWithRGBA:(CPArray)components { self = [super init]; - + if (self) { _components = components; @@ -454,14 +448,14 @@ var cachedBlackColor, - (id)_initWithPatternImage:(CPImage)anImage { self = [super init]; - + if (self) { _patternImage = anImage; _cssString = "url(\"" + [_patternImage filename] + "\")"; _components = [0.0, 0.0, 0.0, 1.0]; } - + return self; } @@ -523,17 +517,17 @@ var cachedBlackColor, /*! Returns a new color with the same RGB as the receiver but a new alpha component. - + @param anAlphaComponent the alpha component for the new color - + @return a new color object */ - (CPColor)colorWithAlphaComponent:(float)anAlphaComponent { var components = _components.slice(); - + components[components.length - 1] = anAlphaComponent; - + return [[[self class] alloc] _initWithRGBA:components]; } @@ -552,35 +546,38 @@ var cachedBlackColor, var red = ROUND(_components[_redComponent] * 255.0), green = ROUND(_components[_greenComponent] * 255.0), blue = ROUND(_components[_blueComponent] * 255.0); - + var max = MAX(red, green, blue), min = MIN(red, green, blue), delta = max - min; - + var brightness = max / 255.0, saturation = (max != 0) ? delta / max : 0; - + var hue; - if(saturation == 0) + + if (saturation == 0) + { hue = 0; + } else { var rr = (max - red) / delta; var gr = (max - green) / delta; var br = (max - blue) / delta; - + if (red == max) hue = br - gr; else if (green == max) hue = 2 + rr - br; else hue = 4 + gr - rr; - + hue /= 6; if (hue < 0) hue++; } - + return [ ROUND(hue * 360.0), ROUND(saturation * 100.0), @@ -699,10 +696,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey", @end -var hexCharacters = "0123456789ABCDEF"; -// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior -var hexToRGB, rgbToHex, byteToHex; +var hexCharacters = "0123456789ABCDEF"; /*! Used for the CPColor \c +colorWithHexString: implementation @@ -710,39 +705,39 @@ var hexToRGB, rgbToHex, byteToHex; @class CPColor @return an array of rgb components */ -function hexToRGB(hex) +var hexToRGB = function(hex) { - if ( hex.length == 3 ) + if (hex.length == 3) hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2); - if(hex.length != 6) + + if (hex.length != 6) return null; hex = hex.toUpperCase(); - for(var i=0; i Date: Wed, 28 Jul 2010 17:51:05 -0400 Subject: [PATCH 141/356] Full support for intercell spacing (issue #797) --- AppKit/CPTableView.j | 63 ++++++++++++++++++++----------------- Tools/nib2cib/NSTableView.j | 15 ++++----- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index cda709b43..652831c90 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -261,7 +261,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _dirtyTableColumnRangeIndex = CPNotFound; _numberOfHiddenColumns = 0; - _intercellSpacing = _CGSizeMake(0.0, 0.0); + _intercellSpacing = _CGSizeMake(3.0, 2.0); _rowHeight = 23.0; [self setGridColor:[CPColor colorWithHexString:@"dce0e2"]]; @@ -543,6 +543,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return; _intercellSpacing = _CGSizeMakeCopy(aSize); + + _dirtyTableColumnRangeIndex = 0; // so that _recalculateTableColumnRanges will work + [self _recalculateTableColumnRanges]; [self setNeedsLayout]; } @@ -1251,7 +1254,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else { - var width = [_tableColumns[index] width]; + var width = [_tableColumns[index] width] + _intercellSpacing.width; _tableColumnRanges[index] = CPMakeRange(x, width); @@ -1283,11 +1286,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (CGRect)rectOfRow:(CPInteger)aRowIndex { - if (NO) - return NULL; + var height = _rowHeight + _intercellSpacing.height; - // FIXME: WRONG: ASK TABLE COLUMN RANGE - return _CGRectMake(0.0, (aRowIndex * (_rowHeight + _intercellSpacing.height)), _CGRectGetWidth([self bounds]), _rowHeight); + return _CGRectMake(0.0, aRowIndex * height, _CGRectGetWidth([self bounds]), height); } // Complexity: @@ -1404,9 +1405,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (CPInteger)rowAtPoint:(CGPoint)aPoint { - var y = aPoint.y; - - var row = FLOOR(y / (_rowHeight + _intercellSpacing.height)); + var y = aPoint.y, + row = FLOOR(y / (_rowHeight + _intercellSpacing.height)); if (row >= _numberOfRows) return -1; @@ -1419,9 +1419,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; UPDATE_COLUMN_RANGES_IF_NECESSARY(); var tableColumnRange = _tableColumnRanges[aColumn], - rectOfRow = [self rectOfRow:aRow]; - - return _CGRectMake(tableColumnRange.location, _CGRectGetMinY(rectOfRow), tableColumnRange.length, _CGRectGetHeight(rectOfRow)); + rectOfRow = [self rectOfRow:aRow], + leftInset = FLOOR(_intercellSpacing.width / 2.0), + topInset = FLOOR(_intercellSpacing.height / 2.0); + + return _CGRectMake(tableColumnRange.location + leftInset, + _CGRectGetMinY(rectOfRow) + topInset, + tableColumnRange.length - _intercellSpacing.width, + _CGRectGetHeight(rectOfRow) - _intercellSpacing.height); } - (void)resizeWithOldSuperviewSize:(CGSize)aSize @@ -1908,11 +1913,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [newSortDescriptors insertObject:newMainSortDescriptor atIndex:0]; // Update indicator image & highlighted column before - var image = [newMainSortDescriptor ascending] ? [self _tableHeaderSortImage] : [self _tableHeaderReverseSortImage]; + var image = [newMainSortDescriptor ascending] ? [self _tableHeaderSortImage] : [self _tableHeaderReverseSortImage]; [self setIndicatorImage:nil inTableColumn:_currentHighlightedTableColumn]; - [self setIndicatorImage:image inTableColumn:tableColumn]; - [self setHighlightedTableColumn:tableColumn]; + [self setIndicatorImage:image inTableColumn:tableColumn]; + [self setHighlightedTableColumn:tableColumn]; [self setSortDescriptors:newSortDescriptors]; } @@ -2139,7 +2144,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _sortDescriptors = newSortDescriptors; - [self _sendDataSourceSortDescriptorsDidChange:oldSortDescriptors]; + [self _sendDataSourceSortDescriptorsDidChange:oldSortDescriptors]; } - (CPArray)sortDescriptors @@ -3094,11 +3099,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // If there is no (the default) or to little inter cell spacing we create some room for the CPTableViewDropAbove indicator // This probably doesn't work if the row height is smaller than or around 5.0 if ([self intercellSpacing].height < 5.0) - rowRect = CPRectInset(rowRect, 0.0, 5.0 - [self intercellSpacing].height); + rowRect = CPRectInset(rowRect, 0.0, 5.0 - [self intercellSpacing].height); - // If the altered row rect contains the drag point we show the drop on - // We don't show the drop on indicator if we are dragging below the last row - // in that case we always want to show the drop above indicator + // If the altered row rect contains the drag point we show the drop on + // We don't show the drop on indicator if we are dragging below the last row + // in that case we always want to show the drop above indicator if (CGRectContainsPoint(rowRect, theDragPoint) && row < _numberOfRows) return CPTableViewDropOn; @@ -3110,23 +3115,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPInteger)_proposedRowAtPoint:(CGPoint)dragPoint { - // We don't use rowAtPoint here because the drag indicator can appear below the last row - // and rowAtPoint doesn't return rows that are larger than numberOfRows + // We don't use rowAtPoint here because the drag indicator can appear below the last row + // and rowAtPoint doesn't return rows that are larger than numberOfRows // FIX ME: this is going to break when we implement variable row heights... - var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )), - // Determine if the mouse is currently closer to this row or the row below it + var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )), + // Determine if the mouse is currently closer to this row or the row below it lowerRow = row + 1, - rect = [self rectOfRow:row], + rect = [self rectOfRow:row], bottomPoint = CGRectGetMaxY(rect), bottomThirty = bottomPoint - ((bottomPoint - CGRectGetMinY(rect)) * 0.3); if (dragPoint.y > MAX(bottomThirty, bottomPoint - 6)) - row = lowerRow; + row = lowerRow; if (row >= [self numberOfRows]) row = [self numberOfRows]; - return row; + return row; } - (void)_validateDrop:(id)info proposedRow:(CPInteger)row proposedDropOperation:(CPTableViewDropOperation)dropOperation @@ -3150,7 +3155,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (theLowerRowIndex > [self numberOfRows]) theLowerRowIndex = [self numberOfRows]; - return [self rectOfRow:theLowerRowIndex]; + return [self rectOfRow:theLowerRowIndex]; } - (CPDragOperation)draggingUpdated:(id)sender @@ -3539,7 +3544,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", else _rowHeight = 23.0; - _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(0.0, 0.0); + _intercellSpacing = [aCoder decodeSizeForKey:CPTableViewIntercellSpacingKey] || _CGSizeMake(3.0, 2.0); [self setGridColor:[aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; diff --git a/Tools/nib2cib/NSTableView.j b/Tools/nib2cib/NSTableView.j index f185ce817..49540479e 100644 --- a/Tools/nib2cib/NSTableView.j +++ b/Tools/nib2cib/NSTableView.j @@ -41,9 +41,6 @@ // Convert xib default to cib default if (_rowHeight == 17) _rowHeight = 23; - - if ([_gridColor isEqual:[CPColor colorWithRed:127.0 / 255.0 green:127.0 / 255.0 blue:127.0 / 255.0 alpha:1.0]]) - _gridColor = [CPColor colorWithRed:229.0 / 255.0 green:229.0 / 255.0 blue:229.0 / 255.0 alpha:1.0]; _headerView = [aCoder decodeObjectForKey:@"NSHeaderView"]; _cornerView = [aCoder decodeObjectForKey:@"NSCornerView"]; @@ -51,13 +48,13 @@ _tableColumns = [aCoder decodeObjectForKey:@"NSTableColumns"]; [_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self]; - _intercellSpacing = CGSizeMake(0.0, 0.0);//CGSizeMake([aCoder decodeFloatForKey:"NSIntercellSpacingWidth"], [aCoder decodeFloatForKey:"NSIntercellSpacingHeight"]); + _intercellSpacing = CGSizeMake([aCoder decodeFloatForKey:@"NSIntercellSpacingWidth"], + [aCoder decodeFloatForKey:@"NSIntercellSpacingHeight"]); - _gridColor = [aCoder decodeObjectForKey:@"NSGridColor"]; - - // Convert xib default to cib default - if ([_gridColor isEqual:[CPColor colorWithRed:127.0 / 255.0 green:127.0 / 255.0 blue:127.0 / 255.0 alpha:1.0]]) - _gridColor = [CPColor colorWithRed:229.0 / 255.0 green:229.0 / 255.0 blue:229.0 / 255.0 alpha:1.0]; + var gridColor = [aCoder decodeObjectForKey:@"NSGridColor"]; + + if (![gridColor isEqual:[CPColor colorWithRed:127.0 / 255.0 green:127.0 / 255.0 blue:127.0 / 255.0 alpha:1.0]]) + [self setValue:gridColor forThemeAttribute:@"grid-color"]; _gridStyleMask = [aCoder decodeIntForKey:@"NSGridStyleMask"]; From 9fc07ac6223f727c3526552180ef5bd3231bbb1f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 27 Jun 2010 01:56:17 -0400 Subject: [PATCH 142/356] Implemented NSView viewDidHide and viewDidUnhide. --- AppKit/CPView.j | 412 +++++++++++++++++++++++++++--------------------- 1 file changed, 232 insertions(+), 180 deletions(-) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 7b1c193d6..8066cafe5 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -90,7 +90,7 @@ var CachedNotificationCenter = nil, #if PLATFORM(DOM) var DOMElementPrototype = nil, - + BackgroundTrivialColor = 0, BackgroundVerticalThreePartImage = 1, BackgroundHorizontalThreePartImage = 2, @@ -102,7 +102,7 @@ var CPViewFlags = { }, CPViewHasCustomDrawRect = 1 << 0, CPViewHasCustomLayoutSubviews = 1 << 1; -/*! +/*! @ingroup appkit @class CPView @@ -122,37 +122,37 @@ var CPViewFlags = { }, @implementation CPView : CPResponder { CPWindow _window; - + CPView _superview; CPArray _subviews; - + CPGraphicsContext _graphicsContext; - + int _tag; - + CGRect _frame; CGRect _bounds; CGAffineTransform _boundsTransform; CGAffineTransform _inverseBoundsTransform; - + CPSet _registeredDraggedTypes; CPArray _registeredDraggedTypesArray; - + BOOL _isHidden; BOOL _hitTests; BOOL _clipsToBounds; - + BOOL _postsFrameChangedNotifications; BOOL _postsBoundsChangedNotifications; BOOL _inhibitFrameAndBoundsChangedNotifications; - + #if PLATFORM(DOM) DOMElement _DOMElement; DOMElement _DOMContentsElement; - + CPArray _DOMImageParts; CPArray _DOMImageSizes; - + unsigned _backgroundType; #endif @@ -163,19 +163,19 @@ var CPViewFlags = { }, BOOL _autoresizesSubviews; unsigned _autoresizingMask; - + CALayer _layer; BOOL _wantsLayer; - + // Full Screen State BOOL _isInFullScreenMode; - + _CPViewFullScreenModeState _fullScreenModeState; - + // Layout Support BOOL _needsLayout; JSObject _ephemeralSubviews; - + // Theming Support CPTheme _theme; JSObject _themeAttributes; @@ -202,9 +202,9 @@ var CPViewFlags = { }, #if PLATFORM(DOM) DOMElementPrototype = document.createElement("div"); - + var style = DOMElementPrototype.style; - + style.overflow = "hidden"; style.position = "absolute"; style.visibility = "visible"; @@ -262,12 +262,12 @@ var CPViewFlags = { }, - (id)initWithFrame:(CGRect)aFrame { self = [super init]; - + if (self) { var width = _CGRectGetWidth(aFrame), height = _CGRectGetHeight(aFrame); - + _subviews = []; _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; @@ -280,7 +280,7 @@ var CPViewFlags = { }, _autoresizingMask = CPViewNotSizable; _autoresizesSubviews = YES; _clipsToBounds = YES; - + _opacity = 1.0; _isHidden = NO; _hitTests = YES; @@ -290,11 +290,11 @@ var CPViewFlags = { }, CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(aFrame), _CGRectGetMinY(aFrame)); CPDOMDisplayServerSetStyleSize(_DOMElement, width, height); - + _DOMImageParts = []; _DOMImageSizes = []; #endif - + _theme = [CPTheme defaultTheme]; _themeState = CPThemeStateNormal; @@ -302,7 +302,7 @@ var CPViewFlags = { }, [self _loadThemeAttributes]; } - + return self; } @@ -350,15 +350,15 @@ var CPViewFlags = { }, - (void)addSubview:(CPView)aSubview positioned:(CPWindowOrderingMode)anOrderingMode relativeTo:(CPView)anotherView { var index = anotherView ? [_subviews indexOfObjectIdenticalTo:anotherView] : CPNotFound; - + // In other words, if no view, then either all the way at the bottom or all the way at the top. if (index === CPNotFound) index = (anOrderingMode === CPWindowAbove) ? [_subviews count] : 0; - + // else, if we have a view, above if above. else if (anOrderingMode === CPWindowAbove) ++index; - + [self _insertSubview:aSubview atIndex:index]; } @@ -375,20 +375,20 @@ var CPViewFlags = { }, if (aSubview._superview == self) { var index = [_subviews indexOfObjectIdenticalTo:aSubview]; - + // FIXME: should this be anIndex >= count? (last one) if (index === anIndex || index === count - 1 && anIndex === count) return; - + [_subviews removeObjectAtIndex:index]; - + #if PLATFORM(DOM) CPDOMDisplayServerRemoveChild(_DOMElement, aSubview._DOMElement); #endif if (anIndex > index) --anIndex; - + //We've effectively made the subviews array shorter, so represent that. --count; } @@ -397,16 +397,16 @@ var CPViewFlags = { }, // Remove the view from its previous superview. [aSubview removeFromSuperview]; - // Set the subview's window to our own. + // Set the subview's window to our own. [aSubview _setWindow:_window]; // Notify the subview that it will be moving. [aSubview viewWillMoveToSuperview:self]; - + // Set ourselves as the superview. aSubview._superview = self; } - + if (anIndex === CPNotFound || anIndex >= count) { _subviews.push(aSubview); @@ -419,16 +419,16 @@ var CPViewFlags = { }, else { _subviews.splice(anIndex, 0, aSubview); - + #if PLATFORM(DOM) // Attach the actual node. CPDOMDisplayServerInsertBefore(_DOMElement, aSubview._DOMElement, _subviews[anIndex + 1]._DOMElement); #endif } - + [aSubview setNextResponder:self]; [aSubview viewDidMoveToSuperview]; - + [self didAddSubview:aSubview]; } @@ -453,14 +453,14 @@ var CPViewFlags = { }, [[self window] _dirtyKeyViewLoop]; [_superview willRemoveSubview:self]; - + [_superview._subviews removeObject:self]; #if PLATFORM(DOM) CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement); #endif _superview = nil; - + [self _setWindow:nil]; } @@ -473,11 +473,11 @@ var CPViewFlags = { }, { if (aSubview._superview != self) return; - + var index = [_subviews indexOfObjectIdenticalTo:aSubview]; - + [aSubview removeFromSuperview]; - + [self _insertSubview:aView atIndex:index]; } @@ -555,7 +555,7 @@ var CPViewFlags = { }, { if (_window === aWindow) return; - + [[self window] _dirtyKeyViewLoop]; // Clear out first responder if we're the first responder and leaving. @@ -579,7 +579,7 @@ var CPViewFlags = { }, while (count--) [_subviews[count] _setWindow:aWindow]; - + [self viewDidMoveToWindow]; [[self window] _dirtyKeyViewLoop]; @@ -592,13 +592,13 @@ var CPViewFlags = { }, - (BOOL)isDescendantOf:(CPView)aView { var view = self; - + do { if (view == aView) return YES; } while(view = [view superview]) - + return NO; } @@ -649,20 +649,20 @@ var CPViewFlags = { }, - (CPMenuItem)enclosingMenuItem { var view = self; - + while (view && ![view isKindOfClass:[_CPMenuItemView class]]) view = [view superview]; - + if (view) return view._menuItem; - + return nil; /* var view = self, enclosingMenuItem = _enclosingMenuItem; - + while (!enclosingMenuItem && (view = view._enclosingMenuItem)) view = [view superview]; - + return enclosingMenuItem;*/ } @@ -715,9 +715,9 @@ var CPViewFlags = { }, { if (_CGRectEqualToRect(_frame, aFrame)) return; - + _inhibitFrameAndBoundsChangedNotifications = YES; - + [self setFrameOrigin:aFrame.origin]; [self setFrameSize:aFrame.size]; @@ -747,19 +747,19 @@ var CPViewFlags = { }, } /*! - Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. - The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver - is configured to do so. If the specified origin is the same as the frame's current origin, the method will + Moves the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. + The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver + is configured to do so. If the specified origin is the same as the frame's current origin, the method will simply return (and no notification will be posted). @param aPoint the new origin point */ - (void)setCenter:(CGPoint)aPoint { - [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)]; + [self setFrameOrigin:CGPointMake(aPoint.x - _frame.size.width / 2.0, aPoint.y - _frame.size.height / 2.0)]; } /*! - Returns the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. + Returns the center of the receiver's frame to the provided point. The point is defined in the superview's coordinate system. @return CGPoint the center point of the receiver's frame */ - (CGPoint)center @@ -768,16 +768,16 @@ var CPViewFlags = { }, } /*! - Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system. - The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver - is configured to do so. If the specified origin is the same as the frame's current origin, the method will + Sets the receiver's frame origin to the provided point. The point is defined in the superview's coordinate system. + The method posts a CPViewFrameDidChangeNotification to the default notification center if the receiver + is configured to do so. If the specified origin is the same as the frame's current origin, the method will simply return (and no notification will be posted). @param aPoint the new origin point */ - (void)setFrameOrigin:(CGPoint)aPoint { var origin = _frame.origin; - + if (!aPoint || _CGPointEqualToPoint(origin, aPoint)) return; @@ -803,7 +803,7 @@ var CPViewFlags = { }, - (void)setFrameSize:(CGSize)aSize { var size = _frame.size; - + if (!aSize || _CGSizeEqualToSize(size, aSize)) return; @@ -823,7 +823,7 @@ var CPViewFlags = { }, if (_autoresizesSubviews) [self resizeSubviewsWithOldSize:oldSize]; - + [self setNeedsLayout]; [self setNeedsDisplay:YES]; @@ -874,7 +874,7 @@ var CPViewFlags = { }, } /*! - Sets the receiver's bounds. The bounds define the size and location of the receiver inside it's frame. Posts a + Sets the receiver's bounds. The bounds define the size and location of the receiver inside it's frame. Posts a CPViewBoundsDidChangeNotification to the default notification center if the receiver is configured to do so. @param bounds the new bounds */ @@ -882,9 +882,9 @@ var CPViewFlags = { }, { if (_CGRectEqualToRect(_bounds, bounds)) return; - + _inhibitFrameAndBoundsChangedNotifications = YES; - + [self setBoundsOrigin:bounds.origin]; [self setBoundsSize:bounds.size]; @@ -922,13 +922,13 @@ var CPViewFlags = { }, - (void)setBoundsOrigin:(CGPoint)aPoint { var origin = _bounds.origin; - + if (_CGPointEqualToPoint(origin, aPoint)) return; - + origin.x = aPoint.x; origin.y = aPoint.y; - + if (origin.x != 0 || origin.y != 0) { _boundsTransform = _CGAffineTransformMakeTranslation(-origin.x, -origin.y); @@ -939,19 +939,19 @@ var CPViewFlags = { }, _boundsTransform = nil; _inverseBoundsTransform = nil; } - + #if PLATFORM(DOM) var index = _subviews.length; - + while (index--) { var view = _subviews[index], origin = view._frame.origin; - + CPDOMDisplayServerSetStyleLeftTop(view._DOMElement, _boundsTransform, origin.x, origin.y); } #endif - + if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; } @@ -965,7 +965,7 @@ var CPViewFlags = { }, - (void)setBoundsSize:(CGSize)aSize { var size = _bounds.size; - + if (_CGSizeEqualToSize(size, aSize)) return; @@ -974,22 +974,22 @@ var CPViewFlags = { }, if (!_CGSizeEqualToSize(size, frameSize)) { var origin = _bounds.origin; - + origin.x /= size.width / frameSize.width; origin.y /= size.height / frameSize.height; } - + size.width = aSize.width; size.height = aSize.height; - + if (!_CGSizeEqualToSize(size, frameSize)) { var origin = _bounds.origin; - + origin.x *= size.width / frameSize.width; origin.y *= size.height / frameSize.height; } - + if (_postsBoundsChangedNotifications && !_inhibitFrameAndBoundsChangedNotifications) [CachedNotificationCenter postNotificationName:CPViewBoundsDidChangeNotification object:self]; } @@ -1002,7 +1002,7 @@ var CPViewFlags = { }, - (void)resizeWithOldSuperviewSize:(CGSize)aSize { var mask = [self autoresizingMask]; - + if(mask == CPViewNotSizable) return; @@ -1017,7 +1017,7 @@ var CPViewFlags = { }, newFrame.origin.x += dX; if (mask & CPViewWidthSizable) newFrame.size.width += dX; - + if (mask & CPViewMinYMargin) newFrame.origin.y += dY; if (mask & CPViewHeightSizable) @@ -1033,7 +1033,7 @@ var CPViewFlags = { }, - (void)resizeSubviewsWithOldSize:(CGSize)aSize { var count = _subviews.length; - + while (count--) [_subviews[count] resizeWithOldSuperviewSize:aSize]; } @@ -1094,14 +1094,14 @@ var CPViewFlags = { }, - (BOOL)enterFullScreenMode:(CPScreen)aScreen withOptions:(CPDictionary)options { _fullScreenModeState = _CPViewFullScreenModeStateMake(self); - + var fullScreenWindow = [[CPWindow alloc] initWithContentRect:[[CPPlatformWindow primaryPlatformWindow] contentBounds] styleMask:CPBorderlessWindowMask]; - + [fullScreenWindow setLevel:CPScreenSaverWindowLevel]; [fullScreenWindow setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - + var contentView = [fullScreenWindow contentView]; - + [contentView setBackgroundColor:[CPColor blackColor]]; [contentView addSubview:self]; @@ -1109,11 +1109,11 @@ var CPViewFlags = { }, [self setFrame:CGRectMakeCopy([contentView bounds])]; [fullScreenWindow makeKeyAndOrderFront:self]; - + [fullScreenWindow makeFirstResponder:self]; - + _isInFullScreenMode = YES; - + return YES; } @@ -1139,7 +1139,7 @@ var CPViewFlags = { }, [self setFrame:_fullScreenModeState.frame]; [self setAutoresizingMask:_fullScreenModeState.autoresizingMask]; [_fullScreenModeState.superview _insertSubview:self atIndex:_fullScreenModeState.index]; - + [[self window] orderOut:self]; } @@ -1175,17 +1175,41 @@ var CPViewFlags = { }, if ([view isKindOfClass:[CPView class]]) { - do + do { if (self == view) { [_window makeFirstResponder:[self nextValidKeyView]]; break; - } - } + } + } while (view = [view superview]); } + + [self _notifyViewDidHide]; } + else + { + [self _notifyViewDidUnhide]; + } +} + +- (void)_notifyViewDidHide +{ + [self viewDidHide]; + + var count = [_subviews count]; + while (count--) + [_subviews[count] _notifyViewDidHide]; +} + +- (void)_notifyViewDidUnhide +{ + [self viewDidUnhide]; + + var count = [_subviews count]; + while (count--) + [_subviews[count] _notifyViewDidUnhide]; } /*! @@ -1214,7 +1238,7 @@ var CPViewFlags = { }, } /*! - Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is + Sets the opacity of the receiver. The value must be in the range of 0.0 to 1.0, where 0.0 is completely transparent and 1.0 is completely opaque. @param anAlphaValue an alpha value ranging from 0.0 to 1.0. */ @@ -1222,11 +1246,11 @@ var CPViewFlags = { }, { if (_opacity == anAlphaValue) return; - + _opacity = anAlphaValue; - + #if PLATFORM(DOM) - + if (CPFeatureIsCompatible(CPOpacityRequiresFilterFeature)) { if (anAlphaValue === 1.0) @@ -1252,23 +1276,51 @@ var CPViewFlags = { }, /*! Returns \c YES if the receiver is hidden, or one of it's ancestor views is hidden. \c NO, otherwise. -*/ +*/ - (BOOL)isHiddenOrHasHiddenAncestor { var view = self; - + while (view && ![view isHidden]) view = [view superview]; - + return view !== nil; } +/*! + Called when the return value of isHiddenOrHasHiddenAncestor becomes YES, + e.g. when this view becomes hidden due to a setHidden:YES message to + itself or to one of its superviews. + + Note: in the current implementation, viewDidHide may be called multiple + times if additional superviews are hidden, even if + isHiddenOrHasHiddenAncestor was already YES. +*/ +- (void)viewDidHide +{ + +} + +/*! + Called when the return value of isHiddenOrHasHiddenAncestor becomes NO, + e.g. when this view stops being hidden due to a setHidden:NO message to + itself or to one of its superviews. + + Note: in the current implementation, viewDidUnhide may be called multiple + times if additional superviews are unhidden, even if + isHiddenOrHasHiddenAncestor was already NO. +*/ +- (void)viewDidUnhide +{ + +} + /*! Returns whether the receiver should be sent a \c -mouseDown: message for \c anEvent.
Returns \c YES by default. @return \c YES, if the view object accepts first mouse-down event. \c NO, otherwise. */ -//FIXME: should be NO by default? +//FIXME: should be NO by default? - (BOOL)acceptsFirstMouse:(CPEvent)anEvent { return YES; @@ -1301,7 +1353,7 @@ var CPViewFlags = { }, { if(_isHidden || !_hitTests || !CPRectContainsPoint(_frame, aPoint)) return nil; - + var view = nil, i = _subviews.length, adjustedPoint = _CGPointMake(aPoint.x - _CGRectGetMinX(_frame), aPoint.y - _CGRectGetMinY(_frame)); @@ -1467,7 +1519,7 @@ var CPViewFlags = { }, CPDOMDisplayServerSetStyleSize(_DOMImageParts[5], _DOMImageSizes[5].width, height); CPDOMDisplayServerSetStyleSize(_DOMImageParts[7], width, _DOMImageSizes[7].height); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[3], NULL, 0.0, _DOMImageSizes[1].height); @@ -1475,14 +1527,14 @@ var CPViewFlags = { }, CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[5], NULL, 0.0, _DOMImageSizes[1].height); CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[6], NULL, 0.0, 0.0); CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[7], NULL, _DOMImageSizes[6].width, 0.0); - CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0); + CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[8], NULL, 0.0, 0.0); } else if (_backgroundType == BackgroundVerticalThreePartImage) - { + { CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width, frameSize.height - _DOMImageSizes[0].height - _DOMImageSizes[2].height); CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height); + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, 0.0, _DOMImageSizes[0].height); CPDOMDisplayServerSetStyleLeftBottom(_DOMImageParts[2], NULL, 0.0, 0.0); } else if (_backgroundType == BackgroundHorizontalThreePartImage) @@ -1490,7 +1542,7 @@ var CPViewFlags = { }, CPDOMDisplayServerSetStyleSize(_DOMImageParts[1], frameSize.width - _DOMImageSizes[0].width - _DOMImageSizes[2].width, frameSize.height); CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[0], NULL, 0.0, 0.0); - CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); + CPDOMDisplayServerSetStyleLeftTop(_DOMImageParts[1], NULL, _DOMImageSizes[0].width, 0.0); CPDOMDisplayServerSetStyleRightTop(_DOMImageParts[2], NULL, 0.0, 0.0); } } @@ -1786,9 +1838,9 @@ setBoundsOrigin: - (void)displayRect:(CPRect)aRect { [self viewWillDraw]; - + [self displayRectIgnoringOpacity:aRect inContext:nil]; - + _dirtyRect = NULL; } @@ -1796,9 +1848,9 @@ setBoundsOrigin: { #if PLATFORM(DOM) [self lockFocus]; - + CGContextClearRect([[CPGraphicsContext currentContext] graphicsPort], aRect); - + [self drawRect:aRect]; [self unlockFocus]; #endif @@ -1816,18 +1868,18 @@ setBoundsOrigin: if (!_graphicsContext) { var graphicsPort = CGBitmapGraphicsContextCreate(); - + _DOMContentsElement = graphicsPort.DOMElement; - + _DOMContentsElement.style.zIndex = -100; _DOMContentsElement.style.overflow = "hidden"; _DOMContentsElement.style.position = "absolute"; _DOMContentsElement.style.visibility = "visible"; - + _DOMContentsElement.width = ROUND(_CGRectGetWidth(_frame)); _DOMContentsElement.height = ROUND(_CGRectGetHeight(_frame)); - + _DOMContentsElement.style.top = "0px"; _DOMContentsElement.style.left = "0px"; _DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_frame)) + "px"; @@ -1838,9 +1890,9 @@ setBoundsOrigin: #endif _graphicsContext = [CPGraphicsContext graphicsContextWithGraphicsPort:graphicsPort flipped:YES]; } - + [CPGraphicsContext setCurrentContext:_graphicsContext]; - + CGContextSaveGState([_graphicsContext graphicsPort]); } @@ -1850,7 +1902,7 @@ setBoundsOrigin: - (void)unlockFocus { CGContextRestoreGState([_graphicsContext graphicsPort]); - + [CPGraphicsContext setCurrentContext:nil]; } @@ -1869,7 +1921,7 @@ setBoundsOrigin: if (_needsLayout) { _needsLayout = NO; - + [self layoutSubviews]; } } @@ -1893,7 +1945,7 @@ setBoundsOrigin: { if (!_superview) return _bounds; - + return CGRectIntersection([self convertRect:[_superview visibleRect] fromView:_superview], _bounds); } @@ -1904,7 +1956,7 @@ setBoundsOrigin: var superview = _superview, clipViewClass = [CPClipView class]; - while(superview && ![superview isKindOfClass:clipViewClass]) + while(superview && ![superview isKindOfClass:clipViewClass]) superview = superview._superview; return superview; @@ -1917,10 +1969,10 @@ setBoundsOrigin: - (void)scrollPoint:(CGPoint)aPoint { var clipView = [self _enclosingClipView]; - + if (!clipView) return; - + [clipView scrollToPoint:[self convertPoint:aPoint toView:clipView]]; } @@ -1932,35 +1984,35 @@ setBoundsOrigin: - (BOOL)scrollRectToVisible:(CGRect)aRect { var visibleRect = [self visibleRect]; - + // Make sure we have a rect that exists. aRect = CGRectIntersection(aRect, _bounds); - + // If aRect is empty or is already visible then no scrolling required. if (_CGRectIsEmpty(aRect) || CGRectContainsRect(visibleRect, aRect)) return NO; var enclosingClipView = [self _enclosingClipView]; - + // If we're not in a clip view, then there isn't much we can do. if (!enclosingClipView) return NO; - + var scrollPoint = _CGPointMakeCopy(visibleRect.origin); - + // One of the following has to be true since our current visible rect didn't contain aRect. if (_CGRectGetMinX(aRect) <= _CGRectGetMinX(visibleRect)) scrollPoint.x = _CGRectGetMinX(aRect); else if (_CGRectGetMaxX(aRect) > _CGRectGetMaxX(visibleRect)) scrollPoint.x += _CGRectGetMaxX(aRect) - _CGRectGetMaxX(visibleRect); - + if (_CGRectGetMinY(aRect) <= _CGRectGetMinY(visibleRect)) scrollPoint.y = CGRectGetMinY(aRect); else if (_CGRectGetMaxY(aRect) > _CGRectGetMaxY(visibleRect)) scrollPoint.y += _CGRectGetMaxY(aRect) - _CGRectGetMaxY(visibleRect); - + [enclosingClipView scrollToPoint:CGPointMake(scrollPoint.x, scrollPoint.y)]; - + return YES; } @@ -2000,7 +2052,7 @@ setBoundsOrigin: var superview = _superview, scrollViewClass = [CPScrollView class]; - while(superview && ![superview isKindOfClass:scrollViewClass]) + while(superview && ![superview isKindOfClass:scrollViewClass]) superview = superview._superview; return superview; @@ -2098,7 +2150,7 @@ setBoundsOrigin: { if (_layer == aLayer) return; - + if (_layer) { _layer._owningView = nil; @@ -2106,18 +2158,18 @@ setBoundsOrigin: _DOMElement.removeChild(_layer._DOMElement); #endif } - + _layer = aLayer; - + if (_layer) { var bounds = CGRectMakeCopy([self bounds]); - + [_layer _setOwningView:self]; - + #if PLATFORM(DOM) _layer._DOMElement.style.zIndex = 100; - + _DOMElement.appendChild(_layer._DOMElement); #endif } @@ -2229,7 +2281,7 @@ setBoundsOrigin: } var attributeDictionary = [theClass themeAttributes]; - + if (!attributeDictionary) continue; @@ -2262,14 +2314,14 @@ setBoundsOrigin: themeClass = [theClass themeClass]; _themeAttributes = {}; - + while (count--) { var attributeName = attributes[count--], attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]]; [attribute setParentAttribute:[theme _attributeWithName:attributeName forClass:themeClass]]; - + _themeAttributes[attributeName] = attribute; } } @@ -2278,9 +2330,9 @@ setBoundsOrigin: { if (_theme === aTheme) return; - + _theme = aTheme; - + [self viewDidChangeTheme]; } @@ -2387,7 +2439,7 @@ setBoundsOrigin: return _CGRectMakeZero(); } -- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName +- (CPView)layoutEphemeralSubviewNamed:(CPString)aViewName positioned:(CPWindowOrderingMode)anOrderingMode relativeToEphemeralSubviewNamed:(CPString)relativeToViewName { @@ -2452,9 +2504,9 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", */ - (id)initWithCoder:(CPCoder)aCoder { - // We create the DOMElement "early" because there is a chance that we - // will decode our superview before we are done decoding, at which point - // we have to have an element to place in the tree. Perhaps there is + // We create the DOMElement "early" because there is a chance that we + // will decode our superview before we are done decoding, at which point + // we have to have an element to place in the tree. Perhaps there is // a more "elegant" way to do this...? #if PLATFORM(DOM) _DOMElement = DOMElementPrototype.cloneNode(false); @@ -2465,16 +2517,16 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", _bounds = [aCoder decodeRectForKey:CPViewBoundsKey]; self = [super initWithCoder:aCoder]; - + if (self) { // We have to manually check because it may be 0, so we can't use || _tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1; - + _window = [aCoder decodeObjectForKey:CPViewWindowKey]; _subviews = [aCoder decodeObjectForKey:CPViewSubviewsKey] || []; _superview = [aCoder decodeObjectForKey:CPViewSuperviewKey]; - + // FIXME: Should we encode/decode this? _registeredDraggedTypes = [CPSet set]; _registeredDraggedTypesArray = []; @@ -2483,7 +2535,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", _autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey]; _hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey]; - + // DOM SETUP #if PLATFORM(DOM) _DOMImageParts = []; @@ -2491,10 +2543,10 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", CPDOMDisplayServerSetStyleLeftTop(_DOMElement, NULL, _CGRectGetMinX(_frame), _CGRectGetMinY(_frame)); CPDOMDisplayServerSetStyleSize(_DOMElement, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)); - + var index = 0, count = _subviews.length; - + for (; index < count; ++index) { CPDOMDisplayServerAppendChild(_DOMElement, _subviews[index]._DOMElement); @@ -2546,7 +2598,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; - + if (_tag !== -1) [aCoder encodeInt:_tag forKey:CPViewTagKey]; @@ -2616,7 +2668,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask", var _CPViewFullScreenModeStateMake = function(aView) { var superview = aView._superview; - + return { autoresizingMask:aView._autoresizingMask, frame:CGRectMakeCopy(aView._frame), index:(superview ? [superview._subviews indexOfObjectIdenticalTo:aView] : 0), superview:superview }; } @@ -2626,93 +2678,93 @@ var _CPViewGetTransform = function(/*CPView*/ fromView, /*CPView */ toView) sameWindow = YES, fromWindow = nil, toWindow = nil; - + if (fromView) { var view = fromView; - + // FIXME: This doesn't handle the case when the outside views are equal. - // If we have a fromView, "climb up" the view tree until + // If we have a fromView, "climb up" the view tree until // we hit the root node or we hit the toLayer. while (view && view != toView) { var frame = view._frame; - + transform.tx += _CGRectGetMinX(frame); transform.ty += _CGRectGetMinY(frame); - + if (view._boundsTransform) { _CGAffineTransformConcatTo(transform, view._boundsTransform, transform); } - + view = view._superview; } - + // If we hit toView, then we're done. if (view === toView) return transform; - + else if (fromView && toView) { fromWindow = [fromView window]; toWindow = [toView window]; - + if (fromWindow && toWindow && fromWindow !== toWindow) { sameWindow = NO; - + var frame = [fromWindow frame]; - + transform.tx += _CGRectGetMinX(frame); transform.ty += _CGRectGetMinY(frame); } } } - + // FIXME: For now we can do things this way, but eventually we need to do them the "hard" way. var view = toView; - + while (view) { var frame = view._frame; - + transform.tx -= _CGRectGetMinX(frame); transform.ty -= _CGRectGetMinY(frame); - + if (view._boundsTransform) { _CGAffineTransformConcatTo(transform, view._inverseBoundsTransform, transform); } - + view = view._superview; } - + if (!sameWindow) { var frame = [toWindow frame]; - + transform.tx -= _CGRectGetMinX(frame); transform.ty -= _CGRectGetMinY(frame); } /* var views = [], view = toView; - + while (view) { views.push(view); view = view._superview; } - + var index = views.length; - + while (index--) { var frame = views[index]._frame; - + transform.tx -= _CGRectGetMinX(frame); transform.ty -= _CGRectGetMinY(frame); }*/ - + return transform; } From 7c787538653fc8f18f07d2fe41443768cac4f3ad Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 3 Jul 2010 21:37:42 -0400 Subject: [PATCH 143/356] Fixed with CPTabView: don't remove the content and auxiliary views if the new views are the same as the old ones. This prevents flickering and needless redraws when the currently selected tab is reselected. --- AppKit/CPTabView.j | 214 +++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 104 deletions(-) diff --git a/AppKit/CPTabView.j b/AppKit/CPTabView.j index 71aac4a7b..e5e7b72bf 100644 --- a/AppKit/CPTabView.j +++ b/AppKit/CPTabView.j @@ -63,20 +63,20 @@ var CPTabViewBezelBorderLeftImage = nil, var LEFT_INSET = 7.0, RIGHT_INSET = 7.0; - + var CPTabViewDidSelectTabViewItemSelector = 1, CPTabViewShouldSelectTabViewItemSelector = 2, CPTabViewWillSelectTabViewItemSelector = 4, CPTabViewDidChangeNumberOfTabViewItemsSelector = 8; -/*! +/*! @ingroup appkit @class CPTabView This class represents a view that has multiple subviews (CPTabViewItem) presented as individual tabs. Only one CPTabViewItem is shown at a time, and other CPTabViewItems can be made visible (one at a time) by clicking on the CPTabViewItem's tab at the top of the tab view. - + THe currently selected CPTabViewItem is the view that is displayed. */ @implementation CPTabView : CPView @@ -84,15 +84,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1, CPView _labelsView; CPView _backgroundView; CPView _separatorView; - + CPView _auxiliaryView; CPView _contentView; - + CPArray _tabViewItems; CPTabViewItem _selectedTabViewItem; CPTabViewType _tabViewType; - + id _delegate; unsigned _delegateSelectors; } @@ -104,20 +104,20 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (self != CPTabView) return; - + var bundle = [CPBundle bundleForClass:self], - + emptyImage = [[CPImage alloc] initByReferencingFile:@"" size:CGSizeMake(7.0, 0.0)], backgroundImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBackgroundCenter.png"] size:CGSizeMake(1.0, 1.0)], - + bezelBorderLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderLeft.png"] size:CGSizeMake(7.0, 1.0)], bezerBorderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorder.png"] size:CGSizeMake(1.0, 1.0)], bezelBorderRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderRight.png"] size:CGSizeMake(7.0, 1.0)]; - + CPTabViewBezelBorderBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: [ - emptyImage, - emptyImage, + emptyImage, + emptyImage, emptyImage, bezelBorderLeftImage, @@ -128,7 +128,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, bezerBorderImage, bezelBorderRightImage ]]]; - + CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage]; } @@ -143,13 +143,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1, - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) { _tabViewType = CPTopTabsBezelBorder; _tabViewItems = []; } - + return self; } @@ -157,7 +157,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (_tabViewType != CPTopTabsBezelBorder || _labelsView) return; - + [self _createBezelBorder]; [self layoutSubviews]; } @@ -166,7 +166,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, - (void)_createBezelBorder { var bounds = [self bounds]; - + _labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)]; [_labelsView setTabView:self]; @@ -174,19 +174,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1, [self addSubview:_labelsView]; - _backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()]; - + _backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()]; + [_backgroundView setBackgroundColor:CPTabViewBezelBorderBackgroundColor]; [_backgroundView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - + [self addSubview:_backgroundView]; - + _separatorView = [[CPView alloc] initWithFrame:CGRectMakeZero()]; [_separatorView setBackgroundColor:[[self class] bezelBorderColor]]; [_separatorView setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin]; - + [self addSubview:_separatorView]; } @@ -200,21 +200,21 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { var backgroundRect = [self bounds], labelsViewHeight = [_CPTabLabelsView height]; - + backgroundRect.origin.y += labelsViewHeight; backgroundRect.size.height -= labelsViewHeight; - + [_backgroundView setFrame:backgroundRect]; - + var auxiliaryViewHeight = 5.0; - + if (_auxiliaryView) { auxiliaryViewHeight = CGRectGetHeight([_auxiliaryView frame]); - + [_auxiliaryView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, auxiliaryViewHeight)]; } - + [_separatorView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight + auxiliaryViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, 1.0)]; } @@ -242,13 +242,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (!_labelsView && _tabViewType == CPTopTabsBezelBorder) [self _createBezelBorder]; - + [_tabViewItems insertObject:aTabViewItem atIndex:anIndex]; - + [_labelsView tabView:self didAddTabViewItem:aTabViewItem]; - + [aTabViewItem _setTabView:self]; - + if ([_tabViewItems count] == 1) [self selectFirstTabViewItem:self]; @@ -265,11 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1, var index = [self indexOfTabViewItem:aTabViewItem]; [_tabViewItems removeObjectIdenticalTo:aTabViewItem]; - + [_labelsView tabView:self didRemoveTabViewItemAtIndex:index]; - + [aTabViewItem _setTabView:nil]; - + if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector) [_delegate tabViewDidChangeNumberOfTabViewItems:self]; } @@ -292,7 +292,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { var index = 0, count = [_tabViewItems count]; - + for (; index < count; ++index) if ([[_tabViewItems[index] identifier] isEqual:anIdentifier]) return index; @@ -332,7 +332,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, - (void)selectFirstTabViewItem:(id)aSender { var count = [_tabViewItems count]; - + if (count) [self selectTabViewItemAtIndex:0]; } @@ -344,7 +344,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, - (void)selectLastTabViewItem:(id)aSender { var count = [_tabViewItems count]; - + if (count) [self selectTabViewItemAtIndex:count - 1]; } @@ -357,10 +357,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (!_selectedTabViewItem) return; - + var index = [self indexOfTabViewItem:_selectedTabViewItem], count = [_tabViewItems count]; - + [self selectTabViewItemAtIndex:index + 1 % count]; } @@ -372,10 +372,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (!_selectedTabViewItem) return; - + var index = [self indexOfTabViewItem:_selectedTabViewItem], count = [_tabViewItems count]; - + [self selectTabViewItemAtIndex:index == 0 ? count : index - 1]; } @@ -387,7 +387,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem]) return; - + if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector) [_delegate tabView:self willSelectTabViewItem:aTabViewItem]; @@ -395,29 +395,35 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { _selectedTabViewItem._tabState = CPBackgroundTab; [_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem]; - - [_contentView removeFromSuperview]; - [_auxiliaryView removeFromSuperview]; } _selectedTabViewItem = aTabViewItem; - - _selectedTabViewItem._tabState = CPSelectedTab; - - _contentView = [_selectedTabViewItem view]; - [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - - _auxiliaryView = [_selectedTabViewItem auxiliaryView]; - [_auxiliaryView setAutoresizingMask:CPViewWidthSizable]; - - [self addSubview:_contentView]; - if (_auxiliaryView) + _selectedTabViewItem._tabState = CPSelectedTab; + + var _previousContentView = _contentView; + _contentView = [_selectedTabViewItem view]; + + if (_previousContentView !== _contentView) + { + [_previousContentView removeFromSuperview]; + [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; + [self addSubview:_contentView]; + } + + var _previousAuxiliaryView = _auxiliaryView; + _auxiliaryView = [_selectedTabViewItem auxiliaryView]; + + if (_previousAuxiliaryView !== _auxiliaryView) + { + [_previousAuxiliaryView removeFromSuperview]; + [_auxiliaryView setAutoresizingMask:CPViewWidthSizable]; [self addSubview:_auxiliaryView]; - + } + [_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem]; - + [self layoutSubviews]; - + if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector) [_delegate tabView:self didSelectTabViewItem:aTabViewItem]; } @@ -439,7 +445,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, return _selectedTabViewItem; } -// +// /*! Sets the tab view type. @param aTabViewType the view type @@ -448,19 +454,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (_tabViewType == aTabViewType) return; - + _tabViewType = aTabViewType; - + if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder) [_labelsView removeFromSuperview]; else if (![_labelsView superview]) [self addSubview:_labelsView]; - + if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder) [_backgroundView removeFromSuperview]; else if (![_backgroundView superview]) [self addSubview:_backgroundView]; - + [self layoutSubviews]; } @@ -479,7 +485,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, - (CGRect)contentRect { var contentRect = CGRectMakeCopy([self bounds]); - + if (_tabViewType == CPTopTabsBezelBorder) { var labelsViewHeight = [_CPTabLabelsView height], @@ -488,7 +494,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, contentRect.origin.y += labelsViewHeight + auxiliaryViewHeight + separatorViewHeight; contentRect.size.height -= labelsViewHeight + auxiliaryViewHeight + separatorViewHeight * 2.0; // 2 for the bottom border as well. - + contentRect.origin.x += LEFT_INSET; contentRect.size.width -= LEFT_INSET + RIGHT_INSET; } @@ -512,9 +518,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { if (_delegate == aDelegate) return; - + _delegate = aDelegate; - + _delegateSelectors = 0; if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) @@ -527,7 +533,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, _delegateSelectors |= CPTabViewDidSelectTabViewItemSelector; if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)]) - _delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector; + _delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector; } // @@ -536,7 +542,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, { var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil], tabViewItem = [_labelsView representedTabViewItemAtPoint:location]; - + if (tabViewItem) [self selectTabViewItem:tabViewItem]; } @@ -556,18 +562,18 @@ var CPTabViewItemsKey = "CPTabViewItemsKey", { _tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey]; _tabViewItems = []; - + // FIXME: this is somewhat hacky [self _createBezelBorder]; - + var items = [aCoder decodeObjectForKey:CPTabViewItemsKey]; for (var i = 0; items && i < items.length; i++) [self insertTabViewItem:items[i] atIndex:i]; - + var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey]; if (selected) [self selectTabViewItem:selected]; - + [self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]]; } @@ -580,12 +586,12 @@ var CPTabViewItemsKey = "CPTabViewItemsKey", _subviews = []; [super encodeWithCoder:aCoder]; _subviews = actualSubviews; - + [aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];; [aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey]; - + [aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey]; - + [aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey]; } @@ -609,7 +615,7 @@ var _CPTabLabelsViewBackgroundColor = nil, return; var bundle = [CPBundle bundleForClass:self]; - + _CPTabLabelsViewBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: [ [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewLeft.png"] size:CGSizeMake(12.0, 26.0)], @@ -626,16 +632,16 @@ var _CPTabLabelsViewBackgroundColor = nil, - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) { _tabLabels = []; - + [self setBackgroundColor:_CPTabLabelsViewBackgroundColor]; [self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)]; } - + return self; } @@ -652,24 +658,24 @@ var _CPTabLabelsViewBackgroundColor = nil, - (void)tabView:(CPTabView)aTabView didAddTabViewItem:(CPTabViewItem)aTabViewItem { var label = [[_CPTabLabel alloc] initWithFrame:CGRectMakeZero()]; - + [label setTabViewItem:aTabViewItem]; - + _tabLabels.push(label); - + [self addSubview:label]; - + [self layoutSubviews]; } - (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index { var label = _tabLabels[index]; - + [_tabLabels removeObjectAtIndex:index]; [label removeFromSuperview]; - + [self layoutSubviews]; } @@ -682,11 +688,11 @@ var _CPTabLabelsViewBackgroundColor = nil, { var index = 0, count = _tabLabels.length; - + for (; index < count; ++index) { var label = _tabLabels[index]; - + if (CGRectContainsPoint([label frame], aPoint)) return [label tabViewItem]; } @@ -700,14 +706,14 @@ var _CPTabLabelsViewBackgroundColor = nil, count = _tabLabels.length, width = (_CGRectGetWidth([self bounds]) - (count - 1) * _CPTabLabelsViewInsideMargin - 2 * _CPTabLabelsViewOutsideMargin) / count, x = _CPTabLabelsViewOutsideMargin; - + for (; index < count; ++index) { var label = _tabLabels[index], frame = _CGRectMake(x, 8.0, width, 18.0); - + [label setFrame:frame]; - + x = _CGRectGetMaxX(frame) + _CPTabLabelsViewInsideMargin; } } @@ -716,9 +722,9 @@ var _CPTabLabelsViewBackgroundColor = nil, { if (CGSizeEqualToSize([self frame].size, aSize)) return; - + [super setFrameSize:aSize]; - + [self layoutSubviews]; } @@ -740,14 +746,14 @@ var _CPTabLabelBackgroundColor = nil, return; var bundle = [CPBundle bundleForClass:self]; - + _CPTabLabelBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: [ [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundLeft.png"] size:CGSizeMake(6.0, 18.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundCenter.png"] size:CGSizeMake(1.0, 18.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundRight.png"] size:CGSizeMake(6.0, 18.0)] ] isVertical:NO]]; - + _CPTabLabelSelectedBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices: [ [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedLeft.png"] size:CGSizeMake(3.0, 18.0)], @@ -759,21 +765,21 @@ var _CPTabLabelBackgroundColor = nil, - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) - { + { _labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; - + [_labelField setAlignment:CPCenterTextAlignment]; [_labelField setFrame:CGRectMake(5.0, 0.0, CGRectGetWidth(aFrame) - 10.0, 20.0)]; [_labelField setAutoresizingMask:CPViewWidthSizable]; [_labelField setFont:[CPFont boldSystemFontOfSize:11.0]]; - + [self addSubview:_labelField]; - + [self setTabState:CPBackgroundTab]; } - + return self; } @@ -785,7 +791,7 @@ var _CPTabLabelBackgroundColor = nil, - (void)setTabViewItem:(CPTabViewItem)aTabViewItem { _tabViewItem = aTabViewItem; - + [self update]; } From c277ae7f68e7512d5473c68c38997abd70025119 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 3 Jul 2010 22:08:21 -0400 Subject: [PATCH 144/356] Fixed: calling CPTabView setTabViewType:CPNoTabsNoBorder before the first insertTabViewItem would cause an error. Fixed: if a tab item was added in CPNoTabsNoBorder mode, and the mode was later switched to CPTopTabsBezelBorder, that previously added tab item would have no label/tab. The solution is to maintain _labelsView in either mode; since in CPNoTabsNoBorder mode _labelsView is not in the view hierarchy anyhow the performance impact should be minimal. --- AppKit/CPTabView.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTabView.j b/AppKit/CPTabView.j index e5e7b72bf..04fa320ba 100644 --- a/AppKit/CPTabView.j +++ b/AppKit/CPTabView.j @@ -240,7 +240,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1, */ - (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex { - if (!_labelsView && _tabViewType == CPTopTabsBezelBorder) + if (!_labelsView) [self _createBezelBorder]; [_tabViewItems insertObject:aTabViewItem atIndex:anIndex]; @@ -459,12 +459,12 @@ var CPTabViewDidSelectTabViewItemSelector = 1, if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder) [_labelsView removeFromSuperview]; - else if (![_labelsView superview]) + else if (_labelsView && ![_labelsView superview]) [self addSubview:_labelsView]; if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder) [_backgroundView removeFromSuperview]; - else if (![_backgroundView superview]) + else if (_backgroundView && ![_backgroundView superview]) [self addSubview:_backgroundView]; [self layoutSubviews]; From 7ac59dd142e8a1329346f9a3135b1caca7952f4f Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sat, 31 Jul 2010 20:20:18 -0500 Subject: [PATCH 145/356] Sheets should be assigned to the platform window of the window it is attached to. --- AppKit/CPApplication.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 7958fc45f..ad729b0f5 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -861,6 +861,7 @@ CPRunContinuesResponse = -1002; } [aWindow orderFront:self]; + [aSheet setPlatformWindow:[aWindow platformWindow]]; [aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo]; } From 17cc77e81664cf5bfdc1a35d9e0eff37b16f201f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 1 Aug 2010 17:08:50 -0400 Subject: [PATCH 146/356] Clean up code in table column resizing paths in preparation for fixing it. --- AppKit/CPTableView.j | 189 ++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 94 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 652831c90..37421f6aa 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -543,7 +543,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return; _intercellSpacing = _CGSizeMakeCopy(aSize); - + _dirtyTableColumnRangeIndex = 0; // so that _recalculateTableColumnRanges will work [self _recalculateTableColumnRanges]; @@ -1422,10 +1422,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; rectOfRow = [self rectOfRow:aRow], leftInset = FLOOR(_intercellSpacing.width / 2.0), topInset = FLOOR(_intercellSpacing.height / 2.0); - - return _CGRectMake(tableColumnRange.location + leftInset, - _CGRectGetMinY(rectOfRow) + topInset, - tableColumnRange.length - _intercellSpacing.width, + + return _CGRectMake(tableColumnRange.location + leftInset, + _CGRectGetMinY(rectOfRow) + topInset, + tableColumnRange.length - _intercellSpacing.width, _CGRectGetHeight(rectOfRow) - _intercellSpacing.height); } @@ -1450,114 +1450,115 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var superview = [self superview]; - if (!superview) - return; + if (!superview) + return; - var superviewSize = [superview bounds].size; + var superviewSize = [superview bounds].size; - UPDATE_COLUMN_RANGES_IF_NECESSARY(); + UPDATE_COLUMN_RANGES_IF_NECESSARY(); - var count = NUMBER_OF_COLUMNS(), - visColumns = [[CPArray alloc] init], - totalWidth = 0, - i = 0; + var count = NUMBER_OF_COLUMNS(), + visColumns = [[CPArray alloc] init], + totalWidth = 0, + i = 0; - for(; i < count; i++) - { - if(![_tableColumns[i] isHidden]) - { + for(; i < count; i++) + { + if(![_tableColumns[i] isHidden]) + { [visColumns addObject:i]; totalWidth += [_tableColumns[i] width]; - } - } + } + } - count = [visColumns count]; + count = [visColumns count]; - //if there are rows - if (count > 0) - { - var columnToResize = _tableColumns[visColumns[0]]; - var newWidth = superviewSize.width - totalWidth;// - [columnToResize width]; - newWidth += [columnToResize width]; - newWidth = (newWidth < [columnToResize minWidth]) ? [columnToResize minWidth] : newWidth; - newWidth = (newWidth > [columnToResize maxWidth]) ? [columnToResize maxWidth] : newWidth; + //if there are rows + if (count > 0) + { + var columnToResize = _tableColumns[visColumns[0]], + newWidth = superviewSize.width - totalWidth;// - [columnToResize width]; - [columnToResize setWidth:FLOOR(newWidth)]; - } + newWidth += [columnToResize width]; + newWidth = MAX([columnToResize minWidth], newWidth); + newWidth = MIN([columnToResize maxWidth], newWidth); - [self setNeedsLayout]; + [columnToResize setWidth:FLOOR(newWidth)]; + } + + [self setNeedsLayout]; } - (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize { - var superview = [self superview]; + var superview = [self superview]; - if (!superview) + if (!superview) + return; + + var superviewSize = [superview bounds].size; + + if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); + + var count = _tableColumns.length,//NUMBER_OF_COLUMNS(), + visColumns = [[CPArray alloc] init], + buffer = 0.0; + + // Fixme: cache resizable columns because they won't changes betwwen two calls to this method. + for(var i=0; i < count; i++) + { + var tableColumn = _tableColumns[i]; + if(![tableColumn isHidden] && ([tableColumn resizingMask] & CPTableColumnAutoresizingMask)) + [visColumns addObject:i]; + } + + // redefine count + count = [visColumns count]; + + //if there are columns + if (count > 0) + { + var maxXofColumns = CGRectGetMaxX([self rectOfColumn:visColumns[count - 1]]); + + // If the x value of the end of the last column is between the current bounds and the previous bounds we should snap. + if (!_lastColumnShouldSnap && (maxXofColumns >= superviewSize.width && maxXofColumns <= oldSize.width || maxXofColumns <= superviewSize.width && maxXofColumns >= oldSize.width)) + { + //set the snap mask + _lastColumnShouldSnap = YES; + //then we need to make sure everything is set correctly. + [self _resizeAllColumnUniformlyWithOldSize:CGSizeMake(maxXofColumns, 0)]; + } + + if(!_lastColumnShouldSnap) return; - var superviewSize = [superview bounds].size; + // FIX ME: This is wrong because this should continue to resize all columns + // If the last column reaches it's max/min it will simply stop resizing, + // correct behavior is to resize all columns until they reach their min/max - if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); - - var count = _tableColumns.length,//NUMBER_OF_COLUMNS(), - visColumns = [[CPArray alloc] init], - buffer = 0.0; - - // Fixme: cache resizable columns because they won't changes betwwen two calls to this method. - for(var i=0; i < count; i++) + for (var i = 0; i < count; i++) { - var tableColumn = _tableColumns[i]; - if(![tableColumn isHidden] && ([tableColumn resizingMask] & CPTableColumnAutoresizingMask)) - [visColumns addObject:i]; + var column = visColumns[i]; + columnToResize = _tableColumns[column], + currentBuffer = buffer / (count - i), + realNewWidth = ([columnToResize width] / oldSize.width * [superview bounds].size.width) + currentBuffer, + newWidth = realNewWidth; + newWidth = MAX([columnToResize minWidth], newWidth); + newWidth = MIN([columnToResize maxWidth], newWidth); + buffer -= currentBuffer; + + // the buffer takes into account the min/max width of the column + buffer += realNewWidth - newWidth; + + [columnToResize setWidth:newWidth]; } - // redefine count - count = [visColumns count]; + // if there is space left over that means column resize was too long or too short + if(buffer !== 0) + _lastColumnShouldSnap = NO; + } - //if there are columns - if (count > 0) - { - var maxXofColumns = CGRectGetMaxX([self rectOfColumn:visColumns[count - 1]]); - - // If the x value of the end of the last column is between the current bounds and the previous bounds we should snap. - if (!_lastColumnShouldSnap && (maxXofColumns >= superviewSize.width && maxXofColumns <= oldSize.width || maxXofColumns <= superviewSize.width && maxXofColumns >= oldSize.width)) - { - //set the snap mask - _lastColumnShouldSnap = YES; - //then we need to make sure everything is set correctly. - [self _resizeAllColumnUniformlyWithOldSize:CGSizeMake(maxXofColumns, 0)]; - } - - if(!_lastColumnShouldSnap) - return; - - - // FIX ME: This is wrong because this should continue to resize all columns - // If the last column reaches it's max/min it will simply stop resizing, - // correct behavior is to resize all columns until they reach their min/max - - for (var i = 0; i < count; i++) - { - var column = visColumns[i]; - columnToResize = _tableColumns[column], - currentBuffer = buffer / (count - i), - realNewWidth = ([columnToResize width] / oldSize.width * [superview bounds].size.width) + currentBuffer , - newWidth = MAX([columnToResize minWidth], realNewWidth); - newWidth = MIN([columnToResize maxWidth], realNewWidth); - buffer -= currentBuffer; - - // the buffer takes into account the min/max width of the column - buffer += realNewWidth - newWidth; - - [columnToResize setWidth:newWidth]; - } - - // if there is space left over that means column resize was too long or too short - if(buffer !== 0) - _lastColumnShouldSnap = NO; - } - - [self setNeedsLayout]; + [self setNeedsLayout]; } /*! @@ -1599,8 +1600,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; //if the last row exists if (count >= 0) { - var columnToResize = _tableColumns[count]; - var newSize = MAX(0.0, superviewSize.width - CGRectGetMinX([self rectOfColumn:count])); + var columnToResize = _tableColumns[count], + newSize = MAX(0.0, superviewSize.width - CGRectGetMinX([self rectOfColumn:count])); if (newSize > 0) { @@ -3117,7 +3118,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { // We don't use rowAtPoint here because the drag indicator can appear below the last row // and rowAtPoint doesn't return rows that are larger than numberOfRows - // FIX ME: this is going to break when we implement variable row heights... + // FIX ME: this is going to break when we implement variable row heights... var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )), // Determine if the mouse is currently closer to this row or the row below it lowerRow = row + 1, From 6884f93d76e617571a496b1e32de95e11daa1b0b Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 1 Aug 2010 18:06:18 -0400 Subject: [PATCH 147/356] Fixed: after the intercell spacing commit, table column auto resizing on the first or last column would result in a total column width wider than the scroll width of the table. This would appear as the rightmost column sticking out and the table showing a horizontal scrollbar. --- AppKit/CPTableView.j | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 37421f6aa..9581a2dba 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1438,11 +1438,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var mask = _columnAutoResizingStyle; - if(mask === CPTableViewUniformColumnAutoresizingStyle) + if (mask === CPTableViewUniformColumnAutoresizingStyle) [self _resizeAllColumnUniformlyWithOldSize:aSize]; - else if(mask === CPTableViewLastColumnOnlyAutoresizingStyle) + else if (mask === CPTableViewLastColumnOnlyAutoresizingStyle) [self sizeLastColumnToFit]; - else if(mask === CPTableViewFirstColumnOnlyAutoresizingStyle) + else if (mask === CPTableViewFirstColumnOnlyAutoresizingStyle) [self _autoResizeFirstColumn]; } @@ -1467,7 +1467,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if(![_tableColumns[i] isHidden]) { [visColumns addObject:i]; - totalWidth += [_tableColumns[i] width]; + totalWidth += [_tableColumns[i] width] + _intercellSpacing.width; } } @@ -1601,7 +1601,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (count >= 0) { var columnToResize = _tableColumns[count], - newSize = MAX(0.0, superviewSize.width - CGRectGetMinX([self rectOfColumn:count])); + newSize = MAX(0.0, superviewSize.width - CGRectGetMinX([self rectOfColumn:count]) - _intercellSpacing.width); if (newSize > 0) { From dac61a14cd4b3a1ec73408c4b9fde0f3c5e81388 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 1 Aug 2010 18:10:27 -0400 Subject: [PATCH 148/356] Eliminated some accidental globals in uniform table column resizing. --- AppKit/CPTableView.j | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 9581a2dba..fe9155bcb 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1498,14 +1498,15 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var superviewSize = [superview bounds].size; - if (_dirtyTableColumnRangeIndex !== CPNotFound) [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); + if (_dirtyTableColumnRangeIndex !== CPNotFound) + [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); var count = _tableColumns.length,//NUMBER_OF_COLUMNS(), visColumns = [[CPArray alloc] init], buffer = 0.0; // Fixme: cache resizable columns because they won't changes betwwen two calls to this method. - for(var i=0; i < count; i++) + for (var i=0; i < count; i++) { var tableColumn = _tableColumns[i]; if(![tableColumn isHidden] && ([tableColumn resizingMask] & CPTableColumnAutoresizingMask)) @@ -1529,7 +1530,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self _resizeAllColumnUniformlyWithOldSize:CGSizeMake(maxXofColumns, 0)]; } - if(!_lastColumnShouldSnap) + if (!_lastColumnShouldSnap) return; // FIX ME: This is wrong because this should continue to resize all columns @@ -1538,7 +1539,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; for (var i = 0; i < count; i++) { - var column = visColumns[i]; + var column = visColumns[i], columnToResize = _tableColumns[column], currentBuffer = buffer / (count - i), realNewWidth = ([columnToResize width] / oldSize.width * [superview bounds].size.width) + currentBuffer, @@ -1554,7 +1555,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } // if there is space left over that means column resize was too long or too short - if(buffer !== 0) + if (buffer !== 0) _lastColumnShouldSnap = NO; } From f028533c0706363cd1af2ebc752aa0bac6f4bdfd Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sun, 1 Aug 2010 17:50:19 -0500 Subject: [PATCH 149/356] Removed gradient stuff that has been moved to the theme. --- AppKit/CPTableView.j | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index fe9155bcb..50070e5a3 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -216,12 +216,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; int _draggedColumnIndex; CPArray _differedColumnDataToRemove; - -/* - CPGradient _sourceListInactiveGradient; - CPColor _sourceListInactiveTopLineColor; - CPColor _sourceListInactiveBottomLineColor; -*/ } + (CPString)themeClass @@ -337,11 +331,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _draggedColumnIndex = -1; - // Gradients for the source list - _sourceListActiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [89.0/255.0, 153.0/255.0, 209.0/255.0,1.0, 33.0/255.0, 94.0/255.0, 208.0/255.0,1.0], [0,1], 2); - _sourceListActiveTopLineColor = [CPColor colorWithCalibratedRed:(61.0/255.0) green:(123.0/255.0) blue:(218.0/255.0) alpha:1.0]; - _sourceListActiveBottomLineColor = [CPColor colorWithCalibratedRed:(31.0/255.0) green:(92.0/255.0) blue:(207.0/255.0) alpha:1.0]; - /* //gradients for the source list when CPTableView is NOT first responder or the window is NOT key // FIX ME: we need to actually implement this. _sourceListInactiveGradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [168.0/255.0,183.0/255.0,205.0/255.0,1.0,157.0/255.0,174.0/255.0,199.0/255.0,1.0], [0,1], 2); From b4dd6b670bb084bbcb662f8b76ff13406c817567 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 1 Aug 2010 19:06:57 -0400 Subject: [PATCH 150/356] Switch to the standard macros in _resizeAllColumnUniformlyWithOldSize as originally intended by Randy Luecke. --- AppKit/CPTableView.j | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index fe9155bcb..991ad5cf1 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1498,10 +1498,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var superviewSize = [superview bounds].size; - if (_dirtyTableColumnRangeIndex !== CPNotFound) - [self _recalculateTableColumnRanges];//UPDATE_COLUMN_RANGES_IF_NECESSARY(); + UPDATE_COLUMN_RANGES_IF_NECESSARY(); - var count = _tableColumns.length,//NUMBER_OF_COLUMNS(), + var count = NUMBER_OF_COLUMNS(), visColumns = [[CPArray alloc] init], buffer = 0.0; From dff6203fb3d8f01c2313ff6f2452e81114e7e808 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 1 Aug 2010 19:10:22 -0400 Subject: [PATCH 151/356] Closes #806. Fixed: if a selected row was removed from a table view, the selection remained and would show up again if a new row was later added. --- AppKit/CPTableView.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 991ad5cf1..1f96b6b5d 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1616,11 +1616,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (void)noteNumberOfRowsChanged { + var oldNumberOfRows = _numberOfRows; + _numberOfRows = nil; _numberOfRows = [self numberOfRows]; - var oldNumberOfRows = _numberOfRows; - // remove row indexes from the selection if they no longer exist var hangingSelections = oldNumberOfRows - _numberOfRows; From 90a45dca29f87fb4933d267bee2e31bc2360b442 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sun, 1 Aug 2010 20:19:26 -0500 Subject: [PATCH 152/356] some fixes to default buttons to make them more cocoa compliant... --- AppKit/CPButton.j | 6 ++++++ AppKit/CPWindow/CPWindow.j | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index c2f212644..7cfe38e54 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -572,9 +572,15 @@ CPButtonStateMixed = CPThemeState("mixed"); // Check if the key equivalent is the enter key // Treat \r and \n as the same key equivalent. See issue #710. if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter) + { [[self window] setDefaultButton:self]; + [self setDefaultButton:YES]; + } else if ([[self window] defaultButton] === self) + { [[self window] setDefaultButton:nil]; + [self setDefaultButton:NO]; + } _keyEquivalent = aString || @""; } diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index d010871ed..de0744e7f 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -2406,9 +2406,12 @@ CPTexturedBackgroundWindowMask if (_defaultButton === aButton) return; - [_defaultButton setDefaultButton:NO]; + if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter) + [_defaultButton setKeyEquivalent:nil]; + _defaultButton = aButton; - [_defaultButton setDefaultButton:YES]; + + [_defaultButton setKeyEquivalent:CPCarriageReturnCharacter]; } - (CPButton)defaultButton From e4c79d210111b4b2a5f16e86c8236d1117a55101 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 2 Aug 2010 23:13:06 -0400 Subject: [PATCH 153/356] Closes #809. End editing of a text field if it is disabled or made uneditable. Manual test included. --- AppKit/CPTextField.j | 164 ++++++++++-------- Tests/Manual/CPTextField/AppController.j | 48 +++++ Tests/Manual/CPTextField/Info.plist | 12 ++ Tests/Manual/CPTextField/Jakefile | 93 ++++++++++ .../Manual/CPTextField/Resources/spinner.gif | Bin 0 -> 1849 bytes Tests/Manual/CPTextField/index-debug.html | 104 +++++++++++ Tests/Manual/CPTextField/index.html | 79 +++++++++ Tests/Manual/CPTextField/main.j | 18 ++ 8 files changed, 446 insertions(+), 72 deletions(-) create mode 100644 Tests/Manual/CPTextField/AppController.j create mode 100644 Tests/Manual/CPTextField/Info.plist create mode 100644 Tests/Manual/CPTextField/Jakefile create mode 100644 Tests/Manual/CPTextField/Resources/spinner.gif create mode 100644 Tests/Manual/CPTextField/index-debug.html create mode 100644 Tests/Manual/CPTextField/index.html create mode 100644 Tests/Manual/CPTextField/main.j diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 6440017d5..489312f12 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -49,7 +49,7 @@ var CPTextFieldDOMInputElement = nil, CPTextFieldCachedSelectStartFunction = nil, CPTextFieldCachedDragFunction = nil, CPTextFieldBlurFunction = nil; - + #endif var CPSecureTextFieldCharacter = "\u2022"; @@ -82,13 +82,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); BOOL _isSecure; BOOL _drawsBackground; - + CPColor _textFieldBackgroundColor; - + id _placeholderString; - + id _delegate; - + CPString _textDidChangeValue; // NS-style Display Properties @@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); } CPTextFieldHandleBlur = function(anEvent) - { + { CPTextFieldInputOwner = nil; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; @@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); //FIXME make this not onblur CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction; - + CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement; } - + if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature)) { if ([self isSecure]) @@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction; } - + CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement; } else { CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement; } - + return CPTextFieldDOMInputElement; } #endif @@ -262,18 +262,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; } - + return self; } #pragma mark Controlling Editability and Selectability -/*! - Sets whether or not the receiver text field can be edited +/*! + Sets whether or not the receiver text field can be edited. If NO, any + ongoing edit is ended. */ - (void)setEditable:(BOOL)shouldBeEditable { + if (_isEditable === shouldBeEditable) + return; + _isEditable = shouldBeEditable; + // We only allow first responder status if the field is editable and enabled. + if (!shouldBeEditable && [[self window] firstResponder] === self) + [[self window] makeFirstResponder:nil]; } /*! @@ -284,6 +291,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); return _isEditable; } +/*! + Sets whether the field reacts to events. If NO, any ongoing edit is + ended. +*/ +- (void)setEnabled:(BOOL)shouldBeEnabled +{ + [super setEnabled:shouldBeEnabled]; + + // We only allow first responder status if the field is editable and enabled. + if (!shouldBeEnabled && [[self window] firstResponder] === self) + [[self window] makeFirstResponder:nil]; +} + /*! Sets whether the field's text is selectable by the user. @param aFlag \c YES makes the text selectable @@ -346,7 +366,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle { var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel; - + if (shouldBeRounded) [self setThemeState:CPTextFieldStateRounded]; else @@ -392,9 +412,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if (_drawsBackground == shouldDrawBackground) return; - + _drawsBackground = shouldDrawBackground; - + [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -415,9 +435,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if (_textFieldBackgroundColor == aColor) return; - + _textFieldBackgroundColor = aColor; - + [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -480,24 +500,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); _DOMElement.appendChild(element); - window.setTimeout(function() - { + window.setTimeout(function() + { element.focus(); [self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]]; CPTextFieldInputOwner = self; }, 0.0); - + element.value = [self stringValue]; [[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; - + CPTextFieldInputIsActive = YES; if (document.attachEvent) { CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart; CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag; - + [[self window] platformWindow]._DOMBodyElement.ondrag = function () {}; [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {}; } @@ -523,10 +543,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPTextFieldInputResigning = YES; element.blur(); - + if (!CPTextFieldInputDidBlur) CPTextFieldBlurFunction(); - + CPTextFieldInputDidBlur = NO; CPTextFieldInputResigning = NO; @@ -536,14 +556,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); CPTextFieldInputIsActive = NO; if (document.attachEvent) - { + { [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction; [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; CPTextFieldCachedSelectStartFunction = nil; CPTextFieldCachedDragFunction = nil; } - + #endif //post CPControlTextDidEndEditingNotification @@ -580,7 +600,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart; CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag; - + [[self window] platformWindow]._DOMBodyElement.ondrag = function () {}; [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {}; } @@ -599,7 +619,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); if (document.attachEvent) { [[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction; - [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; + [[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction; CPTextFieldCachedSelectStartFunction = nil CPTextFieldCachedDragFunction = nil; @@ -709,7 +729,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)setObjectValue:(id)aValue { [super setObjectValue:aValue]; - + #if PLATFORM(DOM) if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self) @@ -737,7 +757,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if (_placeholderString === aStringValue) return; - + _placeholderString = aStringValue; // Only update things if we need to show the placeholder @@ -758,17 +778,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); /*! Size to fit has two behavior, depending on if the receiver is an editable text field or not. - - For non-editable text fields (typically, a label), sizeToFit will change the frame of the + + For non-editable text fields (typically, a label), sizeToFit will change the frame of the receiver to perfectly fit the current text in stringValue in the current font, and respecting the current theme values for content-inset, min-size, and max-size. - - For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not - change the width of the text field. You can use setFrameSize: with the current height to set the - width, and you can get the size of a string with [CPString sizeWithFont:]. - + + For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not + change the width of the text field. You can use setFrameSize: with the current height to set the + width, and you can get the size of a string with [CPString sizeWithFont:]. + The logic behind this decision is that most of the time you do not know what content will be placed - in an editable text field, so you want to just choose a fixed width and leave it at that size. + in an editable text field, so you want to just choose a fixed width and leave it at that size. However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be useful for making the textfield an appropriate height. */ @@ -802,7 +822,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { #if PLATFORM(DOM) var element = [self _inputElement]; - + if (([self isEditable] || [self isSelectable])) { if ([[self window] firstResponder] === self) @@ -867,14 +887,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); return CPMakeRange(0, 0); // we wrap this in try catch because firefox will throw an exception in certain instances - try + try { var inputElement = [self _inputElement], selectionStart = inputElement.selectionStart, selectionEnd = inputElement.selectionEnd; if ([selectionStart isKindOfClass:CPNumber]) - return CPMakeRange(selectionStart, selectionEnd - selectionStart); + return CPMakeRange(selectionStart, selectionEnd - selectionStart); // browsers which don't support selectionStart/selectionEnd (aka IE). var theDocument = inputElement.ownerDocument || inputElement.document, @@ -886,8 +906,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); range.setEndPoint('EndToStart', selectionRange); return CPMakeRange(range.text.length, selectionRange.text.length); } - } - catch (e) + } + catch (e) { // fall through to the return } @@ -902,7 +922,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); var inputElement = [self _inputElement]; - try + try { if ([inputElement.selectionStart isKindOfClass:CPNumber]) { @@ -915,7 +935,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); var theDocument = inputElement.ownerDocument || inputElement.document, existingRange = theDocument.selection.createRange(), range = inputElement.createTextRange(); - + if (range.inRange(existingRange)) { range.collapse(true); @@ -950,7 +970,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (void)setDelegate:(id)aDelegate { var defaultCenter = [CPNotificationCenter defaultCenter]; - + //unsubscribe the existing delegate if it exists if (_delegate) { @@ -960,24 +980,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self]; [defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self]; } - + _delegate = aDelegate; - + if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)]) [defaultCenter addObserver:_delegate selector:@selector(controlTextDidBeginEditing:) name:CPControlTextDidBeginEditingNotification object:self]; - + if ([_delegate respondsToSelector:@selector(controlTextDidChange:)]) [defaultCenter addObserver:_delegate selector:@selector(controlTextDidChange:) name:CPControlTextDidChangeNotification object:self]; - - + + if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)]) [defaultCenter addObserver:_delegate @@ -1008,15 +1028,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); - (CGRect)contentRectForBounds:(CGRect)bounds { var contentInset = [self currentValueForThemeAttribute:@"content-inset"]; - + if (!contentInset) return bounds; - + bounds.origin.x += contentInset.left; bounds.origin.y += contentInset.top; bounds.size.width -= contentInset.left + contentInset.right; bounds.size.height -= contentInset.top + contentInset.bottom; - + return bounds; } @@ -1026,12 +1046,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); if (_CGInsetIsEmpty(bezelInset)) return bounds; - + bounds.origin.x += bezelInset.left; bounds.origin.y += bezelInset.top; bounds.size.width -= bezelInset.left + bezelInset.right; bounds.size.height -= bezelInset.top + bezelInset.bottom; - + return bounds; } @@ -1039,10 +1059,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if (aName === "bezel-view") return [self bezelRectForBounds:[self bounds]]; - + else if (aName === "content-view") return [self contentRectForBounds:[self bounds]]; - + return [super rectForEphemeralSubviewNamed:aName]; } @@ -1053,19 +1073,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; [view setHitTests:NO]; - + return view; } else { var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; //[view setImagePosition:CPNoImage]; - + [view setHitTests:NO]; - + return view; } - + return [super createEphemeralSubviewNamed:aName]; } @@ -1074,10 +1094,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view" positioned:CPWindowBelow relativeToEphemeralSubviewNamed:@"content-view"]; - + if (bezelView) [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]]; - + var contentView = [self layoutEphemeralSubviewNamed:@"content-view" positioned:CPWindowAbove relativeToEphemeralSubviewNamed:@"bezel-view"]; @@ -1087,7 +1107,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); [contentView setHidden:[self hasThemeState:CPThemeStateEditing]]; var string = ""; - + if ([self hasThemeState:CPTextFieldStatePlaceholder]) string = [self placeholderString]; else @@ -1158,7 +1178,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - + if (self) { [self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]]; @@ -1170,7 +1190,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", [self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]]; } - + return self; } @@ -1181,14 +1201,14 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", - (void)encodeWithCoder:(CPCoder)aCoder { [super encodeWithCoder:aCoder]; - + [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey]; [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey]; - + [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey]; - + [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey]; - + [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey]; } diff --git a/Tests/Manual/CPTextField/AppController.j b/Tests/Manual/CPTextField/AppController.j new file mode 100644 index 000000000..56c081216 --- /dev/null +++ b/Tests/Manual/CPTextField/AppController.j @@ -0,0 +1,48 @@ +/* + * AppController.j + * CPTextField + * + * Created by Alexander Ljungberg on August 2, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var textField = [CPTextField textFieldWithStringValue:"" placeholder:"Edit me!" width:200], + label = [[CPTextField alloc] initWithFrame:CGRectMake(15, 15, 400, 24)]; + + [label setStringValue:"Edit and hit enter: editing should end."]; + [contentView addSubview:label]; + + [textField setFrameOrigin:CGPointMake(15, 35)]; + + [textField setEditable:YES]; + [textField setPlaceholderString:"Edit me!"]; + + [textField setTarget:self]; + [textField setAction:@selector(textAction:)]; + + [contentView addSubview:textField]; + + [theWindow orderFront:self]; + + // Uncomment the following line to turn on the standard menu bar. + //[CPMenu setMenuBarVisible:YES]; +} + +- (void)textAction:(id)sender +{ + [sender setEditable:NO]; +} + +@end diff --git a/Tests/Manual/CPTextField/Info.plist b/Tests/Manual/CPTextField/Info.plist new file mode 100644 index 000000000..bdb30d0ef --- /dev/null +++ b/Tests/Manual/CPTextField/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + CPTextField + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/CPTextField/Jakefile b/Tests/Manual/CPTextField/Jakefile new file mode 100644 index 000000000..bf53a9a61 --- /dev/null +++ b/Tests/Manual/CPTextField/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * CPTextField + * + * Created by Alexander Ljungberg on August 2, 2010. + * Copyright 2010, WireLoad, LLC 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 ("CPTextField", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "CPTextField.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPTextField"); + task.setIdentifier("com.yourcompany.CPTextField"); + task.setVersion("1.0"); + task.setAuthor("WireLoad, LLC"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPTextField"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["CPTextField"], 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", "CPTextField", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "CPTextField", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "CPTextField")); + OS.system(["press", "-f", FILE.join("Build", "Release", "CPTextField"), FILE.join("Build", "Deployment", "CPTextField")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "CPTextField")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPTextField"), FILE.join("Build", "Desktop", "CPTextField", "CPTextField.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "CPTextField", "CPTextField.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPTextField")); + print("----------------------------"); +} diff --git a/Tests/Manual/CPTextField/Resources/spinner.gif b/Tests/Manual/CPTextField/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/CPTextField/index-debug.html b/Tests/Manual/CPTextField/index-debug.html new file mode 100644 index 000000000..75231a8b1 --- /dev/null +++ b/Tests/Manual/CPTextField/index-debug.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + CPTextField + + + + + + + + + + + + + + +

+
+ + + +
+
+ + + diff --git a/Tests/Manual/CPTextField/index.html b/Tests/Manual/CPTextField/index.html new file mode 100644 index 000000000..0982d7110 --- /dev/null +++ b/Tests/Manual/CPTextField/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + CPTextField + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/CPTextField/main.j b/Tests/Manual/CPTextField/main.j new file mode 100644 index 000000000..66b702a49 --- /dev/null +++ b/Tests/Manual/CPTextField/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CPTextField + * + * Created by Alexander Ljungberg on August 2, 2010. + * Copyright 2010, WireLoad, LLC All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} From 8c13204afab7e6cf1d666a1ce70e15fbe8d6eef4 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 2 Aug 2010 23:28:40 -0400 Subject: [PATCH 154/356] Save some memory and time in CPTableViewFirstColumnOnlyAutoresizingStyle mode. --- AppKit/CPTableView.j | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index f89c060fc..f41462277 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1442,31 +1442,30 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!superview) return; - var superviewSize = [superview bounds].size; - UPDATE_COLUMN_RANGES_IF_NECESSARY(); var count = NUMBER_OF_COLUMNS(), - visColumns = [[CPArray alloc] init], + columnToResize = nil, totalWidth = 0, i = 0; - for(; i < count; i++) + for (; i < count; i++) { - if(![_tableColumns[i] isHidden]) + var column = _tableColumns[i]; + + if (![column isHidden]) { - [visColumns addObject:i]; - totalWidth += [_tableColumns[i] width] + _intercellSpacing.width; + if (!columnToResize) + columnToResize = column; + totalWidth += [column width] + _intercellSpacing.width; } } - count = [visColumns count]; - - //if there are rows - if (count > 0) + // If there is a visible column + if (columnToResize) { - var columnToResize = _tableColumns[visColumns[0]], - newWidth = superviewSize.width - totalWidth;// - [columnToResize width]; + var superviewSize = [superview bounds].size, + newWidth = superviewSize.width - totalWidth; newWidth += [columnToResize width]; newWidth = MAX([columnToResize minWidth], newWidth); From 4ea0d4d043222ce366d256bcfa374633afa0f594 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 4 Aug 2010 16:43:04 -0400 Subject: [PATCH 155/356] CPNull is equal to CPNull. Unit test included. --- Foundation/CPNull.j | 9 +++++++++ Tests/Foundation/CPNullTest.j | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/Foundation/CPNull.j b/Foundation/CPNull.j index 0eaca5773..2c267dcb8 100644 --- a/Foundation/CPNull.j +++ b/Foundation/CPNull.j @@ -44,6 +44,7 @@ var CPNullSharedNull = nil; return [super alloc]; }*/ + /*! Returns the singleton instance of the CPNull object. While CPNull and \c nil should @@ -57,6 +58,14 @@ var CPNullSharedNull = nil; return CPNullSharedNull; } +- (BOOL)isEqual:(id)anObject +{ + if (self === anObject) + return YES; + + return [anObject isKindOfClass:[CPNull class]]; +} + /*! Returns CPNull null. @param aCoder the coder from which to do nothing diff --git a/Tests/Foundation/CPNullTest.j b/Tests/Foundation/CPNullTest.j index 7b99a14a2..92c9cd8b7 100644 --- a/Tests/Foundation/CPNullTest.j +++ b/Tests/Foundation/CPNullTest.j @@ -4,6 +4,12 @@ @implementation CPNullTest : OJTestCase +- (void)testEquals +{ + [self assert:[CPNull null] equals:[CPNull null] message:"CPNull null should equal itself."]; + [self assert:[CPNull null] equals:[CPNull new] message:"CPNull null should equal another CPNull."]; +} + - (void)testArchiving { [self assert:[CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:[CPNull null]]] equals:[CPNull null]]; From bfbf8fb841c63fe0bdaf8de98f77c12181137caf Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 13 Oct 2009 02:09:03 +0200 Subject: [PATCH 156/356] Support for diacritics aware strings comparison --- Foundation/CPString.j | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Foundation/CPString.j b/Foundation/CPString.j index 877604f4c..cb5b23917 100644 --- a/Foundation/CPString.j +++ b/Foundation/CPString.j @@ -55,6 +55,12 @@ CPAnchoredSearch = 8; @class CPString */ CPNumericSearch = 64; +/*! + Search ignores diacritic marks. + @global + @class CPString +*/ +CPDiacriticInsensitiveSearch = 128; var CPStringUIDs = new CFMutableDictionary(); @@ -469,6 +475,12 @@ var CPStringRegexSpecialCharacters = [ rhs = rhs.toLowerCase(); } + if(aMask & CPDiacriticInsensitiveSearch) + { + lhs = lhs.stripDiacritics(); + rhs = rhs.stripDiacritics(); + } + if (lhs < rhs) return CPOrderedAscending; else if (lhs > rhs) @@ -783,4 +795,31 @@ var CPStringRegexSpecialCharacters = [ @end +var diacritics = [[192,198],[224,230],[231,231],[232,235],[236,239],[242,246],[249,252]]; // Basic Latin ; Latin-1 Supplement. +var normalized = [65,97,99,101,105,111,117]; + +String.prototype.stripDiacritics = function () +{ + var output = ""; + for (var indexSource = 0; indexSource < this.length; indexSource++) + { + var code = this.charCodeAt(indexSource); + + for (var i = 0; i < diacritics.length; i++) + { + var drange = diacritics[i]; + + if (code >= drange[0] && code <= drange[drange.length-1]) + { + code = normalized[i]; + break; + } + } + + output += String.fromCharCode(code); + } + + return output; +} + String.prototype.isa = CPString; From 7187ba30748946faf071f75fb2defcfd3ae4bc1f Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 13 Oct 2009 02:37:10 +0200 Subject: [PATCH 157/356] CPCharacterSet implementation --- Foundation/CPCharacterSet.j | 2926 +++++++++++++++++++++++++++++++++++ Foundation/Foundation.j | 1 + 2 files changed, 2927 insertions(+) create mode 100644 Foundation/CPCharacterSet.j diff --git a/Foundation/CPCharacterSet.j b/Foundation/CPCharacterSet.j new file mode 100644 index 000000000..a087a39c8 --- /dev/null +++ b/Foundation/CPCharacterSet.j @@ -0,0 +1,2926 @@ +// CPCharacterSet.j +// © Emanuele Vulcano, 2008. +// +// Licensed under the terms of Cappuccino's license +// (the GNU Lesser General Public License, version 2.1). +// Please see Cappuccino's LICENSE file for details. + +@import + +// CPCharacterSet is a class cluster. Concrete implementations +// follow after the main abstract class. + +var _builtInCharacterSets = {}; + +@implementation CPCharacterSet : CPObject +{ + BOOL _inverted; +} + +// Missing methods +/* +- (BOOL)isSupersetOfSet:(CPCharacterSet)theOtherSet{} ++ (id)characterSetWithBitmapRepresentation:(CPData)data{} ++ (id)characterSetWithContentsOfFile:(CPString)path{} +- (CPData)bitmapRepresentation{} + +- (void)formIntersectionWithCharacterSet:(CPCharacterSet)otherSet +- (void)formUnionWithCharacterSet:(CPCharacterSet)otherSet +- (void)removeCharactersInRange:(CPRange)aRange +- (void)removeCharactersInString:(CPString)aString +*/ + +- (id)init +{ + self = [super init]; + _inverted = NO; + + return self; +} + +- (void)invert +{ + _inverted = !_inverted; +} + +- (BOOL)characterIsMember:(CPString)aCharacter +{ + // IMPLEMENTED BY SUBCLASSES +} + +- (BOOL)hasMemberInPlane:(int)aPlane +{ + // IMPLEMENTED BY SUBCLASSES +} + ++ (id)characterSetWithCharactersInString:(CPString)aString +{ + return [[_CPStringContentCharacterSet alloc] initWithString:aString]; +} + ++ (id)characterSetWithRange:(CPRange)aRange +{ + return [[_CPRangeCharacterSet alloc] initWithRange:aRange]; +} + ++ (id)alphanumericCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)controlCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)decimalDigitCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)decomposableCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)illegalCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)letterCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)lowercaseLetterCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)nonBaseCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)punctuationCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)uppercaseLetterCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)whitespaceAndNewlineCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + ++ (id)whitespaceCharacterSet +{ + return [CPCharacterSet _sharedCharacterSetWithName:_cmd]; +} + +// private methods ++ (id)_sharedCharacterSetWithName:(id)csname +{ + var cs = _builtInCharacterSets[csname]; + if(cs == nil) + { + var i, + ranges = [CPArray array], + rangeArray = eval(csname); + + for(i = 0; i < rangeArray.length; i+= 2) + { + var loc = rangeArray[i]; + var length = rangeArray[i+1]; + var range = CPMakeRange(loc,length); + [ranges addObject:range]; + } + cs = [[_CPRangeCharacterSet alloc] initWithRanges:ranges]; + _builtInCharacterSets[csname] = cs; + } + + return cs; +} + +- (void)_setInverted:flag +{ + _inverted = flag; +} + +@end + +// A character set that stores a list of ranges of +// acceptable characters. +@implementation _CPRangeCharacterSet : CPCharacterSet +{ + CPArray _ranges; +} + +// Creates a range character set with a single range. +- (id)initWithRange:(CPRange)r +{ + return [self initWithRanges:[CPArray arrayWithObject:r]]; +} + +// Creates a range character set with multiple ranges. +- (id)initWithRanges:(CPArray)ranges +{ + if (self = [super init]) + { + _ranges = ranges; + } + + return self; +} + +- (id)copy +{ + var set = [[_CPRangeCharacterSet alloc] initWithRanges:_ranges]; + [set _setInverted:_inverted]; + return set; +} + +- (id)invertedSet +{ + var set = [[_CPRangeCharacterSet alloc] initWithRanges:_ranges]; + [set invert]; + return set; +} + +- (BOOL)characterIsMember:(CPString)aCharacter +{ + c = aCharacter.charCodeAt(0); + var enu = [_ranges objectEnumerator]; + var range; + + while (range = [enu nextObject]) + { + if (CPLocationInRange(c, range)) + return !_inverted; + } + + return _inverted; +} + +- (BOOL)hasMemberInPlane:(int)plane // TO DO : when inverted +{ + // the highest Unicode plane we reach. + // (There are 65536 code points in each plane.) + var maxPlane = Math.floor((range.start + range.length - 1) / 65536); // should iterate _ranges + + return (plane <= maxPlane); +} + +- (void)addCharactersInRange:(CPRange)aRange // Needs _inverted support +{ + [_ranges addObject:aRange]; +} + +- (void)addCharactersInString:(CPString)aString // Needs _inverted support +{ + var i; + + for(i = 0; i < aString.length; i++) + { + var code = aString.charCodeAt(i); + var range = CPMakeRange(code,1); + + [_ranges addObject:range]; + } +} + +@end + +// A character set that scans a string's contents for +// acceptable characters. +@implementation _CPStringContentCharacterSet : CPCharacterSet +{ + CPString _string; +} + +- (id)initWithString:(CPString)s +{ + if (self = [super init]) + { + _string = s; + } + + return self; +} + +- (id)copy +{ + var set = [[_CPStringContentCharacterSet alloc] initWithString:_string]; + [set _setInverted:_inverted]; + + return set; +} + +-(id)invertedSet +{ + var set = [[_CPStringContentCharacterSet alloc] initWithString:_string]; + [set invert]; + + return set; +} + +- (BOOL)characterIsMember:(CPString)c +{ + return (_string.indexOf(c.charAt(0)) != -1) == !_inverted; +} + +- (CPString)description +{ + return [super description] + " { string = '" + _string + "'}"; +} + +- (BOOL)hasMemberInPlane:(int)plane +{ + // JavaScript strings can only return char codes + // up to 0xFFFF (per the ECMA standard), so + // they all live in the Basic Multilingual Plane + // (aka plane 0). + // TODO if the above is wrong, this must be changed! + + return plane == 0; +} + +- (void)addCharactersInRange:(CPRange)aRange // Needs _inverted support +{ + var i; + for(i = aRange.location; i < aRange.location + aRange.length; i++) + { + var s = String.fromCharCode(i); + + if (![self characterIsMember:s]) + _string = [_string stringByAppendingString:s]; + } +} + +- (void)addCharactersInString:(CPString)aString // Needs _inverted support +{ + var i; + + for(i = 0; i < aString.length; i++) + { + var s = aString.charAt(i); + + if (![self characterIsMember:s]) + _string = [_string stringByAppendingString:s]; + } +} + +@end + +_CPCharacterSetTrimAtBeginning = 1 << 1; +_CPCharacterSetTrimAtEnd = 1 << 2; + +@implementation CPString (CPCharacterSetAdditions) + +// As per the Cocoa method. +- (id)stringByTrimmingCharactersInSet:(CPCharacterSet)set +{ + return [self _stringByTrimmingCharactersInSet:set options:_CPCharacterSetTrimAtBeginning | _CPCharacterSetTrimAtEnd]; +} + +// private method evilness! +// CPScanner's scanUpToString:... methods rely on this +// method being present. +- (id)_stringByTrimmingCharactersInSet:(CPCharacterSet)set options:(int)options +{ + var str = self; + + if (options & _CPCharacterSetTrimAtBeginning) + { + var cutEdgeBeginning = 0; + + while (cutEdgeBeginning < self.length && [set characterIsMember:self.charAt(cutEdgeBeginning)]) + cutEdgeBeginning++; + + str = str.substr(cutEdgeBeginning); + } + + if (options & _CPCharacterSetTrimAtEnd) + { + var cutEdgeEnd = str.length; + + while (cutEdgeEnd > 0 && [set characterIsMember:self.charAt(cutEdgeEnd)]) + cutEdgeEnd--; + + str = str.substr(0, cutEdgeEnd + 1); + } + + return str; +} + +@end + +alphanumericCharacterSet = [ +48,10, +65,26, +97,26, +170,1, +178,2, +181,1, +185,2, +188,3, +192,23, +216,31, +248,458, +710,12, +736,5, +750,1, +768,112, +890,4, +902,1, +904,3, +908,1, +910,20, +931,44, +976,38, +1015,139, +1155,4, +1160,140, +1329,38, +1369,1, +1377,39, +1425,45, +1471,1, +1473,2, +1476,2, +1479,1, +1488,27, +1520,3, +1552,6, +1569,26, +1600,31, +1632,10, +1646,102, +1749,8, +1758,11, +1770,19, +1791,1, +1808,59, +1869,33, +1920,50, +1984,54, +2042,1, +2305,57, +2364,18, +2384,5, +2392,12, +2406,10, +2427,5, +2433,3, +2437,8, +2447,2, +2451,22, +2474,7, +2482,1, +2486,4, +2492,9, +2503,2, +2507,4, +2519,1, +2524,2, +2527,5, +2534,12, +2548,6, +2561,3, +2565,6, +2575,2, +2579,22, +2602,7, +2610,2, +2613,2, +2616,2, +2620,1, +2622,5, +2631,2, +2635,3, +2649,4, +2654,1, +2662,15, +2689,3, +2693,9, +2703,3, +2707,22, +2730,7, +2738,2, +2741,5, +2748,10, +2759,3, +2763,3, +2768,1, +2784,4, +2790,10, +2817,3, +2821,8, +2831,2, +2835,22, +2858,7, +2866,2, +2869,5, +2876,8, +2887,2, +2891,3, +2902,2, +2908,2, +2911,3, +2918,10, +2929,1, +2946,2, +2949,6, +2958,3, +2962,4, +2969,2, +2972,1, +2974,2, +2979,2, +2984,3, +2990,12, +3006,5, +3014,3, +3018,4, +3031,1, +3046,13, +3073,3, +3077,8, +3086,3, +3090,23, +3114,10, +3125,5, +3134,7, +3142,3, +3146,4, +3157,2, +3168,2, +3174,10, +3202,2, +3205,8, +3214,3, +3218,23, +3242,10, +3253,5, +3260,9, +3270,3, +3274,4, +3285,2, +3294,1, +3296,4, +3302,10, +3330,2, +3333,8, +3342,3, +3346,23, +3370,16, +3390,6, +3398,3, +3402,4, +3415,1, +3424,2, +3430,10, +3458,2, +3461,18, +3482,24, +3507,9, +3517,1, +3520,7, +3530,1, +3535,6, +3542,1, +3544,8, +3570,2, +3585,58, +3648,15, +3664,10, +3713,2, +3716,1, +3719,2, +3722,1, +3725,1, +3732,4, +3737,7, +3745,3, +3749,1, +3751,1, +3754,2, +3757,13, +3771,3, +3776,5, +3782,1, +3784,6, +3792,10, +3804,2, +3840,1, +3864,2, +3872,20, +3893,1, +3895,1, +3897,1, +3902,10, +3913,34, +3953,20, +3974,6, +3984,8, +3993,36, +4038,1, +4096,34, +4131,5, +4137,2, +4140,7, +4150,4, +4160,10, +4176,10, +4256,38, +4304,43, +4348,1, +4352,90, +4447,68, +4520,82, +4608,73, +4682,4, +4688,7, +4696,1, +4698,4, +4704,41, +4746,4, +4752,33, +4786,4, +4792,7, +4800,1, +4802,4, +4808,15, +4824,57, +4882,4, +4888,67, +4959,1, +4969,20, +4992,16, +5024,85, +5121,620, +5743,8, +5761,26, +5792,75, +5870,3, +5888,13, +5902,7, +5920,21, +5952,20, +5984,13, +5998,3, +6002,2, +6016,52, +6070,30, +6103,1, +6108,2, +6112,10, +6128,10, +6155,3, +6160,10, +6176,88, +6272,42, +6400,29, +6432,12, +6448,12, +6470,40, +6512,5, +6528,42, +6576,26, +6608,10, +6656,28, +6912,76, +6992,10, +7019,9, +7424,203, +7678,158, +7840,90, +7936,22, +7960,6, +7968,38, +8008,6, +8016,8, +8025,1, +8027,1, +8029,1, +8031,31, +8064,53, +8118,7, +8126,1, +8130,3, +8134,7, +8144,4, +8150,6, +8160,13, +8178,3, +8182,7, +8304,2, +8308,6, +8319,11, +8336,5, +8400,32, +8450,1, +8455,1, +8458,10, +8469,1, +8473,5, +8484,1, +8486,1, +8488,1, +8490,4, +8495,11, +8508,4, +8517,5, +8526,1, +8531,50, +9312,60, +9450,22, +10102,30, +11264,47, +11312,47, +11360,13, +11380,4, +11392,101, +11517,1, +11520,38, +11568,54, +11631,1, +11648,23, +11680,7, +11688,7, +11696,7, +11704,7, +11712,7, +11720,7, +11728,7, +11736,7, +12293,3, +12321,15, +12337,5, +12344,5, +12353,86, +12441,2, +12445,3, +12449,90, +12540,4, +12549,40, +12593,94, +12690,4, +12704,24, +12784,16, +12832,10, +12881,15, +12928,10, +12977,15, +13312,6582, +19968,20924, +40960,1165, +42775,4, +43008,40, +43072,52, +44032,11172, +63744,302, +64048,59, +64112,106, +64256,7, +64275,5, +64285,12, +64298,13, +64312,5, +64318,1, +64320,2, +64323,2, +64326,108, +64467,363, +64848,64, +64914,54, +65008,12, +65024,16, +65056,4, +65136,5, +65142,135, +65296,10, +65313,26, +65345,26, +65382,89, +65474,6, +65482,6, +65490,6 +]; + +controlCharacterSet = [ +0,32, +127,33, +173,1, +1536,4, +1757,1, +1807,1, +6068,2, +8203,5, +8234,5, +8288,4, +8298,6, +65279,1 +]; + +decimalDigitCharacterSet = [ +48,10, +1632,10, +1776,10, +1984,10, +2406,10, +2534,10, +2662,10, +2790,10, +2918,10, +3046,10, +3174,10, +3302,10, +3430,10, +3664,10, +3792,10, +3872,10, +4160,10, +6112,10, +6160,10, +6470,10, +6608,10, +6992,10 +]; + +decomposableCharacterSet = [ +192,6, +199,9, +209,6, +217,5, +224,6, +231,9, +241,6, +249,5, +255,17, +274,20, +296,9, +308,4, +313,6, +323,6, +332,6, +340,18, +360,23, +416,2, +431,2, +461,16, +478,6, +486,11, +500,2, +504,36, +542,2, +550,14, +832,2, +835,2, +884,1, +894,1, +901,6, +908,1, +910,3, +938,7, +970,5, +979,2, +1024,2, +1027,1, +1031,1, +1036,3, +1049,1, +1081,1, +1104,2, +1107,1, +1111,1, +1116,3, +1142,2, +1217,2, +1232,4, +1238,2, +1242,6, +1250,6, +1258,12, +1272,2, +1570,5, +1728,1, +1730,1, +1747,1, +2345,1, +2353,1, +2356,1, +2392,8, +2507,2, +2524,2, +2527,1, +2611,1, +2614,1, +2649,3, +2654,1, +2888,1, +2891,2, +2908,2, +2964,1, +3018,3, +3144,1, +3264,1, +3271,2, +3274,2, +3402,3, +3546,1, +3548,3, +3907,1, +3917,1, +3922,1, +3927,1, +3932,1, +3945,1, +3955,1, +3957,2, +3960,1, +3969,1, +3987,1, +3997,1, +4002,1, +4007,1, +4012,1, +4025,1, +4134,1, +6918,1, +6920,1, +6922,1, +6924,1, +6926,1, +6930,1, +6971,1, +6973,1, +6976,2, +6979,1, +7680,154, +7835,1, +7840,90, +7936,22, +7960,6, +7968,38, +8008,6, +8016,8, +8025,1, +8027,1, +8029,1, +8031,31, +8064,53, +8118,7, +8126,1, +8129,4, +8134,14, +8150,6, +8157,19, +8178,3, +8182,8, +8192,2, +8486,1, +8490,2, +8602,2, +8622,1, +8653,3, +8708,1, +8713,1, +8716,1, +8740,1, +8742,1, +8769,1, +8772,1, +8775,1, +8777,1, +8800,1, +8802,1, +8813,5, +8820,2, +8824,2, +8832,2, +8836,2, +8840,2, +8876,4, +8928,4, +8938,4, +9001,2, +10972,1, +12364,1, +12366,1, +12368,1, +12370,1, +12372,1, +12374,1, +12376,1, +12378,1, +12380,1, +12382,1, +12384,1, +12386,1, +12389,1, +12391,1, +12393,1, +12400,2, +12403,2, +12406,2, +12409,2, +12412,2, +12436,1, +12446,1, +12460,1, +12462,1, +12464,1, +12466,1, +12468,1, +12470,1, +12472,1, +12474,1, +12476,1, +12478,1, +12480,1, +12482,1, +12485,1, +12487,1, +12489,1, +12496,2, +12499,2, +12502,2, +12505,2, +12508,2, +12532,1, +12535,4, +12542,1, +44032,11172, +63744,270, +64016,1, +64018,1, +64021,10, +64032,1, +64034,1, +64037,2, +64042,4, +64048,59, +64112,106, +64285,1, +64287,1, +64298,13, +64312,5, +64318,1, +64320,2, +64323,2 +]; + +illegalCharacterSet = [ +880,4, +886,4, +895,5, +907,1, +909,1, +930,1, +975,1, +1159,1, +1300,29, +1367,2, +1376,1, +1416,1, +1419,6, +1480,8, +1515,5, +1525,11, +1540,7, +1558,5, +1564,2, +1568,1, +1595,5, +1631,1, +1806,1, +1867,2, +1902,18, +1970,14, +2043,262, +2362,2, +2382,2, +2389,3, +2417,10, +2432,1, +2436,1, +2445,2, +2449,2, +2473,1, +2481,1, +2483,3, +2490,2, +2501,2, +2505,2, +2511,8, +2520,4, +2526,1, +2532,2, +2555,6, +2564,1, +2571,4, +2577,2, +2601,1, +2609,1, +2612,1, +2615,1, +2618,2, +2621,1, +2627,4, +2633,2, +2638,11, +2653,1, +2655,7, +2677,12, +2692,1, +2702,1, +2706,1, +2729,1, +2737,1, +2740,1, +2746,2, +2758,1, +2762,1, +2766,2, +2769,15, +2788,2, +2800,1, +2802,15, +2820,1, +2829,2, +2833,2, +2857,1, +2865,1, +2868,1, +2874,2, +2884,3, +2889,2, +2894,8, +2904,4, +2910,1, +2914,4, +2930,16, +2948,1, +2955,3, +2961,1, +2966,3, +2971,1, +2973,1, +2976,3, +2981,3, +2987,3, +3002,4, +3011,3, +3017,1, +3022,9, +3032,14, +3067,6, +3076,1, +3085,1, +3089,1, +3113,1, +3124,1, +3130,4, +3141,1, +3145,1, +3150,7, +3159,9, +3170,4, +3184,18, +3204,1, +3213,1, +3217,1, +3241,1, +3252,1, +3258,2, +3269,1, +3273,1, +3278,7, +3287,7, +3295,1, +3300,2, +3312,1, +3315,15, +3332,1, +3341,1, +3345,1, +3369,1, +3386,4, +3396,2, +3401,1, +3406,9, +3416,8, +3426,4, +3440,18, +3460,1, +3479,3, +3506,1, +3516,1, +3518,2, +3527,3, +3531,4, +3541,1, +3543,1, +3552,18, +3573,12, +3643,4, +3676,37, +3715,1, +3717,2, +3721,1, +3723,2, +3726,6, +3736,1, +3744,1, +3748,1, +3750,1, +3752,2, +3756,1, +3770,1, +3774,2, +3781,1, +3783,1, +3790,2, +3802,2, +3806,34, +3912,1, +3947,6, +3980,4, +3992,1, +4029,1, +4045,2, +4050,46, +4130,1, +4136,1, +4139,1, +4147,3, +4154,6, +4186,70, +4294,10, +4349,3, +4442,5, +4515,5, +4602,6, +4681,1, +4686,2, +4695,1, +4697,1, +4702,2, +4745,1, +4750,2, +4785,1, +4790,2, +4799,1, +4801,1, +4806,2, +4823,1, +4881,1, +4886,2, +4955,4, +4989,3, +5018,6, +5109,12, +5751,9, +5789,3, +5873,15, +5901,1, +5909,11, +5943,9, +5972,12, +5997,1, +6001,1, +6004,12, +6110,2, +6122,6, +6138,6, +6159,1, +6170,6, +6264,8, +6314,86, +6429,3, +6444,4, +6460,4, +6465,3, +6510,2, +6517,11, +6570,6, +6602,6, +6618,4, +6684,2, +6688,224, +6988,4, +7037,387, +7627,51, +7836,4, +7930,6, +7958,2, +7966,2, +8006,2, +8014,2, +8024,1, +8026,1, +8028,1, +8030,1, +8062,2, +8117,1, +8133,1, +8148,2, +8156,1, +8176,2, +8181,1, +8191,1, +8292,6, +8306,2, +8335,1, +8341,11, +8374,26, +8432,16, +8527,4, +8581,11, +9192,24, +9255,25, +9291,21, +9885,3, +9907,78, +9989,1, +9994,2, +10024,1, +10060,1, +10062,1, +10067,3, +10071,1, +10079,2, +10133,3, +10160,1, +10175,1, +10187,5, +10220,4, +11035,5, +11044,220, +11311,1, +11359,1, +11373,7, +11384,8, +11499,14, +11558,10, +11622,9, +11632,16, +11671,9, +11687,1, +11695,1, +11703,1, +11711,1, +11719,1, +11727,1, +11735,1, +11743,33, +11800,4, +11806,98, +11930,1, +12020,12, +12246,26, +12284,4, +12352,1, +12439,2, +12544,5, +12589,4, +12687,1, +12728,8, +12752,32, +12831,1, +12868,12, +13055,1, +19894,10, +40892,68, +42125,3, +42183,569, +42779,5, +42786,222, +43052,20, +43128,904, +55204,92, +64046,2, +64107,5, +64218,38, +64263,12, +64280,5, +64311,1, +64317,1, +64319,1, +64322,1, +64325,1, +64434,33, +64832,16, +64912,2, +64968,40, +65022,2, +65050,6, +65060,12, +65107,1, +65127,1, +65132,4, +65141,1, +65277,2, +65280,1, +65471,3, +65480,2, +65488,2, +65496,2, +65501,3, +65511,1, +65519,10 +]; + +letterCharacterSet = [ +65,26, +97,26, +170,1, +181,1, +186,1, +192,23, +216,31, +248,458, +710,12, +736,5, +750,1, +768,112, +890,4, +902,1, +904,3, +908,1, +910,20, +931,44, +976,38, +1015,139, +1155,4, +1160,140, +1329,38, +1369,1, +1377,39, +1425,45, +1471,1, +1473,2, +1476,2, +1479,1, +1488,27, +1520,3, +1552,6, +1569,26, +1600,31, +1646,102, +1749,8, +1758,11, +1770,6, +1786,3, +1791,1, +1808,59, +1869,33, +1920,50, +1994,44, +2042,1, +2305,57, +2364,18, +2384,5, +2392,12, +2427,5, +2433,3, +2437,8, +2447,2, +2451,22, +2474,7, +2482,1, +2486,4, +2492,9, +2503,2, +2507,4, +2519,1, +2524,2, +2527,5, +2544,2, +2561,3, +2565,6, +2575,2, +2579,22, +2602,7, +2610,2, +2613,2, +2616,2, +2620,1, +2622,5, +2631,2, +2635,3, +2649,4, +2654,1, +2672,5, +2689,3, +2693,9, +2703,3, +2707,22, +2730,7, +2738,2, +2741,5, +2748,10, +2759,3, +2763,3, +2768,1, +2784,4, +2817,3, +2821,8, +2831,2, +2835,22, +2858,7, +2866,2, +2869,5, +2876,8, +2887,2, +2891,3, +2902,2, +2908,2, +2911,3, +2929,1, +2946,2, +2949,6, +2958,3, +2962,4, +2969,2, +2972,1, +2974,2, +2979,2, +2984,3, +2990,12, +3006,5, +3014,3, +3018,4, +3031,1, +3073,3, +3077,8, +3086,3, +3090,23, +3114,10, +3125,5, +3134,7, +3142,3, +3146,4, +3157,2, +3168,2, +3202,2, +3205,8, +3214,3, +3218,23, +3242,10, +3253,5, +3260,9, +3270,3, +3274,4, +3285,2, +3294,1, +3296,4, +3330,2, +3333,8, +3342,3, +3346,23, +3370,16, +3390,6, +3398,3, +3402,4, +3415,1, +3424,2, +3458,2, +3461,18, +3482,24, +3507,9, +3517,1, +3520,7, +3530,1, +3535,6, +3542,1, +3544,8, +3570,2, +3585,58, +3648,15, +3713,2, +3716,1, +3719,2, +3722,1, +3725,1, +3732,4, +3737,7, +3745,3, +3749,1, +3751,1, +3754,2, +3757,13, +3771,3, +3776,5, +3782,1, +3784,6, +3804,2, +3840,1, +3864,2, +3893,1, +3895,1, +3897,1, +3902,10, +3913,34, +3953,20, +3974,6, +3984,8, +3993,36, +4038,1, +4096,34, +4131,5, +4137,2, +4140,7, +4150,4, +4176,10, +4256,38, +4304,43, +4348,1, +4352,90, +4447,68, +4520,82, +4608,73, +4682,4, +4688,7, +4696,1, +4698,4, +4704,41, +4746,4, +4752,33, +4786,4, +4792,7, +4800,1, +4802,4, +4808,15, +4824,57, +4882,4, +4888,67, +4959,1, +4992,16, +5024,85, +5121,620, +5743,8, +5761,26, +5792,75, +5888,13, +5902,7, +5920,21, +5952,20, +5984,13, +5998,3, +6002,2, +6016,52, +6070,30, +6103,1, +6108,2, +6155,3, +6176,88, +6272,42, +6400,29, +6432,12, +6448,12, +6480,30, +6512,5, +6528,42, +6576,26, +6656,28, +6912,76, +7019,9, +7424,203, +7678,158, +7840,90, +7936,22, +7960,6, +7968,38, +8008,6, +8016,8, +8025,1, +8027,1, +8029,1, +8031,31, +8064,53, +8118,7, +8126,1, +8130,3, +8134,7, +8144,4, +8150,6, +8160,13, +8178,3, +8182,7, +8305,1, +8319,1, +8336,5, +8400,32, +8450,1, +8455,1, +8458,10, +8469,1, +8473,5, +8484,1, +8486,1, +8488,1, +8490,4, +8495,11, +8508,4, +8517,5, +8526,1, +8579,2, +11264,47, +11312,47, +11360,13, +11380,4, +11392,101, +11520,38, +11568,54, +11631,1, +11648,23, +11680,7, +11688,7, +11696,7, +11704,7, +11712,7, +11720,7, +11728,7, +11736,7, +12293,2, +12330,6, +12337,5, +12347,2, +12353,86, +12441,2, +12445,3, +12449,90, +12540,4, +12549,40, +12593,94, +12704,24, +12784,16, +13312,6582, +19968,20924, +40960,1165, +42775,4, +43008,40, +43072,52, +44032,11172, +63744,302, +64048,59, +64112,106, +64256,7, +64275,5, +64285,12, +64298,13, +64312,5, +64318,1, +64320,2, +64323,2, +64326,108, +64467,363, +64848,64, +64914,54, +65008,12, +65024,16, +65056,4, +65136,5, +65142,135, +65313,26, +65345,26, +65382,89, +65474,6, +65482,6, +65490,6 +]; + +lowercaseLetterCharacterSet = [ +97,26, +170,1, +181,1, +186,1, +223,24, +248,8, +257,1, +259,1, +261,1, +263,1, +265,1, +267,1, +269,1, +271,1, +273,1, +275,1, +277,1, +279,1, +281,1, +283,1, +285,1, +287,1, +289,1, +291,1, +293,1, +295,1, +297,1, +299,1, +301,1, +303,1, +305,1, +307,1, +309,1, +311,2, +314,1, +316,1, +318,1, +320,1, +322,1, +324,1, +326,1, +328,2, +331,1, +333,1, +335,1, +337,1, +339,1, +341,1, +343,1, +345,1, +347,1, +349,1, +351,1, +353,1, +355,1, +357,1, +359,1, +361,1, +363,1, +365,1, +367,1, +369,1, +371,1, +373,1, +375,1, +378,1, +380,1, +382,3, +387,1, +389,1, +392,1, +396,2, +402,1, +405,1, +409,3, +414,1, +417,1, +419,1, +421,1, +424,1, +426,2, +429,1, +432,1, +436,1, +438,1, +441,2, +445,3, +454,1, +457,1, +460,1, +462,1, +464,1, +466,1, +468,1, +470,1, +472,1, +474,1, +476,2, +479,1, +481,1, +483,1, +485,1, +487,1, +489,1, +491,1, +493,1, +495,2, +499,1, +501,1, +505,1, +507,1, +509,1, +511,1, +513,1, +515,1, +517,1, +519,1, +521,1, +523,1, +525,1, +527,1, +529,1, +531,1, +533,1, +535,1, +537,1, +539,1, +541,1, +543,1, +545,1, +547,1, +549,1, +551,1, +553,1, +555,1, +557,1, +559,1, +561,1, +563,7, +572,1, +575,2, +578,1, +583,1, +585,1, +587,1, +589,1, +591,69, +661,27, +891,3, +912,1, +940,35, +976,2, +981,3, +985,1, +987,1, +989,1, +991,1, +993,1, +995,1, +997,1, +999,1, +1001,1, +1003,1, +1005,1, +1007,5, +1013,1, +1016,1, +1019,2, +1072,48, +1121,1, +1123,1, +1125,1, +1127,1, +1129,1, +1131,1, +1133,1, +1135,1, +1137,1, +1139,1, +1141,1, +1143,1, +1145,1, +1147,1, +1149,1, +1151,1, +1153,1, +1163,1, +1165,1, +1167,1, +1169,1, +1171,1, +1173,1, +1175,1, +1177,1, +1179,1, +1181,1, +1183,1, +1185,1, +1187,1, +1189,1, +1191,1, +1193,1, +1195,1, +1197,1, +1199,1, +1201,1, +1203,1, +1205,1, +1207,1, +1209,1, +1211,1, +1213,1, +1215,1, +1218,1, +1220,1, +1222,1, +1224,1, +1226,1, +1228,1, +1230,2, +1233,1, +1235,1, +1237,1, +1239,1, +1241,1, +1243,1, +1245,1, +1247,1, +1249,1, +1251,1, +1253,1, +1255,1, +1257,1, +1259,1, +1261,1, +1263,1, +1265,1, +1267,1, +1269,1, +1271,1, +1273,1, +1275,1, +1277,1, +1279,1, +1281,1, +1283,1, +1285,1, +1287,1, +1289,1, +1291,1, +1293,1, +1295,1, +1297,1, +1299,1, +1377,39, +7424,44, +7522,22, +7545,34, +7681,1, +7683,1, +7685,1, +7687,1, +7689,1, +7691,1, +7693,1, +7695,1, +7697,1, +7699,1, +7701,1, +7703,1, +7705,1, +7707,1, +7709,1, +7711,1, +7713,1, +7715,1, +7717,1, +7719,1, +7721,1, +7723,1, +7725,1, +7727,1, +7729,1, +7731,1, +7733,1, +7735,1, +7737,1, +7739,1, +7741,1, +7743,1, +7745,1, +7747,1, +7749,1, +7751,1, +7753,1, +7755,1, +7757,1, +7759,1, +7761,1, +7763,1, +7765,1, +7767,1, +7769,1, +7771,1, +7773,1, +7775,1, +7777,1, +7779,1, +7781,1, +7783,1, +7785,1, +7787,1, +7789,1, +7791,1, +7793,1, +7795,1, +7797,1, +7799,1, +7801,1, +7803,1, +7805,1, +7807,1, +7809,1, +7811,1, +7813,1, +7815,1, +7817,1, +7819,1, +7821,1, +7823,1, +7825,1, +7827,1, +7829,7, +7841,1, +7843,1, +7845,1, +7847,1, +7849,1, +7851,1, +7853,1, +7855,1, +7857,1, +7859,1, +7861,1, +7863,1, +7865,1, +7867,1, +7869,1, +7871,1, +7873,1, +7875,1, +7877,1, +7879,1, +7881,1, +7883,1, +7885,1, +7887,1, +7889,1, +7891,1, +7893,1, +7895,1, +7897,1, +7899,1, +7901,1, +7903,1, +7905,1, +7907,1, +7909,1, +7911,1, +7913,1, +7915,1, +7917,1, +7919,1, +7921,1, +7923,1, +7925,1, +7927,1, +7929,1, +7936,8, +7952,6, +7968,8, +7984,8, +8000,6, +8016,8, +8032,8, +8048,14, +8064,8, +8080,8, +8096,8, +8112,5, +8118,2, +8126,1, +8130,3, +8134,2, +8144,4, +8150,2, +8160,8, +8178,3, +8182,2, +8305,1, +8319,1, +8458,1, +8462,2, +8467,1, +8495,1, +8500,1, +8505,1, +8508,2, +8518,4, +8526,1, +8580,1, +11312,47, +11361,1, +11365,2, +11368,1, +11370,1, +11372,1, +11380,1, +11382,2, +11393,1, +11395,1, +11397,1, +11399,1, +11401,1, +11403,1, +11405,1, +11407,1, +11409,1, +11411,1, +11413,1, +11415,1, +11417,1, +11419,1, +11421,1, +11423,1, +11425,1, +11427,1, +11429,1, +11431,1, +11433,1, +11435,1, +11437,1, +11439,1, +11441,1, +11443,1, +11445,1, +11447,1, +11449,1, +11451,1, +11453,1, +11455,1, +11457,1, +11459,1, +11461,1, +11463,1, +11465,1, +11467,1, +11469,1, +11471,1, +11473,1, +11475,1, +11477,1, +11479,1, +11481,1, +11483,1, +11485,1, +11487,1, +11489,1, +11491,2, +11520,38, +64256,7, +64275,5 +]; + +nonBaseCharacterSet = [ +768,112, +1155,4, +1160,2, +1425,45, +1471,1, +1473,2, +1476,2, +1479,1, +1552,6, +1611,20, +1648,1, +1750,7, +1758,7, +1767,2, +1770,4, +1809,1, +1840,27, +1958,11, +2027,9, +2305,3, +2364,1, +2366,16, +2385,4, +2402,2, +2433,3, +2492,1, +2494,7, +2503,2, +2507,3, +2519,1, +2530,2, +2561,3, +2620,1, +2622,5, +2631,2, +2635,3, +2672,2, +2689,3, +2748,1, +2750,8, +2759,3, +2763,3, +2786,2, +2817,3, +2876,1, +2878,6, +2887,2, +2891,3, +2902,2, +2946,1, +3006,5, +3014,3, +3018,4, +3031,1, +3073,3, +3134,7, +3142,3, +3146,4, +3157,2, +3202,2, +3260,1, +3262,7, +3270,3, +3274,4, +3285,2, +3298,2, +3330,2, +3390,6, +3398,3, +3402,4, +3415,1, +3458,2, +3530,1, +3535,6, +3542,1, +3544,8, +3570,2, +3633,1, +3636,7, +3655,8, +3761,1, +3764,6, +3771,2, +3784,6, +3864,2, +3893,1, +3895,1, +3897,1, +3902,2, +3953,20, +3974,2, +3984,8, +3993,36, +4038,1, +4140,7, +4150,4, +4182,4, +4959,1, +5906,3, +5938,3, +5970,2, +6002,2, +6070,30, +6109,1, +6155,3, +6313,1, +6432,12, +6448,12, +6576,17, +6600,2, +6679,5, +6912,5, +6964,17, +7019,9, +7616,11, +7678,2, +8400,32, +12330,6, +12441,2, +43010,1, +43014,1, +43019,1, +43043,5, +64286,1, +65024,16 +]; + +punctuationCharacterSet = [ +33,3, +37,6, +44,4, +58,2, +63,2, +91,3, +95,1, +123,1, +125,1, +161,1, +171,1, +183,1, +187,1, +191,1, +894,1, +903,1, +1370,6, +1417,2, +1470,1, +1472,1, +1475,1, +1478,1, +1523,2, +1548,2, +1563,1, +1566,2, +1642,4, +1748,1, +1792,14, +2039,3, +2404,2, +2416,1, +3572,1, +3663,1, +3674,2, +3844,15, +3898,4, +3973,1, +4048,2, +4170,6, +4347,1, +4961,8, +5741,2, +5787,2, +5867,3, +5941,2, +6100,3, +6104,3, +6144,11, +6468,2, +6622,2, +6686,2, +7002,7, +8208,24, +8240,20, +8261,13, +8275,12, +8317,2, +8333,2, +9001,2, +10088,14, +10181,2, +10214,6, +10627,22, +10712,4, +10748,2, +11513,4, +11518,2, +11776,24, +11804,2, +12289,3, +12296,10, +12308,12, +12336,1, +12349,1, +12448,1, +12539,1, +43124,4, +64830,2, +65040,10, +65072,35, +65108,14, +65123,1, +65128,1, +65130,2, +65281,3, +65285,6, +65292,4, +65306,2, +65311,2, +65339,3, +65343,1, +65371,1, +65373,1 +]; + +uppercaseLetterCharacterSet = [ +65,26, +192,23, +216,7, +256,1, +258,1, +260,1, +262,1, +264,1, +266,1, +268,1, +270,1, +272,1, +274,1, +276,1, +278,1, +280,1, +282,1, +284,1, +286,1, +288,1, +290,1, +292,1, +294,1, +296,1, +298,1, +300,1, +302,1, +304,1, +306,1, +308,1, +310,1, +313,1, +315,1, +317,1, +319,1, +321,1, +323,1, +325,1, +327,1, +330,1, +332,1, +334,1, +336,1, +338,1, +340,1, +342,1, +344,1, +346,1, +348,1, +350,1, +352,1, +354,1, +356,1, +358,1, +360,1, +362,1, +364,1, +366,1, +368,1, +370,1, +372,1, +374,1, +376,2, +379,1, +381,1, +385,2, +388,1, +390,2, +393,3, +398,4, +403,2, +406,3, +412,2, +415,2, +418,1, +420,1, +422,2, +425,1, +428,1, +430,2, +433,3, +437,1, +439,2, +444,1, +452,2, +455,2, +458,2, +461,1, +463,1, +465,1, +467,1, +469,1, +471,1, +473,1, +475,1, +478,1, +480,1, +482,1, +484,1, +486,1, +488,1, +490,1, +492,1, +494,1, +497,2, +500,1, +502,3, +506,1, +508,1, +510,1, +512,1, +514,1, +516,1, +518,1, +520,1, +522,1, +524,1, +526,1, +528,1, +530,1, +532,1, +534,1, +536,1, +538,1, +540,1, +542,1, +544,1, +546,1, +548,1, +550,1, +552,1, +554,1, +556,1, +558,1, +560,1, +562,1, +570,2, +573,2, +577,1, +579,4, +584,1, +586,1, +588,1, +590,1, +902,1, +904,3, +908,1, +910,2, +913,17, +931,9, +978,3, +984,1, +986,1, +988,1, +990,1, +992,1, +994,1, +996,1, +998,1, +1000,1, +1002,1, +1004,1, +1006,1, +1012,1, +1015,1, +1017,2, +1021,51, +1120,1, +1122,1, +1124,1, +1126,1, +1128,1, +1130,1, +1132,1, +1134,1, +1136,1, +1138,1, +1140,1, +1142,1, +1144,1, +1146,1, +1148,1, +1150,1, +1152,1, +1162,1, +1164,1, +1166,1, +1168,1, +1170,1, +1172,1, +1174,1, +1176,1, +1178,1, +1180,1, +1182,1, +1184,1, +1186,1, +1188,1, +1190,1, +1192,1, +1194,1, +1196,1, +1198,1, +1200,1, +1202,1, +1204,1, +1206,1, +1208,1, +1210,1, +1212,1, +1214,1, +1216,2, +1219,1, +1221,1, +1223,1, +1225,1, +1227,1, +1229,1, +1232,1, +1234,1, +1236,1, +1238,1, +1240,1, +1242,1, +1244,1, +1246,1, +1248,1, +1250,1, +1252,1, +1254,1, +1256,1, +1258,1, +1260,1, +1262,1, +1264,1, +1266,1, +1268,1, +1270,1, +1272,1, +1274,1, +1276,1, +1278,1, +1280,1, +1282,1, +1284,1, +1286,1, +1288,1, +1290,1, +1292,1, +1294,1, +1296,1, +1298,1, +1329,38, +4256,38, +7680,1, +7682,1, +7684,1, +7686,1, +7688,1, +7690,1, +7692,1, +7694,1, +7696,1, +7698,1, +7700,1, +7702,1, +7704,1, +7706,1, +7708,1, +7710,1, +7712,1, +7714,1, +7716,1, +7718,1, +7720,1, +7722,1, +7724,1, +7726,1, +7728,1, +7730,1, +7732,1, +7734,1, +7736,1, +7738,1, +7740,1, +7742,1, +7744,1, +7746,1, +7748,1, +7750,1, +7752,1, +7754,1, +7756,1, +7758,1, +7760,1, +7762,1, +7764,1, +7766,1, +7768,1, +7770,1, +7772,1, +7774,1, +7776,1, +7778,1, +7780,1, +7782,1, +7784,1, +7786,1, +7788,1, +7790,1, +7792,1, +7794,1, +7796,1, +7798,1, +7800,1, +7802,1, +7804,1, +7806,1, +7808,1, +7810,1, +7812,1, +7814,1, +7816,1, +7818,1, +7820,1, +7822,1, +7824,1, +7826,1, +7828,1, +7840,1, +7842,1, +7844,1, +7846,1, +7848,1, +7850,1, +7852,1, +7854,1, +7856,1, +7858,1, +7860,1, +7862,1, +7864,1, +7866,1, +7868,1, +7870,1, +7872,1, +7874,1, +7876,1, +7878,1, +7880,1, +7882,1, +7884,1, +7886,1, +7888,1, +7890,1, +7892,1, +7894,1, +7896,1, +7898,1, +7900,1, +7902,1, +7904,1, +7906,1, +7908,1, +7910,1, +7912,1, +7914,1, +7916,1, +7918,1, +7920,1, +7922,1, +7924,1, +7926,1, +7928,1, +7944,8, +7960,6, +7976,8, +7992,8, +8008,6, +8025,1, +8027,1, +8029,1, +8031,1, +8040,8, +8072,8, +8088,8, +8104,8, +8120,5, +8136,5, +8152,4, +8168,5, +8184,5, +8450,1, +8455,1, +8459,3, +8464,3, +8469,1, +8473,5, +8484,1, +8486,1, +8488,1, +8490,4, +8496,4, +8510,2, +8517,1, +8579,1, +11264,47, +11360,1, +11362,3, +11367,1, +11369,1, +11371,1, +11381,1, +11392,1, +11394,1, +11396,1, +11398,1, +11400,1, +11402,1, +11404,1, +11406,1, +11408,1, +11410,1, +11412,1, +11414,1, +11416,1, +11418,1, +11420,1, +11422,1, +11424,1, +11426,1, +11428,1, +11430,1, +11432,1, +11434,1, +11436,1, +11438,1, +11440,1, +11442,1, +11444,1, +11446,1, +11448,1, +11450,1, +11452,1, +11454,1, +11456,1, +11458,1, +11460,1, +11462,1, +11464,1, +11466,1, +11468,1, +11470,1, +11472,1, +11474,1, +11476,1, +11478,1, +11480,1, +11482,1, +11484,1, +11486,1, +11488,1, +11490,1 +]; + +whitespaceAndNewlineCharacterSet = [ +9,5, +32,1, +133,1, +160,1, +5760,1, +8192,12, +8232,2, +8239,1, +8287,1 +]; + +whitespaceCharacterSet = [ +9,1, +32,1, +160,1, +5760,1, +8192,12, +8239,1, +8287,1 +]; diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index f7a65ae8f..942e78ed2 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -22,6 +22,7 @@ @import "CPArray.j" @import "CPBundle.j" +@import "CPCharacterSet.j" @import "CPCoder.j" @import "CPData.j" @import "CPDate.j" From fce726a0319b60a4ebd3972e67339a7acaae8dea Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 13 Oct 2009 02:38:09 +0200 Subject: [PATCH 158/356] CPScanner implementation --- Foundation/CPScanner.j | 392 ++++++++++++++++++++++++++++++++++++++++ Foundation/Foundation.j | 1 + 2 files changed, 393 insertions(+) create mode 100644 Foundation/CPScanner.j diff --git a/Foundation/CPScanner.j b/Foundation/CPScanner.j new file mode 100644 index 000000000..b5373f0af --- /dev/null +++ b/Foundation/CPScanner.j @@ -0,0 +1,392 @@ +// CPScanner.j +// © Emanuele Vulcano, 2008. +// +// Licensed under the terms of Cappuccino's license +// (the GNU Lesser General Public License, version 2.1). +// Please see Cappuccino's LICENSE file for details. + +@import + +@implementation CPScanner : CPObject +{ + CPString _string; + CPDictionary _locale; + int _scanLocation; + BOOL _caseSensitive; + CPCharacterSet _charactersToBeSkipped; +} + +// TODO Not all methods of NSScanner are available! + +/* +- (BOOL)scanLongLong:(long long *)longLongValue +{ +} +- (BOOL)scanDecimal:(NSDecimal *)decimalValue +{ +} +- (BOOL)scanHexDouble:(double *)result +{ +} +- (BOOL)scanHexFloat:(float *)result +{ +} +- (BOOL)scanHexInt:(unsigned *)intValue +{ +} +- (BOOL)scanHexLongLong:(unsigned long long *)result +{ +} +- (BOOL)scanInteger:(NSInteger *)value +{ +} ++ (id)localizedScannerWithString:(CPString)string +{ + var scanner = [self scannerWithString:string]; + + [scanner setLocale:[CPLocale currentLocale]]; + + return scanner; +} + +*/ + ++ (id)scannerWithString:(CPString)aString +{ + return [[self alloc] initWithString:aString]; +} + +- (id)initWithString:(CPString)aString +{ + if (self = [super init]) + { + _string = [aString copy]; + _scanLocation = 0; + _charactersToBeSkipped = [CPCharacterSet whitespaceCharacterSet]; + _caseSensitive = NO; + } + + return self; +} + +- (id)copy +{ + var copy = [[CPScanner alloc] initWithString:[self string]]; + + [copy setCharactersToBeSkipped:[self charactersToBeSkipped]]; + [copy setCaseSensitive:[self caseSensitive]]; + [copy setLocale:[self locale]]; + [copy setScanLocation:[self scanLocation]]; + + return copy; +} + +- (CPDictionary)locale +{ + return _locale; +} + +- (void)setLocale:(CPDictionary)aLocale +{ + _locale = aLocale; +} + +- (void)setCaseSensitive:(BOOL)flag +{ + _caseSensitive = flag; +} + +- (BOOL)caseSensitive +{ + return _caseSensitive; +} + +- (CPString)string +{ + return _string; +} + +- (CPCharacterSet)charactersToBeSkipped +{ + return _charactersToBeSkipped; +} + +- (void)setCharactersToBeSkipped:(CPCharacterSet)c +{ + _charactersToBeSkipped = c; +} + +- (BOOL)isAtEnd +{ + return _scanLocation == _string.length; +} + +- (int)scanLocation +{ + return _scanLocation; +} + +- (void)setScanLocation:(int)aLocation +{ + if (aLocation > _string.length) + aLocation = _string.length; // clamp to just after the last character + else if (aLocation < 0) + aLocation = 0; // clamp to the first + + _scanLocation = aLocation; +} + +// Method body for all methods that return their value by reference. +- (BOOL)_performScanWithSelector:(SEL)s withObject:(id)arg into:(id)ref +{ + var ret = [self performSelector:s withObject:arg]; + + if (ref != nil) + ref(ret); + + return ret != NULL; +} + +/* ================================ */ +/* = Scanning with CPCharacterSet = */ +/* ================================ */ + +- (BOOL)scanCharactersFromSet:(CPCharacterSet)scanSet intoString:(id)ref +{ + return [self _performScanWithSelector:@selector(scanCharactersFromSet:) withObject:scanSet into:ref]; +} + +- (CPString)scanCharactersFromSet:(CPCharacterSet)scanSet +{ + return [self _scanWithSet:scanSet breakFlag:NO]; +} + +- (BOOL)scanUpToCharactersFromSet:(CPCharacterSet)scanSet intoString:(id)ref +{ + return [self _performScanWithSelector:@selector(scanUpToCharactersFromSet:) withObject:scanSet into:ref]; +} + +- (CPString)scanUpToCharactersFromSet:(CPCharacterSet)scanSet +{ + return [self _scanWithSet:scanSet breakFlag:YES]; +} + +// If stop == YES, it will stop when it sees a character from +// the set (scanUpToCharactersFromSet:); if stop == NO, it will +// stop when it sees a character NOT from the set +// (scanCharactersFromSet:). +- (CPString)_scanWithSet:(CPCharacterSet)scanSet breakFlag:(BOOL)stop +{ + if ([self isAtEnd]) + return nil; + + var current = [self scanLocation]; + var str = nil; + + while (current < _string.length) + { + var c = (_string.charAt(current)); + + if ([scanSet characterIsMember:c] == stop) + break; + + if (![_charactersToBeSkipped characterIsMember:c]) + { + if (!str) + str = ''; + str += c; + } + + current++; + } + + if (str) + [self setScanLocation:current]; + + return str; +} + +/* ==================== */ +/* = Scanning strings = */ +/* ==================== */ + +- (void)_movePastCharactersToBeSkipped +{ + var current = [self scanLocation]; + var string = [self string]; + var toSkip = [self charactersToBeSkipped]; + + while (current < string.length) + { + if (![toSkip characterIsMember:string.charAt(current)]) + break; + + current++; + } + + [self setScanLocation:current]; +} + + +- (BOOL)scanString:(CPString)aString intoString:(id)ref +{ + return [self _performScanWithSelector:@selector(scanString:) withObject:aString into:ref]; +} + +- (CPString)scanString:(CPString)s +{ + [self _movePastCharactersToBeSkipped]; + if ([self isAtEnd]) + return nil; + + var currentStr = [self string].substr([self scanLocation], s.length); + if ((_caseSensitive && currentStr != s) || (!_caseSensitive && (currentStr.toLowerCase() != s.toLowerCase()))) + { + return nil; + } + else + { + [self setScanLocation:[self scanLocation] + s.length]; + return s; + } +} + +- (BOOL)scanUpToString:(CPString)aString intoString:(id)ref +{ + return [self _performScanWithSelector:@selector(scanUpToString:) withObject:aString into:ref]; +} + +- (CPString)scanUpToString:(CPString)s +{ + var current = [self scanLocation], str = [self string]; + var captured = nil; + while (current < str.length) + { + var currentStr = str.substr(current, s.length); + if (currentStr == s || (!_caseSensitive && currentStr.toLowerCase() == s.toLowerCase())) + break; + + if (!captured) + captured = ''; + captured += str.charAt(current); + current++; + } + + if (captured) + [self setScanLocation:current]; + + // evil private method use! + // this method is defined in the category on CPString + // in CPCharacterSet.j + if ([self charactersToBeSkipped]) + captured = [captured _stringByTrimmingCharactersInSet:[self charactersToBeSkipped] options:_CPCharacterSetTrimAtBeginning]; + + return captured; +} + +/* ==================== */ +/* = Scanning numbers = */ +/* ==================== */ + +- (float)scanFloat +{ + [self _movePastCharactersToBeSkipped]; + var str = [self string], current = [self scanLocation]; + + if ([self isAtEnd]) + return 0; + + var s = str.substring(current, str.length); + var f = parseFloat(s); // wont work with non . decimal separator !! + if (f) + { + var pos, foundDash = NO; +/* + var decimalSeparatorString; + if(_locale != nil) + decimalSeparatorString = [_locale objectForKey:CPLocaleDecimalSeparator]; + else + decimalSeparatorString = [[CPLocale systemLocale] objectForKey:CPLocaleDecimalSeparator]; + + var separatorCode = (decimalSeparatorString.length >0) decimalSeparatorString.charCodeAt(0) : 45; +*/ + var separatorCode = 45; + + for(pos = current; pos < current + str.length; pos++) + { + var charCode = str.charCodeAt(pos); + if (charCode == separatorCode) + { + if (foundDash == YES) + break; // We already found a decimal separator so this one is an extra char + foundDash = YES; + } + else if (charCode < 48 || charCode > 57 || (charCode == 45 && pos != current)) // not a digit or a "-" but not prefix + break; + } + + [self setScanLocation:pos]; + return f; + } + + return nil; +} + +- (int)scanInt +{ + [self _movePastCharactersToBeSkipped]; + var str = [self string], current = [self scanLocation]; + + if ([self isAtEnd]) + return 0; + var s = str.substring(current, str.length); + + var i = parseInt(s); + if (i) + { + var pos, foundDash = NO; + for (pos = current; pos < current + str.length; pos++) + { + var charCode = str.charCodeAt(pos); + if (charCode == 46) + { + if (foundDash == YES) + break; + foundDash = YES; + } + else if (charCode < 48 || charCode > 57 || (charCode == 45 && pos != current)) + break; + } + + [self setScanLocation:pos]; + return i; + } + + return nil; +} + +- (BOOL)scanInt:(int)intoInt +{ + return [self _performScanWithSelector:@selector(scanInt) withObject:nil into:intoInt]; +} + +- (BOOL)scanFloat:(float)intoFloat +{ + return [self _performScanWithSelector:@selector(scanFloat) withObject:nil into:intoFloat]; +} + +- (BOOL)scanDouble:(float)intoDouble +{ + return [self scanFloat:intoDouble]; +} + +/* ========= */ +/* = Debug = */ +/* ========= */ + +- (void) description +{ + return [super description] + " {" + CPStringFromClass([self class]) + ", state = '" + ([self string].substr(0, _scanLocation) + "{{ SCAN LOCATION ->}}" + [self string].substr(_scanLocation)) + "'; }"; +} + +@end \ No newline at end of file diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index 942e78ed2..d6d0822bd 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -48,6 +48,7 @@ @import "CPPropertyListSerialization.j" @import "CPRange.j" @import "CPRunLoop.j" +@import "CPScanner.j" @import "CPSet.j" @import "CPSortDescriptor.j" @import "CPString.j" From 974cf64e1ddeb861df4b29b0702d098f6d8b6282 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 13 Oct 2009 10:04:30 +0200 Subject: [PATCH 159/356] CPPredicate &al implementation. OJUnit test. --- .../CPPredicate/CPComparisonPredicate.j | 605 ++++++++++++ Foundation/CPPredicate/CPCompoundPredicate.j | 222 +++++ Foundation/CPPredicate/CPExpression.j | 324 +++++++ .../CPPredicate/CPExpression_aggregate.j | 107 ++ .../CPPredicate/CPExpression_assignment.j | 92 ++ .../CPPredicate/CPExpression_constant.j | 65 ++ .../CPPredicate/CPExpression_function.j | 373 +++++++ .../CPPredicate/CPExpression_intersectset.j | 86 ++ Foundation/CPPredicate/CPExpression_keypath.j | 63 ++ .../CPPredicate/CPExpression_minusset.j | 81 ++ .../CPPredicate/CPExpression_operator.j | 117 +++ Foundation/CPPredicate/CPExpression_self.j | 46 + .../CPPredicate/CPExpression_unionset.j | 84 ++ .../CPPredicate/CPExpression_variable.j | 68 ++ Foundation/CPPredicate/CPPredicate.j | 913 ++++++++++++++++++ Foundation/Foundation.j | 4 + Tests/Foundation/CPPredicateTest.j | 187 ++++ 17 files changed, 3437 insertions(+) create mode 100644 Foundation/CPPredicate/CPComparisonPredicate.j create mode 100644 Foundation/CPPredicate/CPCompoundPredicate.j create mode 100644 Foundation/CPPredicate/CPExpression.j create mode 100644 Foundation/CPPredicate/CPExpression_aggregate.j create mode 100644 Foundation/CPPredicate/CPExpression_assignment.j create mode 100644 Foundation/CPPredicate/CPExpression_constant.j create mode 100644 Foundation/CPPredicate/CPExpression_function.j create mode 100644 Foundation/CPPredicate/CPExpression_intersectset.j create mode 100644 Foundation/CPPredicate/CPExpression_keypath.j create mode 100644 Foundation/CPPredicate/CPExpression_minusset.j create mode 100644 Foundation/CPPredicate/CPExpression_operator.j create mode 100644 Foundation/CPPredicate/CPExpression_self.j create mode 100644 Foundation/CPPredicate/CPExpression_unionset.j create mode 100644 Foundation/CPPredicate/CPExpression_variable.j create mode 100644 Foundation/CPPredicate/CPPredicate.j create mode 100644 Tests/Foundation/CPPredicateTest.j diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j new file mode 100644 index 000000000..25f42bed5 --- /dev/null +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -0,0 +1,605 @@ +@import "CPArray.j" +@import "CPNull.j" +@import "CPString.j" +@import "CPEnumerator.j" +@import "CPPredicate.j" +@import "CPExpression.j" +@import "CPExpression_operator.j" + +/*! + A predicate to compare directly the left and right hand sides. + @global + @class CPComparisonPredicate +*/ +CPDirectPredicateModifier = 0; +/*! + A predicate to compare all entries in the destination of a to-many relationship. + + The left hand side must be a collection. The corresponding predicate compares each value in the left hand side with the right hand side, and returns NO when it finds the first mismatch—or YES if all match. + @global + @class CPComparisonPredicate +*/ +CPAllPredicateModifier = 1; +/*! + A predicate to match with any entry in the destination of a to-many relationship. + + The left hand side must be a collection. The corresponding predicate compares each value in the left hand side against the right hand side and returns YES when it finds the first match—or NO if no match is found. + @global + @class CPComparisonPredicate +*/ +CPAnyPredicateModifier = 2; + +/*! + A case-insensitive predicate. + @global + @class CPComparisonPredicate +*/ +CPCaseInsensitivePredicateOption = 1; +/*! + A diacritic-insensitive predicate. + @global + @class CPComparisonPredicate +*/ +CPDiacriticInsensitivePredicateOption = 2; +CPDiacriticInsensitiveSearch = 128; + +/*! + A less-than predicate. + @global + @class CPComparisonPredicate +*/ +CPLessThanPredicateOperatorType = 0; +/*! + A less-than-or-equal-to predicate. + @global + @class CPComparisonPredicate +*/ +CPLessThanOrEqualToPredicateOperatorType = 1; +/*! + A greater-than predicate. + @global + @class CPComparisonPredicate +*/ +CPGreaterThanPredicateOperatorType = 2; +/*! + A greater-than-or-equal-to predicate. + @global + @class CPComparisonPredicate +*/ +CPGreaterThanOrEqualToPredicateOperatorType = 3; +/*! + An equal-to predicate. + @global + @class CPComparisonPredicate +*/ +CPEqualToPredicateOperatorType = 4; +/*! + A not-equal-to predicate. + @global + @class CPComparisonPredicate +*/ +CPNotEqualToPredicateOperatorType = 5; +/*! + A full regular expression matching predicate. + @global + @class CPComparisonPredicate +*/ +CPMatchesPredicateOperatorType = 6; +/*! + A simple subset of the matches predicate, similar in behavior to SQL LIKE. + @global + @class CPComparisonPredicate +*/ +CPLikePredicateOperatorType = 7; +/*! + A begins-with predicate. + @global + @class CPComparisonPredicate +*/ +CPBeginsWithPredicateOperatorType = 8; +/*! + An ends-with predicate. + @global + @class CPComparisonPredicate +*/ +CPEndsWithPredicateOperatorType = 9; +/*! + A predicate to determine if the left hand side is in the right hand side. + + For strings, returns YES if the left hand side is a substring of the right hand side . For collections, returns YES if the left hand side is in the right hand side. + @global + @class CPComparisonPredicate +*/ +CPInPredicateOperatorType = 10; +/*! + Predicate that uses a custom selector that takes a single argument and returns a BOOL value. + + The selector is invoked on the left hand side with the right hand side. + @global + @class CPComparisonPredicate +*/ +CPCustomSelectorPredicateOperatorType = 11; +/*! + A predicate to determine if the left hand side contains the right hand side. + + Returns YES if [lhs contains rhs]; the left hand side must be a CPExpression object that evaluates to a collection + @global + @class CPComparisonPredicate +*/ +CPContainsPredicateOperatorType = 99; +/*! + A predicate to determine if the right hand side lies between bounds specified by the left hand side. + + Returns YES if [lhs between rhs]; the right hand side must be an array in which the first element sets the lower bound and the second element the upper, inclusive. Comparison is performed using compare: or the class-appropriate equivalent. + @global + @class CPComparisonPredicate +*/ +CPBetweenPredicateOperatorType = 100; + +var CPComparisonPredicateModifier; +var CPPredicateOperatorType; + +/*! + @ingroup foundation + @class CPComparisonPredicate + @brief CPComparisonPredicate is a subclass of CPPredicate used to compare expressions. + + Comparison predicates are predicates used to compare the results of two expressions. Comparison predicates take an operator, a left expression, and a right expression, and return as a BOOL the result of invoking the operator with the results of evaluating the expressions. Expressions are represented by instances of the CPExpression class. +*/ +@implementation CPComparisonPredicate : CPPredicate +{ + CPExpression _left; + CPExpression _right; + + CPComparisonPredicateModifier _modifier; + CPPredicateOperatorType _type; + unsigned int _options; + SEL _customSelector; +} + +// Constructors +/*! + Returns a new predicate formed by combining the left and right expressions using a given selector. + @param left The left hand side expression. + @param right The right hand side expression. + @param selector The selector to use for comparison. The method defined by the selector must take a single argument and return a BOOL value. + @return A new predicate formed by combining the left and right expressions using selector. +*/ ++ (CPPredicate)predicateWithLeftExpression:(CPExpression)left rightExpression:(CPExpression)right customSelector:(SEL)selector +{ + return [[self alloc] initWithLeftExpression:left rightExpression:right customSelector:selector]; +} + +/*! + Creates and returns a predicate of a given type formed by combining given left and right expressions using a given modifier and options. + @param left The left hand expression. + @param right The right hand expression. + @param modifier The modifier to apply. + @param type The predicate operator type. + @param options The options to apply (see CPComparisonPredicate Options). + @return A new predicate of type type formed by combining the given left and right expressions using the modifier and options. +*/ ++ (CPPredicate)predicateWithLeftExpression:(CPExpression)left rightExpression:(CPExpression)right modifier:(CPComparisonPredicateModifier)modifier type:(int)type options:(unsigned)options +{ + return [[self alloc] initWithLeftExpression:left rightExpression:right modifier:modifier type:type options:options]; +} + +/*! + Initializes a predicate formed by combining given left and right expressions using a given selector. + @param left The left hand side expression. + @param right The right hand side expression. + @param selector The selector to use for comparison. The method defined by the selector must take a single argument and return a BOOL value. + @return The receiver, initialized by combining the left and right expressions using selector. +*/ +- (id)initWithLeftExpression:(CPExpression)left rightExpression:(CPExpression)right customSelector:(SEL)selector +{ + _left = left; + _right = right; + _modifier = CPDirectPredicateModifier; + _type = CPCustomSelectorPredicateOperatorType; + _options = 0; + _customSelector = selector; + + return self; +} + +/*! + Initializes a predicate to a given type formed by combining given left and right expressions using a given modifier and options. + @param left The left hand expression. + @param right The right hand expression. + @param modifier The modifier to apply. + @param type The predicate operator type. + @param options The options to apply (see CPComparisonPredicate Options). + @return The receiver, initialized to a predicate of type type formed by combining the left and right expressions using the modifier and options. +*/ +- (id)initWithLeftExpression:(CPExpression)left rightExpression:(CPExpression)right modifier:(CPComparisonPredicateModifier)modifier type:(CPPredicateOperatorType)type options:(unsigned)options +{ + _left = left; + _right = right; + _modifier = modifier; + _type = type; + _options = (type != CPMatchesPredicateOperatorType && + type != CPLikePredicateOperatorType && + type != CPBeginsWithPredicateOperatorType && + type != CPEndsWithPredicateOperatorType && + type != CPInPredicateOperatorType && + type != CPContainsPredicateOperatorType) ? 0 : options; + + _customSelector = NULL; + + return self; +} + +// Getting Information About a Comparison Predicate +/*! + Returns the comparison predicate modifier for the receiver. + @return The comparison predicate modifier for the receiver. +*/ +- (CPComparisonPredicateModifier)comparisonPredicateModifier +{ + return _modifier; +} + +/*! + Returns the selector for the receiver. + @return The selector for the receiver, or NULL if there is none. +*/ +- (SEL)customSelector +{ + return _customSelector; +} + +/*! + Returns the left expression for the receiver. + @return The left expression for the receiver, or nil if there is none. +*/ +- (CPExpression)leftExpression +{ + return _left; +} + +/*! + Returns the options that are set for the receiver. + @return The options that are set for the receiver. +*/ +- (unsigned)options +{ + return _options; +} + +/*! + Returns the predicate type for the receiver. + @return Returns the predicate type for the receiver. +*/ +- (CPPredicateOperatorType)predicateOperatorType +{ + return _type; +} + +/*! + Returns the right expression for the receiver. + @return The right expression for the receiver, or nil if there is none. +*/ +- (CPExpression)rightExpression +{ + return _right; +} + + +- (CPString)predicateFormat +{ + var modifier; + + switch (_modifier) + { + case CPDirectPredicateModifier: + modifier = ""; + break; + case CPAllPredicateModifier: + modifier = "ALL "; + break; + case CPAnyPredicateModifier: + modifier = "ANY "; + break; + default: + modifier = ""; + break; + } + + var options; + + switch (_options) + { + case CPCaseInsensitivePredicateOption: + options = "[c]"; + break; + case CPDiacriticInsensitivePredicateOption: + options = "[d]"; + break; + case CPCaseInsensitivePredicateOption | CPDiacriticInsensitivePredicateOption: + options = "[cd]"; + break; + default: + options = ""; + break; + } + + var operator; + + switch (_type) + { + case CPLessThanPredicateOperatorType: + operator = "<"; + break; + case CPLessThanOrEqualToPredicateOperatorType: + operator = "<="; + break; + case CPGreaterThanPredicateOperatorType: + operator = ">"; + break; + case CPGreaterThanOrEqualToPredicateOperatorType: + operator = ">="; + break; + case CPEqualToPredicateOperatorType: + operator = "=="; + break; + case CPNotEqualToPredicateOperatorType: + operator = "!="; + break; + case CPMatchesPredicateOperatorType: + operator = "MATCHES"; + break; + case CPLikePredicateOperatorType: + operator = "LIKE"; + break; + case CPBeginsWithPredicateOperatorType: + operator = "BEGINSWITH"; + break; + case CPEndsWithPredicateOperatorType: + operator = "ENDSWITH"; + break; + case CPInPredicateOperatorType: + operator = "IN"; + break; + case CPContainsPredicateOperatorType: + operator = "CONTAINS"; + break; + case CPCustomSelectorPredicateOperatorType: + operator = CPStringFromSelector(_customSelector); + break; + } + + return [CPString stringWithFormat:@"%s%s %s%s %s",modifier,[_left description],operator,options,[_right description]]; +} + +- (CPPredicate)predicateWithSubstitutionVariables:(CPDictionary)variables +{ + var left = [_left _expressionWithSubstitutionVariables:variables], + right = [_right _expressionWithSubstitutionVariables:variables]; + + if (_type != CPCustomSelectorPredicateOperatorType) + return [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:_modifier type:_type options:_options]; + else + return [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:right customSelector:_customSelector]; +} + +- (BOOL)_evaluateValue:lhs rightValue:rhs +{ + var leftIsNil = (lhs == nil || [lhs isEqual:[CPNull null]]), + rightIsNil = (rhs == nil || [rhs isEqual:[CPNull null]]); + + if (leftIsNil || rightIsNil) + return (leftIsNil == rightIsNil && + (_type == CPEqualToPredicateOperatorType || + _type == CPLessThanOrEqualToPredicateOperatorType || + _type == CPGreaterThanOrEqualToPredicateOperatorType)); + + var string_compare_options = 0; + + // left and right should be casted first [CAST()] following 10.5 rules. + switch (_type) + { + case CPLessThanPredicateOperatorType: + return ([lhs compare:rhs] == CPOrderedAscending); + case CPLessThanOrEqualToPredicateOperatorType: + return ([lhs compare:rhs] != CPOrderedDescending); + case CPGreaterThanPredicateOperatorType: + return ([lhs compare:rhs] == CPOrderedDescending); + case CPGreaterThanOrEqualToPredicateOperatorType: + return ([lhs compare:rhs] != CPOrderedAscending); + case CPEqualToPredicateOperatorType: + return [lhs isEqual:rhs]; + case CPNotEqualToPredicateOperatorType: + return (![lhs isEqual:rhs]); + case CPMatchesPredicateOperatorType: + var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g"; + if (_options & CPDiacriticInsensitivePredicateOption) + { + lhs = lhs.stripDiacritics(); + rhs = rhs.stripDiacritics(); + } + + return (new RegExp(rhs,commut)).test(lhs); + case CPLikePredicateOperatorType: + if (_options & CPDiacriticInsensitivePredicateOption) + { + lhs = lhs.stripDiacritics(); + rhs = rhs.stripDiacritics(); + } + var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g"; + var reg = new RegExp(rhs.escapeForRegExp(),commut); + return reg.test(lhs); + case CPBeginsWithPredicateOperatorType: + var range = CPMakeRange(0,[rhs length]); + if (_options & CPCaseInsensitivePredicateOption) string_compare_options |= CPCaseInsensitiveSearch; + if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch; + + return ([lhs compare:rhs options:string_compare_options range:range] == CPOrderedSame); + case CPEndsWithPredicateOperatorType: + var range = CPMakeRange([lhs length] - [rhs length],[rhs length]); + if (_options & CPCaseInsensitivePredicateOption) string_compare_options |= CPCaseInsensitiveSearch; + if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch; + + return ([lhs compare:rhs options:string_compare_options range:range] == CPOrderedSame); + case CPInPredicateOperatorType: + // Handle special case where rhs is a collection and lhs an element of it. + if (![rhs isKindOfClass: [CPString class]]) + { + if (![rhs respondsToSelector: @selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The right hand side for an IN operator must be a collection"]; + + var e = [rhs objectEnumerator], + value; + while (value = [e nextObject]) + if ([value isEqual:lhs]) + return YES; + + return NO; + } + + if (_options & CPCaseInsensitivePredicateOption) + string_compare_options |= CPCaseInsensitiveSearch; + if (_options & CPDiacriticInsensitivePredicateOption) + string_compare_options |= CPDiacriticInsensitiveSearch; + + return ([rhs rangeOfString:lhs options:string_compare_options].location != CPNotFound); + case CPCustomSelectorPredicateOperatorType: + return [lhs performSelector:_customSelector withObject:rhs]; + case CPContainsPredicateOperatorType: + if (![lhs isKindOfClass: [CPString class]]) + { + if (![lhs respondsToSelector: @selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The left hand side for a CONTAINS operator must be a collection or a string"]; + + var e = [lhs objectEnumerator], + value; + while (value = [e nextObject]) + if ([value isEqual:rhs]) + return YES; + + return NO; + } + + if (_options & CPCaseInsensitivePredicateOption) + string_compare_options |= CPCaseInsensitiveSearch; + if (_options & CPDiacriticInsensitivePredicateOption) + string_compare_options |= CPDiacriticInsensitiveSearch; + + return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound); + case CPBetweenPredicateOperatorType: + if ([lhs count] < 2) + [CPException raise:CPInvalidArgumentException reason:@"The right hand side for a BETWEEN operator must contain 2 objects"]; + + var lower = [rhs objectAtIndex:0], + upper = [rhs objectAtIndex:1]; + + return ([lhs compare:lower] == CPOrderedDescending && [lhs compare:upper] == CPOrderedAscending); + default: + return NO; + } +} + +- (BOOL)evaluateWithObject:(id)object +{ + return [self evaluateWithObject:object substitutionVariables:nil]; +} + +- (BOOL)evaluateWithObject:(id)object substitutionVariables:(CPDictionary)variables +{ + var left = _left, + right = _right; + + if(variables != nil) + { + left = [left _expressionWithSubstitutionVariables:variables]; + right = [right _expressionWithSubstitutionVariables:variables]; + } + + var leftValue = [left expressionValueWithObject:object context:nil], + rightValue = [right expressionValueWithObject:object context:nil]; + + if (_modifier == CPDirectPredicateModifier) + return [self _evaluateValue:leftValue rightValue:rightValue]; + else + { + if (![leftValue respondsToSelector:@selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The left hand side for an ALL or ANY operator must be either a CPArray or a CPSet"]; + + var e = [leftValue objectEnumerator], + result = (_modifier == CPAllPredicateModifier), + value; + + while (value = [e nextObject]) + { + var eval = [self _evaluateValue:value rightValue:rightValue]; + if (eval != result) + return eval; + } + + return result; + } +} + +@end + +@implementation CPComparisonPredicate (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + self = [super init]; + if (self != nil) + { + _left = [coder decodeObjectForKey:@"CPComparisonPredicateLeftExpression"]; + _right = [coder decodeObjectForKey:@"CPComparisonPredicateRightExpression"]; + _modifier = [coder decodeIntForKey:@"CPComparisonPredicateModifier"]; + _type = [coder decodeIntForKey:@"CPComparisonPredicateType"]; + _options = [coder decodeIntForKey:@"CPComparisonPredicateOptions"]; + _customSelector = [coder decodeObjectForKey:@"CPComparisonPredicateCustomSelector"]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_left forKey:@"CPComparisonPredicateLeftExpression"]; + [coder encodeObject:_right forKey:@"CPComparisonPredicateRightExpression"]; + [coder encodeInt:_modifier forKey:@"CPComparisonPredicateModifier"]; + [coder encodeInt:_type forKey:@"CPComparisonPredicateType"]; + [coder encodeInt:_options forKey:@"CPComparisonPredicateOptions"]; + [coder encodeObject:_customSelector forKey:@"CPComparisonPredicateCustomSelector"]; +} + +@end + +var source = ['*','?','(',')','{','}','.','+','|','/','$','^']; +var dest = ['.*','.?','\\(','\\)','\\{','\\}','\\.','\\+','\\|','\\/','\\$','\\^']; + +String.prototype.escapeForRegExp = function() +{ + var foundChar = false; + for (var i = 0; i < source.length; ++i) + { + if (this.indexOf(source[i]) !== -1) + { + foundChar = true; + break; + } + } + + if (!foundChar) + return this; + + var result = ""; + var sourceIndex; + for (var i = 0; i < this.length; ++i) + { + var sourceIndex = source.indexOf(this.charAt(i)); + if (sourceIndex !== -1) + result += dest[sourceIndex]; + else + result += this.charAt(i); + } + + return result; +} diff --git a/Foundation/CPPredicate/CPCompoundPredicate.j b/Foundation/CPPredicate/CPCompoundPredicate.j new file mode 100644 index 000000000..86262ece2 --- /dev/null +++ b/Foundation/CPPredicate/CPCompoundPredicate.j @@ -0,0 +1,222 @@ +@import "CPPredicate.j" +@import +@import + +/*! + A predicate to compare directly the left and right hand sides. + @global + @class CPCompoundPredicate +*/ +CPNotPredicateType = 0; +/*! + A predicate to compare directly the left and right hand sides. + @global + @class CPCompoundPredicate +*/ +CPAndPredicateType = 1; +/*! + A predicate to compare directly the left and right hand sides. + @global + @class CPCompoundPredicate +*/ +CPOrPredicateType = 2; + +var CPCompoundPredicateType; + +/*! + @class CPCompoundPredicate + @ingroup foundation + @brief CPCompoundPredicate is a subclass of CPPredicate used to represent logical “gate” operations (AND/OR/NOT) and comparison operations. + + Comparison operations are based on two expressions, as represented by instances of the CPExpression class. Expressions are created for constant values, key paths, and so on. + + A compound predicate with 0 elements evaluates to TRUE, and a compound predicate with a single sub-predicate evaluates to the truth of its sole subpredicate. +*/ +@implementation CPCompoundPredicate : CPPredicate +{ + CPCompoundPredicateType _type; + CPArray _predicates; +} + +// Constructors +/*! + Returns the receiver initialized to a given type using predicates from a given array. + @param type The type of the new predicate. + @return The receiver initialized with its type set to type and subpredicates array to subpredicates. +*/ +- (id)initWithType:(CPCompoundPredicateType)type subpredicates:(CPArray)predicates +{ + _type = type; + _predicates = predicates; + + return self; +} + +/*! + Returns a new predicate formed by NOT-ing the predicates in a given array. + @param subpredicates An array of CPPredicate objects. + @return A new predicate formed by NOT-ing the predicates specified by subpredicates. +*/ ++ (CPPredicate)notPredicateWithSubpredicate:(CPPredicate)predicate +{ + return [[self alloc] initWithType:CPNotPredicateType subpredicates:[CPArray arrayWithObject:predicate]]; +} + +/*! + Returns a new predicate formed by AND-ing the predicates in a given array. + @param subpredicates An array of CPPredicate objects. + @return A new predicate formed by AND-ing the predicates specified by subpredicates. +*/ ++ (CPPredicate)andPredicateWithSubpredicates:(CPArray)subpredicates +{ + return [[self alloc] initWithType:CPAndPredicateType subpredicates:subpredicates]; +} + +/*! + Returns a new predicate formed by OR-ing the predicates in a given array. + @param subpredicates An array of CPPredicate objects. + @return A new predicate formed by OR-ing the predicates specified by subpredicates. +*/ ++ (CPPredicate)orPredicateWithSubpredicates:(CPArray)predicates +{ + return [[self alloc] initWithType:CPOrPredicateType subpredicates:predicates]; +} + +// Getting Information About a Compound Predicate +/*! + Returns the predicate type for the receiver. + @return The predicate type for the receiver. +*/ +- (CPCompoundPredicateType)compoundPredicateType +{ + return _type; +} + +/*! + Returns the array of the receiver’s subpredicates. + @return The array of the receiver’s subpredicates. +*/ +- (CPArray)subpredicates +{ + return _predicates; +} + +- (CPPredicate)predicateWithSubstitutionVariables:(CPDictionary)variables +{ + var subp = [CPArray array], + i; + + for (i = 0; i < [subp count]; i++) + { + var p = [subp objectAtIndex:i], + sp = [p predicateWithSubstitutionVariables:variables]; + + [subp addObject:sp]; + } + + return [[CPCompoundPredicate alloc] initWithType:_type subpredicates:subp]; +} + +- (CPString)predicateFormat +{ + var result = "", + args = [CPArray array], + count = [_predicates count], + i; + + if (count == 0) + return @"TRUPREDICATE"; + + for (i = 0; i < count; i++) + { + var subpredicate = [_predicates objectAtIndex:i], + precedence = [subpredicate predicateFormat]; + + if ([subpredicate isKindOfClass:[CPCompoundPredicate class]] && [[subpredicate subpredicates] count]> 1 && [subpredicate compoundPredicateType] != _type) + precedence = [CPString stringWithFormat:@"(%s)",precedence]; + + if (precedence != nil) + [args addObject:precedence]; + } + + switch (_type) + { + case CPNotPredicateType: + result += "NOT %s" + [args objectAtIndex:0]; + break; + case CPAndPredicateType: + result += [args objectAtIndex:0]; + for (var j = 1; j < [args count]; j++) + result += " AND " + [args objectAtIndex:j]; + break; + case CPOrPredicateType: + result += [args objectAtIndex:0]; + for(var j=1;j<[args count];j++) + result += " OR " + [args objectAtIndex:j]; + break; + } + + return result; +} + +- (BOOL)evaluateWithObject:(id)object +{ + return [self evaluateWithObject:object substitutionVariables:nil]; +} + +- (BOOL)evaluateWithObject:(id)object substitutionVariables:(CPDictionary)variables +{ + var result = NO, + count = [_predicates count], + i; + + if (count == 0) + return YES; + + for (i = 0; i < count; i++) + { + var predicate = [_predicates objectAtIndex:i]; + + switch (_type) + { + case CPNotPredicateType: + return ![predicate evaluateWithObject:object substitutionVariables:variables]; + case CPAndPredicateType: + if (i == 0) + result = [predicate evaluateWithObject:object substitutionVariables:variables]; + else + result = result && [predicate evaluateWithObject:object substitutionVariables:variables]; + break; + case CPOrPredicateType: + if ([predicate evaluateWithObject:object substitutionVariables:variables]) + return YES; + break; + } + } + + return result; +} + +@end + +@implementation CPCompoundPredicate (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + self = [super init]; + if (self != nil) + { + _predicates = [coder decodeObjectForKey:@"CPCompoundPredicateSubpredicates"]; + _type = [coder decodeIntForKey:@"CPCompoundPredicateType"]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_predicates forKey:@"CPCompoundPredicateSubpredicates"]; + [coder encodeInt:_type forKey:@"CPCompoundPredicateType"]; +} + +@end diff --git a/Foundation/CPPredicate/CPExpression.j b/Foundation/CPPredicate/CPExpression.j new file mode 100644 index 000000000..03b31012c --- /dev/null +++ b/Foundation/CPPredicate/CPExpression.j @@ -0,0 +1,324 @@ +@import +@import +@import +@import +@import + +/*! + An expression that always returns the same value. +*/ +CPConstantValueExpressionType = 0; +/*! + An expression that always returns the parameter object itself. +*/ +CPEvaluatedObjectExpressionType = 1; +/*! + An expression that always returns whatever value is associated with the key specified by ‘variable’ in the bindings dictionary. +*/ +CPVariableExpressionType = 2; +/*! + An expression that returns something that can be used as a key path. +*/ +CPKeyPathExpressionType = 3; +/*! + An expression that returns the result of evaluating a function. +*/ +CPFunctionExpressionType = 4; +/*! + An expression that defines an aggregate of NSExpression objects. +*/ +CPAggregateExpressionType = 5; +/*! + An expression that filters a collection using a subpredicate. +*/ +CPSubqueryExpressionType = 6; +/*! + An expression that creates a union of the results of two nested expressions. +*/ +CPUnionSetExpressionType = 7; +/*! + An expression that creates an intersection of the results of two nested expressions. +*/ +CPIntersectSetExpressionType = 8; +/*! + An expression that combines two nested expression results by set subtraction. +*/ +CPMinusSetExpressionType = 9; + +/*! + @ingroup foundation + @class CPExpression + @brief CPExpression is used to represent expressions in a predicate. + + Comparison operations in an CPPredicate are based on two expressions, as represented by instances of the CPExpression class. Expressions are created for constant values, key paths, and so on. + + Generally, anywhere in the CPExpression class hierarchy where there is composite API and subtypes that may only reasonably respond to a subset of that API, invoking a method that does not make sense for that subtype will cause an exception to be thrown. +*/ + +@implementation CPExpression : CPObject +{ + int _type; +} + +// Initializing an Expression +/*! + Initializes the receiver with the specified expression type. + @param type The type of the new expression, as defined by CPExpressionType. + @return An initialized CPExpression object of the type type. +*/ +- (id)initWithExpressionType:(int)type +{ + _type = type; + + return self; +} + +//Creating an Expression for a Value +/*! + Returns a new expression that represents a given constant value. + @param value The constant value the new expression is to represent. + @return A new expression that represents the constant value. +*/ ++ (CPExpression)expressionForConstantValue:(id)value +{ + return [[CPExpression_constant alloc] initWithValue:value]; +} + +/*! + Returns a new expression that represents the object being evaluated. + @return A new expression that represents the object being evaluated. +*/ ++ (CPExpression)expressionForEvaluatedObject +{ + return [[CPExpression_self alloc] init]; +} + +/*! + Returns a new expression that extracts a value from the variable bindings dictionary for a given key. + @param string The key for the variable to extract from the variable bindings dictionary. + @return A new expression that extracts from the variable bindings dictionary the value for the key string. +*/ ++ (CPExpression)expressionForVariable:(CPString)string +{ + return [[CPExpression_variable alloc] initWithVariable:string]; +} + +/*! + Returns a new expression that invokes valueForKeyPath: with a given key path. + @param keyPath The key path that the new expression should evaluate. + @return A new expression that invokes valueForKeyPath: with keyPath. +*/ ++ (CPExpression)expressionForKeyPath:(CPString)keyPath +{ + return [[CPExpression_keypath alloc] initWithKeyPath:keyPath]; +} + +//Creating a Collection Expression +/*! + Returns a new aggregate expression for a given collection. + @param collection A collection object (an instance of CPArray, CPSet, or CPDictionary) that contains further expressions. + @return A new expression that contains the expressions in collection. +*/ ++ (CPExpression)expressionForAggregate:(CPArray)collection +{ + return [[CPExpression_aggregate alloc] initWithAggregate:collection]; +} + +/*! + Returns a new CPExpression object that represent the union of a given set and collection. + @param left An expression that evaluates to an CPSet object. + @param right An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary). + @return A new CPExpression object that represents the union of left and right. +*/ ++ (CPExpression)expressionForUnionSet:(CPExpression)left with:(CPExpression)right +{ + return [[CPExpression_unionset alloc] initWithLeft:left right:right]; +} + +/*! + Returns a new CPExpression object that represent the intersection of a given set and collection. + @param left An expression that evaluates to an CPSet object. + @param right An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary). + @return A new CPExpression object that represents the intersection of left and right. +*/ ++ (CPExpression)expressionForIntersectSetSet:(CPExpression)left with:(CPExpression)right +{ + return [[CPExpression_intersectset alloc] initWithLeft:left right:right]; +} + +/*! + Returns a new CPExpression object that represent the subtraction of a given collection from a given set. + @param left An expression that evaluates to an CPSet object. + @param left An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary). + @return A new CPExpression object that represents the subtraction of right from left. +*/ ++ (CPExpression)expressionForMinusSet:(CPExpression)left with:(CPExpression)right +{ + return [[CPExpression_minusset alloc] initWithLeft:left right:right]; +} + +// Creating an Expression for a Function +/*! + Returns a new expression that will invoke one of the predefined functions. + @param function_name The name of the function to invoke. + @param parameters An array containing NSExpression objects that will be used as parameters during the invocation of selector. + + For a selector taking no parameters, the array should be empty. For a selector taking one or more parameters, the array should contain one NSExpression object which will evaluate to an instance of the appropriate type for each parameter. + + If there is a mismatch between the number of parameters expected and the number you provide during evaluation, an exception may be raised or missing parameters may simply be replaced by nil (which occurs depends on how many parameters are provided, and whether you have over- or underflow). + @return A new expression that invokes the function name using the parameters in parameters. + + The name parameter can be one of the following predefined functions: + @verbatim + name parameter array contents returns + ------------------------------------------------------------------------------------------------------------------------------------- + sum: CPExpression instances representing numbers CPNumber + count: CPExpression instances representing numbers CPNumber + min: CPExpression instances representing numbers CPNumber + max: CPExpression instances representing numbers CPNumber + average: CPExpression instances representing numbers CPNumber + median: CPExpression instances representing numbers CPNumber + mode: CPExpression instances representing numbers CPArray (returned array will contain all occurrences of the mode) + stddev: CPExpression instances representing numbers CPNumber + add:to: CPExpression instances representing numbers CPNumber + from:subtract: two CPExpression instances representing numbers CPNumber + multiply:by: two CPExpression instances representing numbers CPNumber + divide:by: two CPExpression instances representing numbers CPNumber + modulus:by: two CPExpression instances representing numbers CPNumber + sqrt: one CPExpression instance representing numbers CPNumber + log: one CPExpression instance representing a number CPNumber + ln: one CPExpression instance representing a number CPNumber + raise:toPower: one CPExpression instance representing a number CPNumber + exp: one CPExpression instance representing a number CPNumber + floor: one CPExpression instance representing a number CPNumber + ceiling: one CPExpression instance representing a number CPNumber + abs: one CPExpression instance representing a number CPNumber + trunc: one CPExpression instance representing a number CPNumber + uppercase: one CPExpression instance representing a string CPString + lowercase: one CPExpression instance representing a string CPString + random none CPNumber (integer) + random: one CPExpression instance representing a number CPNumber (integer) such that 0 <= rand < param + now none [CPDate now] + bitwiseAnd:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) + bitwiseOr:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) + bitwiseXor:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) + leftshift:by: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) + rightshift:by: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) + onesComplement: one CPExpression instance representing a numbers CPNumber (numbers will be treated as CPInteger) + @endverbatim + + This method raises an exception immediately if the selector is invalid; it raises an exception at runtime if the parameters are incorrect. +*/ ++ (CPExpression)expressionForFunction:(CPString)function_name arguments:(CPArray)parameters +{ + return [[CPExpression_function alloc] initWithSelector:CPSelectorFromString(function_name) arguments:parameters]; +} + +/*! + Returns an expression which will return the result of invoking on a given target a selector with a given name using given arguments. + @param target A CPExpression object which will evaluate an object on which the selector identified by name may be invoked. + @param function_name The name of the method to be invoked. + @param parameters An array containing CPExpression objects which can be evaluated to provide parameters for the method specified by name. + @return An expression which will return the result of invoking the selector named name on the result of evaluating the target expression with the parameters specified by evaluating the elements of parameters. + See the description of expressionForFunction:arguments: for examples of how to construct the parameter array. +*/ ++ (CPExpression)expressionForFunction:(CPExpression)target selectorName:(CPString)function_name arguments:(CPArray)parameters +{ + return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(function_name) arguments:parameters]; +} + + ++ (CPExpression)expressionForSubquery:(CPExpression)expression usingIteratorVariable:(CPString)variable predicate:(id)predicate +{ + return nil; // UNIMPLEMENTED +} + + +// Getting Information About an Expression +/*! + Returns the expression type for the receiver. + @return The expression type for the receiver. + This method raises an exception if it is not applicable to the receiver. +*/ +- (int)expressionType +{ + return _type; +} + +/*! + Returns the constant value of the receiver. + @return The constant value of the receiver. + This method raises an exception if it is not applicable to the receiver. +*/ +- (id)constantValue +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPConstantValueExpressionType"]; + return nil; +} + +/*! + Returns the variable for the receiver. + @return The variable for the receiver. + This method raises an exception if it is not applicable to the receiver. +*/ +- (CPString)variable +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPVariableExpressionType"]; + return nil; +} + +/*! + Returns the key path for the receiver. + @return The key path for the receiver. + This method raises an exception if it is not applicable to the receiver. +*/ +- (CPString)keyPath +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPKeyPathExpressionType"]; + return nil; +} + +/*! + Returns the function for the receiver. + @return The function for the receiver. + This method raises an exception if it is not applicable to the receiver. +*/ +- (CPString)function +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPFunctionExpressionType"]; + return nil; +} + +/*! + Returns the arguments for the receiver. + @return The arguments for the receiver—that is, the array of expressions that will be passed as parameters during invocation of the selector on the operand of a function expression. + This method raises an exception if it is not applicable to the receiver. +*/ +- (CPArray)arguments +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPFunctionExpressionType"]; + return nil; +} + +/*! + Returns the collection of expressions in an aggregate expression, or the collection element of a subquery expression. + @return Returns the collection of expressions in an aggregate expression, or the collection element of a subquery expression. + This method raises an exception if it is not applicable to the receiver. +*/ +- (id)collection +{ + [CPException raise:CPInvalidArgumentException reason:@"self is not of CPAggregateExpressionType"]; + return nil; +} + +@end + +@import "CPExpression_constant.j" +@import "CPExpression_self.j" +@import "CPExpression_variable.j" +@import "CPExpression_keypath.j" +@import "CPExpression_function.j" +@import "CPExpression_aggregate.j" +@import "CPExpression_unionset.j" +@import "CPExpression_intersectset.j" +@import "CPExpression_minusset.j" diff --git a/Foundation/CPPredicate/CPExpression_aggregate.j b/Foundation/CPPredicate/CPExpression_aggregate.j new file mode 100644 index 000000000..01a123b4c --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_aggregate.j @@ -0,0 +1,107 @@ + +@import "CPExpression.j" +@import +@import + +@implementation CPExpression_aggregate : CPExpression +{ + CPArray _aggregate; +} + +- (id)initWithAggregate:(CPArray)collection +{ + [super initWithExpressionType:CPAggregateExpressionType]; + _aggregate = collection; + return self; +} + ++ (CPExpression)expressionForAggregate:(CPArray)collection +{ + return [[self alloc] initWithAggregate:collection]; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var aggregate = [coder decodeObjectForKey:@"CPExpressionAggregate"]; + return [self initWithAggregate:aggregate]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_aggregate forKey:@"CPExpressionAggregate"]; // subexpressions must be CPCoding compliant. +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object collection] isEqual:[self collection]]) + return NO; + + return YES; +} + +- (id)collection +{ + return _aggregate; +} + +- (CPExpression)rightExpression +{ + if ([_aggregate count] > 0) + return [_aggregate lastObject]; + + return nil; +} + +- (CPExpression)leftExpression +{ + if ([_aggregate count] > 0) + return [_aggregate objectAtIndex:0]; + + return nil; +} + +- (id)expressionValueWithObject:(id)object context:(CPDictionary)context +{ + var eval_array = [CPArray array], + collection = [_aggregate objectEnumerator], + exp; + + while (exp = [collection nextObject]) + { + var eval = [exp expressionValueWithObject:object context:context]; + if (eval != nil)[eval_array addObject:eval]; + } + + return eval_array; +} + +- (CPString)description +{ + var i, + count = [_aggregate count], + result = "{"; + + for (i = 0;i < count;i++) + result = result + [CPString stringWithFormat:@"%s%s", [[_aggregate objectAtIndex:i] description], (i + 1 < count) ? @", " : @""]; + + result = result + "}"; + + return result; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + var subst_array = [CPArray array], + count = [_aggregate count], + i; + + for (i = 0; i < count; i++) + [subst_array addObject:[[_aggregate objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; + + return [CPExpression expressionForAggregate:subst_array]; +} + +@end diff --git a/Foundation/CPPredicate/CPExpression_assignment.j b/Foundation/CPPredicate/CPExpression_assignment.j new file mode 100644 index 000000000..771119fd4 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_assignment.j @@ -0,0 +1,92 @@ + +@import "CPExpression.j" +@import "CPExpression_variable.j" +@import + + +@implementation CPExpression_assignment: CPExpression +{ + CPExpression_variable _assignmentVariable; + CPExpression _subexpression; +} + +- (id)initWithAssignmentVariable:(CPString)variable expression:(CPExpression)expression +{ + _assignmentVariable = [CPExpression expressionForVariable:variable]; + _subexpression = expression; + + return self; +} + +- (id)initWithAssignmentExpression:(CPExpression)variableExpression expression:(CPExpression)expression +{ + _assignmentVariable = variableExpression; + _subexpression = expression; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var variable = [coder decodeObjectForKey:@"CPExpressionAssignmentVariable"]; + var expression = [coder decodeObjectForKey:@"CPExpressionAssignmentExpression"]; + + return [self initWithAssignmentVariable:variable expression:expression]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_assignmentVariable forKey:@"CPExpressionAssignmentVariable"]; + [coder encodeObject:_subexpression forKey:@"CPExpressionAssignmentExpression"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object subexpression] isEqual:[self subexpression]] || ![[object variable] isEqualToString:[self variable]]) + return NO; + + return YES; +} + +- (CPExpression)assignmentVariable +{ + return _assignmentVariable; +} + +- (CPExpression)subexpression +{ + return _subexpression; +} + +- (CPString)variable +{ + return [_assignmentVariable variable]; +} + +- (CPString)description +{ + var pretty = [_expression description]; + + if ([_subexpression isKindOfClass:[CPExpression_operator class]]) + pretty = [CPString stringWithFormat:@"(%@)", pretty]; + + return [CPString stringWithFormat:@"%@ := %@", [self variable], pretty]; +} + +- (id)expressionValueWithObject:(id)object context:(id)context +{ + // UNIMPLEMENTED + return nil; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + // UNIMPLEMENTED + return nil; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_constant.j b/Foundation/CPPredicate/CPExpression_constant.j new file mode 100644 index 000000000..af6ed19d4 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_constant.j @@ -0,0 +1,65 @@ + +@import "CPExpression.j" +@import + +@implementation CPExpression_constant : CPExpression +{ + id _value; +} + +- (id)initWithValue:(id)value +{ + [super initWithExpressionType:CPConstantValueExpressionType]; + _value = value; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var value = [coder decodeObjectForKey:@"CPExpressionConstantValue"]; + + return [self initWithValue:value]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_value forKey:@"CPExpressionConstantValue"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object constantValue] isEqual:[self constantValue]]) + return NO; + + return YES; +} + +- (id)constantValue +{ + return _value; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + return _value; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + return self; +} + +- (CPString)description +{ + if ([_value isKindOfClass:[CPString class]]) + return @"\"" + _value + @"\""; + + return [_value description]; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_function.j b/Foundation/CPPredicate/CPExpression_function.j new file mode 100644 index 000000000..539f947f0 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_function.j @@ -0,0 +1,373 @@ + +@import "CPExpression.j" +@import +@import +@import + +@implementation CPExpression_function : CPExpression +{ + CPExpression _operand; + SEL _selector; + CPArray _arguments; + int _argc; +} + +- (id)initWithSelector:(SEL)aselector arguments:(CPArray)parameters +{ + [super initWithExpressionType:CPFunctionExpressionType]; + + if (![self respondsToSelector:aselector]) + [CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector]; + + _selector = aselector; + _operand = nil; + _arguments = parameters; + _argc = [parameters count]; + + return self; +} + +- (id)initWithTarget:(CPExpression)targetExpression selector:(SEL)aselector arguments:(CPArray)parameters +{ + [super initWithExpressionType:CPFunctionExpressionType]; + + var target = [targetExpression expressionValueWithObject:object context:context]; + if (![target respondsToSelector:aselector]) + [CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector]; + + _selector = aselector; + _operand = targetExpression; + _arguments = parameters; + _argc = [parameters count]; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var selector = CPSelectorFromString([coder decodeObjectForKey:@"CPExpressionFunctionName"]); + var arguments = [coder decodeObjectForKey:@"CPExpressionFunctionArguments"]; + + return [self initWithSelector:selector arguments:arguments]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:[self _function] forKey:@"CPExpressionFunctionName"]; + [coder encodeObject:_arguments forKey:@"CPExpressionArguments"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object _function] isEqualToString:[self _function]] || ![[object operand] isEqual:[self operand]] || ![[object arguments] isEqualToArray:[self arguments]]) + return NO; + + return YES; +} + +- (CPString)_function // OBJJ preprocessor does not like function as a method +{ + return CPStringFromSelector(_selector); +} + +- (CPString)function +{ + return [self _function]; +} + +- (CPArray)arguments +{ + return _arguments; +} + +- (CPExpression)operand +{ + return _operand; +} + +- (id)expressionValueWithObject:(id)object context:(CPDictionary)context +{ + var eval_args = [CPArray array], + i; + + for (i = 0; i < _argc; i++) + { + var arg = [[_arguments objectAtIndex:i] expressionValueWithObject:object context:context]; + if (arg != nil) + [eval_args addObject:arg]; + } + + var target = (_operand == nil) ? self : [_operand expressionValueWithObject:object context:context]; + return [target performSelector:_selector withObject:eval_args]; +} + +- (CPString)description +{ + var result = [CPString stringWithFormat:@"%@ %s(", [_operand description], [self _function]], + i; + + for (i = 0; i < _argc; i++) + result = result + [_arguments objectAtIndex:i] + (i+1<_argc) ? ", " : ""; + + result = result + ")"; + + return result ; +} + + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + var array = [CPArray array], + i; + + for (i = 0; i < _argc; i++) + [array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; + + return [CPExpression expressionForFunction:[self operand] selectorName:[self _function] arguments:array]; +} + +- (CPNumber)sum:(CPArray)parameters +{ + if (_argc < 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var i, + sum = 0.0; + + for (i = 0; i < _argc; i++) + sum += [[parameters objectAtIndex:i] doubleValue]; + + return [CPNumber numberWithDouble: sum]; +} + +- (CPNumber)count:(CPArray)parameters +{ + if (_argc < 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return [CPNumber numberWithUnsignedInt: [[parameters objectAtIndex:0] count]]; +} + +- (CPNumber)min:(CPArray)parameters +{ + if (_argc < 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return MIN([parameters objectAtIndex:0],[parameters objectAtIndex:1]); +} + +- (CPNumber)max:(CPArray)parameters +{ + if (_argc < 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return MAX([parameters objectAtIndex:0],[parameters objectAtIndex:1]); +} + +- (CPNumber)average:(CPArray)parameters +{ + if (_argc < 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var i, + sum = 0.0; + + for (i = 0; i < _argc; i++) + sum += [[parameters objectAtIndex:i] doubleValue]; + + return [CPNumber numberWithDouble: sum / _argc]; +} + +- (CPNumber)add:to:(CPArray)parameters +{ + if (_argc != 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + return [CPNumber numberWithDouble: [left doubleValue] + [right doubleValue]]; +} + +- (CPNumber)from:subtract:(CPArray)parameters +{ + if (_argc != 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + return [CPNumber numberWithDouble: [left doubleValue] - [right doubleValue]]; +} + +- (CPNumber)multiply:by:(CPArray)parameters +{ + if (_argc != 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + return [CPNumber numberWithDouble: [left doubleValue] * [right doubleValue]]; +} + +- (CPNumber)divide:by:(CPArray)parameters +{ + if (_argc != 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + return [CPNumber numberWithDouble: [left doubleValue] / [right doubleValue]]; +} + +- (CPNumber)sqrt:(CPArray)parameters +{ + if (_argc != 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue]; + + return [CPNumber numberWithDouble: SQRT(num)]; +} + +- (CPNumber)raise:to:(CPArray)parameters +{ + if (_argc < 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue], + power = [[parameters objectAtIndex:1] doubleValue]; + + return [CPNumber numberWithDouble: POW(num,power)]; +} + +- (CPNumber)abs:(CPArray)parameters +{ + if (_argc != 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue]; + + return [CPNumber numberWithDouble:ABS(num)]; +} + +- (CPDate)now +{ + return [CPDate date]; +} + +- (CPNumber)ln:(CPArray)parameters +{ + if (_argc != 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue]; + + return [CPNumber numberWithDouble:Math.log(num)]; +} + +- (CPNumber)exp:(CPArray)parameters +{ + if (_argc != 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue]; + + return [CPNumber numberWithDouble:EXP(num)]; +} + +- (CPNumber)ceiling:(CPArray)parameters +{ + if (_argc != 1) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var num = [[parameters objectAtIndex:0] doubleValue]; + + return [CPNumber numberWithDouble:CEIL(num)]; +} + +- (CPNumber)random +{ + return [CPNumber numberWithDouble:RAND()]; +} + +- (CPNumber)modulus:by:(CPArray)parameters +{ + if (_argc != 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + return [CPNumber numberWithInt:([left intValue] % [right intValue])]; +} + + +- (id)first:(CPArray)parameters +{ + if (_argc == 0) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return [[parameters objectAtIndex:0] objectAtIndex:0]; +} + +- (id)last:(CPArray)parameters +{ + if (_argc == 0) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return [[parameters objectAtIndex:0] lastObject]; +} + +- (CPNumber)chs:(CPArray)parameters +{ + if (_argc == 0) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + return [CPNumber numberWithInt: - [[parameters objectAtIndex:0] intValue]]; +} + +- (id)index:(CPArray)parameters +{ + if (_argc < 2) + [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + + var left = [parameters objectAtIndex:0], + right = [parameters objectAtIndex:1]; + + if ([left isKindOfClass: [CPDictionary class]]) + return [left objectForKey:right]; + else + return [left objectAtIndex: [right intValue]]; +} + +/* +- (CPNumber)median:(CPArray)parameters +{ +} +- (CPNumber)mode:(CPArray)parameters +{ +} +- (CPNumber)stddev:(CPArray)parameters +{ +} +- (CPNumber)log:(CPArray)parameters +{ +} +- (CPNumber)raise:to:(CPArray)parameters +{ +} +- (CPNumber)trunc:(CPArray)parameters +{ +} + +// These functions are used when parsing +*/ + +@end + diff --git a/Foundation/CPPredicate/CPExpression_intersectset.j b/Foundation/CPPredicate/CPExpression_intersectset.j new file mode 100644 index 000000000..f2f6f3a23 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_intersectset.j @@ -0,0 +1,86 @@ + +@import "CPExpression.j" + +@implementation CPExpression_intersectset : CPExpression +{ + CPExpression _left; + CPExpression _right; +} + +- (id)initWithLeft:(CPExpression)left right:(CPExpression)right +{ + [super initWithExpressionType:CPIntersectSetExpressionType]; + _left = left ; + _right = right; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"]; + var right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; + + return [self initWithLeft:left right:right]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"]; + [coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) + return NO; + + return YES; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + var right = [_right expressionValueWithObject:object context:context]; + if (![right respondsToSelector: @selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; + + var left = [_left expressionValueWithObject:object context:context]; + if (![left isKindOfClass:[CPSet set]]) + [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; + + var set = [CPSet setWithSet:left], + e = [right objectEnumerator], + item; + + while (item = [e nextObject]) + if ([left containsObject:item]) + [set addObject:item]; + + return [CPExpression expressionForConstantValue:set]; +} + +- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables +{ + return self; +} + +- (CPExpression)leftExpression +{ + return _left; +} + +- (CPExpression)rightExpression +{ + return _right; +} + +- (CPString )description +{ + return [_left description] +" INTERSECT "+ [_right description]; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_keypath.j b/Foundation/CPPredicate/CPExpression_keypath.j new file mode 100644 index 000000000..e74c77b71 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_keypath.j @@ -0,0 +1,63 @@ + +@import "CPExpression.j" +@import +@import + +@implementation CPExpression_keypath : CPExpression +{ + CPString _keyPath; +} + +- (id)initWithKeyPath:(CPString)keyPath +{ + [super initWithExpressionType:CPKeyPathExpressionType]; + _keyPath = keyPath ; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var keyPath = [coder decodeObjectForKey:@"CPExpressionKeyPath"]; + + return [self initWithKeyPath:keyPath]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_keyPath forKey:@"CPExpressionKeyPath"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object keyPath] isEqualToString:[self keyPath]]) + return NO; + + return YES; +} + +- (CPString)keyPath +{ + return _keyPath; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + return [object valueForKeyPath:_keyPath]; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + return self; +} + +- (CPString)description +{ + return _keyPath; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_minusset.j b/Foundation/CPPredicate/CPExpression_minusset.j new file mode 100644 index 000000000..528580a9b --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_minusset.j @@ -0,0 +1,81 @@ + +@import "CPExpression.j" + +@implementation CPExpression_minusset : CPExpression + +- (id)initWithLeft:(CPExpression)left right:(CPExpression)right +{ + [super initWithExpressionType:CPMinusSetExpressionType]; + _left = left ; + _right = right; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var left = [coder decodeObjectForKey:@"CPExpressionMinusSetLeftExpression"]; + var right = [coder decodeObjectForKey:@"CPExpressionMinusSetRightExpression"]; + + return [self initWithLeft:left right:right]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_left forKey:@"CPExpressionMinusSetLeftExpression"]; + [coder encodeObject:_right forKey:@"CPExpressionMinusSetRightExpression"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) + return NO; + + return YES; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + var right = [_right expressionValueWithObject:object context:context]; + if (![right respondsToSelector: @selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; + + var left = [_left expressionValueWithObject:object context:context]; + if (![left isKindOfClass:[CPSet set]]) + [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; + + var set = [CPSet setWithSet:left], + e = [right objectEnumerator], + item; + + while (item = [e nextObject]) + [set removeObject:item]; + + return [CPExpression expressionForConstantValue:set]; +} + +- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables +{ + return self; +} + +- (CPExpression)leftExpression +{ + return _left; +} + +- (CPExpression)rightExpression +{ + return _right; +} + +- (CPString )description +{ + return [_left description] +" MINUS "+ [_right description]; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_operator.j b/Foundation/CPPredicate/CPExpression_operator.j new file mode 100644 index 000000000..3ac7d6450 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_operator.j @@ -0,0 +1,117 @@ + +@import "CPExpression.j" +@import +@import +@import + +var CPExpressionOperatorNegate = "CPExpressionOperatorNegate"; +var CPExpressionOperatorAdd = "CPExpressionOperatorAdd"; +var CPExpressionOperatorSubtract = "CPExpressionOperatorSubtract"; +var CPExpressionOperatorMultiply = "CPExpressionOperatorMultiply"; +var CPExpressionOperatorDivide = "CPExpressionOperatorDivide"; +var CPExpressionOperatorExp = "CPExpressionOperatorExp"; +var CPExpressionOperatorAssign = "CPExpressionOperatorAssign"; +var CPExpressionOperatorKeypath = "CPExpressionOperatorKeypath"; +var CPExpressionOperatorIndex = "CPExpressionOperatorIndex"; +var CPExpressionOperatorIndexFirst = "CPExpressionOperatorIndexFirst"; +var CPExpressionOperatorIndexLast = "CPExpressionOperatorIndexLast"; +var CPExpressionOperatorIndexSize = "CPExpressionOperatorIndexSize"; + +@implementation CPExpression_operator : CPExpression +{ + int _operator; + CPArray _arguments; +} + +- (id)initWithOperator:(int)operator arguments:(CPArray)arguments +{ + _operator = operator; + _arguments = arguments; + return self; +} + ++ (CPExpression)expressionForOperator:(CPExpressionOperator)operator arguments:(CPArray)arguments +{ + return [self initWithOperator:operator arguments:arguments]; +} + +- (CPArray)arguments +{ + return _arguments; +} + +- (CPString)description +{ + var result = [CPString string], + args = [CPArray array], + count = [_arguments count], + i; + + for (i = 0; i < count; i++) + { + var check = [_arguments objectAtIndex:i], + precedence = [check description]; + + if ([check isKindOfClass:[CPExpression_operator class]]) + precedence = [CPString stringWithFormat:@"(%@)", precedence]; + + [args addObject:precedence]; + } + + switch (_operator) + { + case CPExpressionOperatorNegate : + result = result + [CPString stringWithFormat:@"-%@", [args objectAtIndex:0]]; + break; + case CPExpressionOperatorAdd : + result = result + [CPString stringWithFormat:@"%@ + %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorSubtract : + result = result + [CPString stringWithFormat:@"%@ - %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorMultiply : + result = result + [CPString stringWithFormat:@"%@ * %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorDivide : + result = result + [CPString stringWithFormat:@"%@ / %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorExp : + result = result + [CPString stringWithFormat:@"%@ ** %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorAssign : + result = result + [CPString stringWithFormat:@"%@ := %@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorKeypath : + result = result + [CPString stringWithFormat:@"%@.%@", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorIndex : + result = result + [CPString stringWithFormat:@"%@[%@]", [args objectAtIndex:0], [args objectAtIndex:1]]; + break; + case CPExpressionOperatorIndexFirst : + result = result + [CPString stringWithFormat:@"%@[FIRST]", [args objectAtIndex:0]]; + break; + case CPExpressionOperatorIndexLast : + result = result + [CPString stringWithFormat:@"%@[LAST]", [args objectAtIndex:0]]; + break; + case CPExpressionOperatorIndexSize : + result = result + [CPString stringWithFormat:@"%@[SIZE]", [args objectAtIndex:0]]; + break; + } + + return result; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + var array = [CPArray array], + count = [_arguments count], + i; + + for (i = 0; i < count; i++) + [array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; + + return [CPExpression_operator expressionForOperator:_operator arguments:array]; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_self.j b/Foundation/CPPredicate/CPExpression_self.j new file mode 100644 index 000000000..bfad66fe5 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_self.j @@ -0,0 +1,46 @@ + +@import "CPExpression.j" +@import +@import +@import + +@implementation CPExpression_self : CPExpression{} + +- (id)init +{ + [super initWithExpressionType:CPEvaluatedObjectExpressionType]; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + return [self init]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ +} + +- (BOOL)isEqual:(id)object +{ + return (object == self); +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + return object; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + return self; +} + +- (CPString)description +{ + return @"SELF"; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_unionset.j b/Foundation/CPPredicate/CPExpression_unionset.j new file mode 100644 index 000000000..cb99edee6 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_unionset.j @@ -0,0 +1,84 @@ + +@import "CPExpression.j" + +@implementation CPExpression_unionset + +- (id)initWithLeft:(CPExpression)left right:(CPExpression)right +{ + [super initWithExpressionType:CPUnionSetExpressionType]; + _left = left; + _right = right; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"]; + var right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; + + return [self initWithLeft:left right:right]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"]; + [coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa + || [object expressionType] != [self expressionType] + || ![[object leftExpression] isEqual:[self leftExpression]] + || ![[object rightExpression] isEqual:[self rightExpression]]) + return NO; + + return YES; +} + +- (id)expressionValueWithObject:object context:(CPDictionary )context +{ + var right = [_right expressionValueWithObject:object context:context]; + if (![right respondsToSelector: @selector(objectEnumerator)]) + [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; + + var left = [_left expressionValueWithObject:object context:context]; + if (![left isKindOfClass:[CPSet set]]) + [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; + + var unionset = [CPSet setWithSet:left], + e = [right objectEnumerator], + item; + + while (item = [e nextObject]) + [unionset addObject:item]; + + return [CPExpression expressionForConstantValue:unionset]; +} + +- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables +{ + return self; +} + +- (CPExpression)leftExpression +{ + return _left; +} + +- (CPExpression)rightExpression +{ + return _right; +} + +- (CPString )description +{ + return [_left description] +" UNION "+ [_right description]; +} + +@end + diff --git a/Foundation/CPPredicate/CPExpression_variable.j b/Foundation/CPPredicate/CPExpression_variable.j new file mode 100644 index 000000000..1b7db6b28 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_variable.j @@ -0,0 +1,68 @@ + +@import "CPExpression.j" +@import +@import + +@implementation CPExpression_variable : CPExpression +{ + CPString _variable; +} + +- (id)initWithVariable:(CPString)variable +{ + [super initWithExpressionType:CPVariableExpressionType]; + _variable = [variable copy]; + + return self; +} + +- (id)initWithCoder:(CPCoder)coder +{ + var variable = [coder decodeObjectForKey:@"CPExpressionVariable"]; + return [self initWithVariable:variable]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_variable forKey:@"CPExpressionVariable"]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object variable] isEqualToString:[self variable]]) + return NO; + + return YES; +} + +- (CPString)variable +{ + return _variable; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + return [context objectForKey:_variable]; +} + +- (CPString)description +{ + return [CPString stringWithFormat:@"$%s", _variable]; +} + +- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables +{ + var aconstant = [variables objectForKey:_variable]; + + if (aconstant != nil) + return [CPExpression expressionForConstantValue:aconstant]; + + return self; +} + + +@end + diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j new file mode 100644 index 000000000..780346bcb --- /dev/null +++ b/Foundation/CPPredicate/CPPredicate.j @@ -0,0 +1,913 @@ + +@import +@import +@import +@import +@import + +/*! + @ingroup foundation + @class CPPredicate + @brief The CPPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering. + + You use predicates to represent logical conditions, used for describing objects in persistent stores and in-memory filtering of objects. Although it is common to create predicates directly from instances of CPComparisonPredicate, CPCompoundPredicate, and CPExpression, you often create predicates from a format string which is parsed by the class methods on CPPredicate. Examples of predicate format strings include: + + Simple comparisons, such as grade == "7" or firstName like "Shaffiq"\n + Case/diacritic insensitive lookups, such as name contains[cd] "itroen"\n + Logical operations, such as (firstName like "Mark") OR (lastName like "Adderley")\n + “Between” predicates such as date between {$YESTERDAY, $TOMORROW}.\n + + You can create predicates for relationships, such as: + + group.name like "work*"\n + ALL children.age > 12\n + ANY children.age > 12\n + You can create predicates for operations, such as @sum.items.price < 1000. + + You can also create predicates that include variables, so that the predicate can be pre-defined before substituting concrete values at runtime with evaluateWithObject:substitutionVariables: method. +*/ + +@implementation CPPredicate : CPObject +{ +} + +/*! + Creates and returns a new predicate formed by creating a new string with a given format and parsing the result. + @param format The format string for the new predicate. + @param … A comma-separated list of arguments to substitute into format. + @return A new predicate formed by creating a new string with format and parsing the result. +*/ + ++ (CPPredicate)predicateWithFormat:(CPString) format, ... +{ + if (!format) + [CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"]; + + var args = Array.prototype.slice.call(arguments, 3); + return [self predicateWithFormat:arguments[2] argumentArray:args]; +} + +/*! + Creates and returns a new predicate by substituting the values in a given array into a format string and parsing the result. + @param format The format string for the new predicate. + @param arguments The arguments to substitute into predicateFormat. Values are substituted into predicateFormat in the order they appear in the array. + @return A new predicate by substituting the values in arguments into predicateFormat, and parsing the result. +*/ ++ (CPPredicate)predicateWithFormat:(CPString)format argumentArray:(CPArray)arguments +{ + if (!format) + [CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"]; + + var s = [[CPPredicateScanner alloc] initWithString:format args:arguments]; + var p = [s parse]; + + return p; +} + +/*! + Creates and returns a new predicate by substituting the values in an argument list into a format string and parsing the result. + @param format The format string for the new predicate. + @param argList The arguments to substitute into predicateFormat. Values are substituted into predicateFormat in the order they appear in the argument list. + @return A new predicate by substituting the values in argList into predicateFormat and parsing the result. +*/ ++ (CPPredicate)predicateWithFormat:(CPString)format arguments:(va_list)argList +{ + // UNIMPLEMENTED + return nil; +} + +/*! + Returns a copy of the receiver with the receiver’s variables substituted by values specified in a given substitution variables dictionary. + @param variables The substitution variables dictionary. The dictionary must contain key-value pairs for all variables in the receiver. + @return A copy of the receiver with the receiver’s variables substituted by values specified in variables. +*/ +- (CPPredicate)predicateWithSubstitutionVariables:(CPDictionary)variables +{ + // IMPLEMENTED BY SUBCLASSES +} + +/*! + Creates and returns a predicate that always evaluates to a given value. + @param value The value to which the new predicate should evaluate. + @return A predicate that always evaluates to value. +*/ ++ (CPPredicate)predicateWithValue:(BOOL)value +{ + return [[CPPredicate_BOOL alloc] initWithBool:value]; +} + +// Evaluating a Predicate +/*! + Returns a Boolean value that indicates whether a given object matches the conditions specified by the receiver. + @param object The object against which to evaluate the receiver. + @return YES if object matches the conditions specified by the receiver, otherwise NO. +*/ +- (BOOL)evaluateWithObject:(id)object +{ + // IMPLEMENTED BY SUBCLASSES +} + +/*! + Returns a Boolean value that indicates whether a given object matches the conditions specified by the receiver after substituting in the values in a given variables dictionary. + @param object The object against which to evaluate the receiver. + @param variables The substitution variables dictionary. The dictionary must contain key-value pairs for all variables in the receiver. + @return YES if object matches the conditions specified by the receiver after substituting in the values in variables for any replacement tokens, otherwise NO. +*/ +- (BOOL)evaluateWithObject:(id)object substitutionVariables:(CPDictionary)variables +{ + // IMPLEMENTED BY SUBCLASSES +} + +// Getting Format Information +/*! + Returns the receiver’s format string. + @return The receiver’s format string. +*/ +- (CPString)predicateFormat +{ + // IMPLEMENTED BY SUBCLASSES +} + +- (CPString)description +{ + return [self predicateFormat]; +} + +@end + +@implementation CPPredicate_BOOL : CPPredicate +{ + BOOL _value; +} + +- (id)initWithBool:(BOOL)value +{ + _value = value; + return self; +} + +- (BOOL)evaluateObject:(id)object +{ + return _value; +} + +- (CPString)predicateFormat +{ + return (_value) ? @"TRUEPREDICATE" : @"FALSEPREDICATE"; +} + +@end + + +@implementation CPArray (CPPredicate) + +- (CPArray)filteredArrayUsingPredicate:(CPPredicate)predicate +{ + var count = [self count], + result = [CPArray array], + i; + + for (i = 0; i < count; i++) + { + var object = [self objectAtIndex:i]; + + if ([predicate evaluateWithObject:object]) + [result addObject:object]; + } + + return result; +} + +- (void)filterUsingPredicate:(CPPredicate)predicate +{ + var count = [self count]; + + while (--count >= 0) + { + var object = [self objectAtIndex:count]; + + if (![predicate evaluateWithObject:object]) + [self removeObjectAtIndex:count]; + } +} + +@end + +@implementation CPSet (CPPredicate) + +- (CPSet)filteredSetUsingPredicate:(CPPredicate)predicate +{ + var count = [self count], + result = [CPSet set], + i; + + for (i = 0; i < count; i++) + { + var object = [self objectAtIndex:i]; + + if ([predicate evaluateWithObject:object]) + [result addObject:object]; + } + + return result; +} + +- (void)filterUsingPredicate:(CPPredicate)predicate +{ + var count = [self count]; + + while (--count >= 0) + { + var object = [self objectAtIndex:count]; + + if (![predicate evaluateWithObject:object]) + [self removeObjectAtIndex:count]; + } +} + +@end + +#define REFERENCE(variable) \ +function(newValue)\ +{\ + var oldValue = variable;\ + if (typeof newValue != 'undefined')\ + variable = newValue;\ + return oldValue;\ +} + +@implementation CPPredicateScanner : CPScanner +{ + CPEnumerator _args; + unsigned _retrieved; +} + +- (id) initWithString:(CPString)format args:(CPArray)args +{ + self = [super initWithString:format]; + if (self != nil) + { + _args = [args objectEnumerator]; + } + return self; +} + +- (id) nextArg +{ + return [_args nextObject]; +} + +- (BOOL)scanPredicateKeyword:(CPString)key +{ + var loc = [self scanLocation]; + var c; + + [self setCaseSensitive:NO]; + if (![self scanString:key intoString:NULL]) + return NO; + + if ([self isAtEnd]) + return YES; + + c = [[self string] characterAtIndex:[self scanLocation]]; + if (![[CPCharacterSet alphanumericCharacterSet] characterIsMember:c]) + return YES; + + [self setScanLocation:loc]; + + return NO; +} + +- (CPPredicate) parse +{ + var r = nil; + + try + { + [self setCharactersToBeSkipped:[CPCharacterSet whitespaceCharacterSet]]; + r = [self parsePredicate]; + } + catch(error) + { + CPLogConsole(@"Parsing failed for "+[self string]+" with " + error); + } + finally + { + if (![self isAtEnd]) + CPLogConsole(@"Format string contains extra characters: \""+[self string]+"\""); + } + + return r; +} + +- (CPPredicate) parsePredicate +{ + return [self parseAnd]; +} + +- (CPPredicate) parseAnd +{ + var l = [self parseOr]; + + while ([self scanPredicateKeyword:@"AND"] || [self scanPredicateKeyword:@"&&"]) + { + var r = [self parseOr]; + + if ([r isKindOfClass:[CPCompoundPredicate class]] && [r compoundPredicateType] == CPAndPredicateType) + { + if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPAndPredicateType) + { + [[l subpredicates] addObjectsFromArray:[r subpredicates]]; + } + else + { + [[r subpredicates] insertObject:l atIndex:0]; + l = r; + } + } + else if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPAndPredicateType) + { + [[l subpredicates] addObject:r]; + } + else + { + l = [CPCompoundPredicate andPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r, nil]]; + } + } + return l; +} + +- (CPPredicate) parseNot +{ + if ([self scanString:@"(" intoString:NULL]) + { + var r = [self parsePredicate]; + + if (![self scanString:@")" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing ) in compound predicate"]; + + return r; + } + + if ([self scanPredicateKeyword:@"NOT"] || [self scanPredicateKeyword:@"!"]) + { + return [CPCompoundPredicate notPredicateWithSubpredicate:[self parseNot]]; + } + if ([self scanPredicateKeyword:@"TRUEPREDICATE"]) + { + return [CPPredicate predicateWithValue:YES]; + } + if ([self scanPredicateKeyword:@"FALSEPREDICATE"]) + { + return [CPPredicate predicateWithValue:NO]; + } + + return [self parseComparison]; +} + +- (CPPredicate) parseOr +{ + var l = [self parseNot]; + while ([self scanPredicateKeyword:@"OR"] || [self scanPredicateKeyword:@"||"]) + { + var r = [self parseNot]; + + if ([r isKindOfClass:[CPCompoundPredicate class]] && [r compoundPredicateType] == CPOrPredicateType) + { + if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPOrPredicateType) + { + [[l subpredicates] addObjectsFromArray:[r subpredicates]]; + } + else + { + [[r subpredicates] insertObject:l atIndex:0]; + l = r; + } + } + else if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPOrPredicateType) + { + [[l subpredicates] addObject:r]; + } + else + { + l = [CPCompoundPredicate orPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r, nil]]; + } + } + return l; +} + +- (CPPredicate) parseComparison +{ + var modifier = CPDirectPredicateModifier, + type = 0, + opts = 0, + left, + right, + p, + negate = NO, + swap = NO; + + if ([self scanPredicateKeyword:@"ANY"]) + { + modifier = CPAnyPredicateModifier; + } + else if ([self scanPredicateKeyword:@"ALL"]) + { + modifier = CPAllPredicateModifier; + } + else if ([self scanPredicateKeyword:@"NONE"]) + { + modifier = CPAnyPredicateModifier; + negate = YES; + } + else if ([self scanPredicateKeyword:@"SOME"]) + { + modifier = CPAllPredicateModifier; + negate = YES; + } + + left = [self parseExpression]; + if ([self scanString:@"!=" intoString:NULL] || [self scanString:@"<>" intoString:NULL]) + { + type = CPNotEqualToPredicateOperatorType; + } + else if ([self scanString:@"<=" intoString:NULL] || [self scanString:@"=<" intoString:NULL]) + { + type = CPLessThanOrEqualToPredicateOperatorType; + } + else if ([self scanString:@">=" intoString:NULL] || [self scanString:@"=>" intoString:NULL]) + { + type = CPGreaterThanOrEqualToPredicateOperatorType; + } + else if ([self scanString:@"<" intoString:NULL]) + { + type = CPLessThanPredicateOperatorType; + } + else if ([self scanString:@">" intoString:NULL]) + { + type = CPGreaterThanPredicateOperatorType; + } + else if ([self scanString:@"==" intoString:NULL] || [self scanString:@"=" intoString:NULL]) + { + type = CPEqualToPredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"MATCHES"]) + { + type = CPMatchesPredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"LIKE"]) + { + type = CPLikePredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"BEGINSWITH"]) + { + type = CPBeginsWithPredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"ENDSWITH"]) + { + type = CPEndsWithPredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"IN"]) + { + type = CPInPredicateOperatorType; + } + else if ([self scanPredicateKeyword:@"CONTAINS"]) + { + type = CPInPredicateOperatorType; + swap = YES; + } + else if ([self scanPredicateKeyword:@"BETWEEN"]) + { + var exp = [self parseSimpleExpression]; + var a = [exp constantValue]; + var lower, upper; + var lexp, uexp; + var lp, up; + + if (![a isKindOfClass:[CPArray class]]) + [CPException raise:CPInvalidArgumentException reason:@"BETWEEN operator requires array argument"]; + + lower = [a objectAtIndex:0]; + upper = [a objectAtIndex:1]; + lexp = [CPExpression expressionForConstantValue:lower]; + uexp = [CPExpression expressionForConstantValue:upper]; + lp = [CPComparisonPredicate predicateWithLeftExpression:left + rightExpression:lexp + modifier:modifier + type:CPGreaterThanPredicateOperatorType + options:opts]; + up = [CPComparisonPredicate predicateWithLeftExpression:left + rightExpression:uexp + modifier:modifier + type:CPLessThanPredicateOperatorType + options:opts]; + return [CPCompoundPredicate andPredicateWithSubpredicates: + [CPArray arrayWithObjects:lp, up, nil]]; + } + else + [CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]]; + + if ([self scanString:@"[cd]" intoString:NULL]) + { + opts = CPCaseInsensitivePredicateOption | CPDiacriticInsensitivePredicateOption; + } + else if ([self scanString:@"[c]" intoString:NULL]) + { + opts = CPCaseInsensitivePredicateOption; + } + else if ([self scanString:@"[d]" intoString:NULL]) + { + opts = CPDiacriticInsensitivePredicateOption; + } + + right = [self parseExpression]; + + if (swap == YES) + { + var tmp = left; + + left = right; + right = tmp; + } + + p = [CPComparisonPredicate predicateWithLeftExpression:left + rightExpression:right + modifier:modifier + type:type + options:opts]; + + return negate ? [CPCompoundPredicate notPredicateWithSubpredicate:p]:p; +} + +- (CPExpression) parseExpression +{ + return [self parseBinaryExpression]; +} + +- (CPExpression) parseSimpleExpression +{ + var identifier, + location, + ident, + dbl; + + if ([self scanDouble:REFERENCE(dbl)]) + return [CPExpression expressionForConstantValue:[CPNumber numberWithDouble:dbl]]; + + // FIXME: handle integer, hex constants, 0x 0o 0b + if ([self scanString:@"-" intoString:NULL]) + return [CPExpression expressionForFunction:@"chs" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + + if ([self scanString:@"(" intoString:NULL]) + { + var arg = [self parseExpression]; + + if (![self scanString:@")" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing ) in expression"]; + + return arg; + } + + if ([self scanString:@"{" intoString:NULL]) + { + var a = [CPMutableArray arrayWithCapacity:10]; + + if ([self scanString:@"}" intoString:NULL]) + return [CPExpression expressionForConstantValue:a]; + + [a addObject:[self parseExpression]]; + while ([self scanString:@"," intoString:NULL]) + [a addObject:[self parseExpression]]; + + if (![self scanString:@"}" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing } in aggregate"]; + + return [CPExpression expressionForConstantValue:a]; + } + + if ([self scanPredicateKeyword:@"NULL"] || [self scanPredicateKeyword:@"NIL"]) + { + return [CPExpression expressionForConstantValue:[CPNull null]]; + } + if ([self scanPredicateKeyword:@"TRUE"] || [self scanPredicateKeyword:@"YES"]) + { + return [CPExpression expressionForConstantValue:[CPNumber numberWithBool:YES]]; + } + if ([self scanPredicateKeyword:@"FALSE"] || [self scanPredicateKeyword:@"NO"]) + { + return [CPExpression expressionForConstantValue:[CPNumber numberWithBool:NO]]; + } + if ([self scanPredicateKeyword:@"SELF"]) + { + return [CPExpression expressionForEvaluatedObject]; + } + + if ([self scanString:@"$" intoString:NULL]) + { + var variable = [self parseExpression]; + + if (![variable keyPath]) + [CPException raise:CPInvalidArgumentException reason:@"Invalid variable identifier: " + variable]; + + return [CPExpression expressionForVariable:[variable keyPath]]; + } + + location = [self scanLocation]; + + if ([self scanString:@"%" intoString:NULL]) + { + if ([self isAtEnd] == NO) + { + var c = [[self string] characterAtIndex:[self scanLocation]]; + + switch (c) + { + case '%':// '%%' is treated as '%' + location = [self scanLocation]; + break; + case 'K': + [self setScanLocation:[self scanLocation] + 1]; + return [CPExpression expressionForKeyPath:[self nextArg]]; + case '@': + case 'c': + case 'C': + case 'd': + case 'D': + case 'i': + case 'o': + case 'O': + case 'u': + case 'U': + case 'x': + case 'X': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + [self setScanLocation:[self scanLocation] + 1]; + return [CPExpression expressionForConstantValue:[self nextArg]]; + case 'h': + [self scanString:@"h" intoString:NULL]; + if ([self isAtEnd] == NO) + { + c = [[self string] characterAtIndex:[self scanLocation]]; + if (c == 'i' || c == 'u') + { + [self setScanLocation:[self scanLocation] + 1]; + return [CPExpression expressionForConstantValue:[self nextArg]]; + } + } + break; + case 'q': + [self scanString:@"q" intoString:NULL]; + if ([self isAtEnd] == NO) + { + c = [[self string] characterAtIndex:[self scanLocation]]; + if (c == 'i' || c == 'u' || c == 'x' || c == 'X') + { + [self setScanLocation:[self scanLocation] + 1]; + return [CPExpression expressionForConstantValue:[self nextArg]]; + } + } + break; + } + } + + [self setScanLocation:location]; + } + + if ([self scanString:@"\"" intoString:NULL]) + { + var skip = [self charactersToBeSkipped]; + var str; + + [self setCharactersToBeSkipped:nil]; + if ([self scanUpToString:@"\"" intoString:REFERENCE(str)] == NO) + { + [self setCharactersToBeSkipped:skip]; + [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location]; + } + + [self scanString:@"\"" intoString:NULL]; + [self setCharactersToBeSkipped:skip]; + + return [CPExpression expressionForConstantValue:str]; + } + if ([self scanString:@"'" intoString:NULL]) + { + var skip = [self charactersToBeSkipped]; + var str; + + [self setCharactersToBeSkipped:nil]; + if ([self scanUpToString:@"'" intoString:REFERENCE(str)] == NO) + { + [self setCharactersToBeSkipped:skip]; + [CPException raise:CPInvalidArgumentException reason:@"Invalid single quoted literal at "+location]; + } + + [self scanString:@"'" intoString:NULL]; + [self setCharactersToBeSkipped:skip]; + + return [CPExpression expressionForConstantValue:str]; + } + + if ([self scanString:@"@" intoString:NULL]) + { + var e = [self parseExpression]; + + if (![e keyPath]) + [CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: "+e]; + + return [CPExpression expressionForKeyPath:[e keyPath]+"@"]; + } + + [self scanString:@"#" intoString:NULL]; + if (!identifier) + identifier = [CPCharacterSet characterSetWithCharactersInString:@"_$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"]; + + if (![self scanCharactersFromSet:identifier intoString:REFERENCE(ident)]) + [CPException raise:CPInvalidArgumentException reason:@"Missing identifier: "+[[self string] substringFromIndex:[self scanLocation]]]; + + return [CPExpression expressionForKeyPath:ident]; +} + +- (CPExpression)parseFunctionalExpression +{ + var left = [self parseSimpleExpression]; + + while (YES) + { + if ([self scanString:@"(" intoString:NULL]) + { + // function - this parser allows for (max)(a, b, c) to be properly + // recognized and even (%K)(a, b, c) if %K evaluates to "max" + var args = [CPMutableArray arrayWithCapacity:5]; + + if (![left keyPath]) + [CPException raise:CPInvalidArgumentException reason:@"Invalid function identifier: " + left]; + + if (![self scanString:@")" intoString:NULL]) + { + // any arguments + // first argument + [args addObject:[self parseExpression]]; + while ([self scanString:@"," intoString:NULL]) + { + // more arguments + [args addObject:[self parseExpression]]; + } + + if (![self scanString:@")" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing ) in function arguments"]; + } + left = [CPExpression expressionForFunction:[left keyPath] arguments:args]; + } + else if ([self scanString:@"[" intoString:NULL]) + { + // index expression + if ([self scanPredicateKeyword:@"FIRST"]) + { + left = [CPExpression expressionForFunction:@"first" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + } + else if ([self scanPredicateKeyword:@"LAST"]) + { + left = [CPExpression expressionForFunction:@"last" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + } + else if ([self scanPredicateKeyword:@"SIZE"]) + { + left = [CPExpression expressionForFunction:@"count" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + } + else + { + left = [CPExpression expressionForFunction:@"index" arguments:[CPArray arrayWithObjects:left, [self parseExpression], nil]]; + } + if (![self scanString:@"]" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"]; + } + else if ([self scanString:@"." intoString:NULL]) + { + // keypath - this parser allows for (a).(b.c) + // to be properly recognized + // and even %K.((%K)) if the first %K evaluates to "a" and the + // second %K to "b.c" + var right; + + if (![left keyPath]) + [CPException raise:CPInvalidArgumentException reason:@"Invalid left keypath:" + left]; + + right = [self parseExpression]; + if (![right keyPath]) + [CPException raise:CPInvalidArgumentException reason:@"Invalid right keypath:" + left]; + + // concatenate + left = [CPExpression expressionForKeyPath:[left keyPath]+ "." + [right keyPath]]; + } + else + { + // done with suffixes + return left; + } + } +} + +- (CPExpression)parsePowerExpression +{ + var left = [self parseFunctionalExpression]; + + while (YES) + { + var right; + + if ([self scanString:@"**" intoString:NULL]) + { + right = [self parseFunctionalExpression]; + left = [CPExpression expressionForFunction:@"pow" arguments:[CPArray arrayWithObjects:left, right, nil]]; + } + else + { + return left; + } + } +} + +- (CPExpression)parseMultiplicationExpression +{ + var left = [self parsePowerExpression]; + + while (YES) + { + var right; + + if ([self scanString:@"*" intoString:NULL]) + { + right = [self parsePowerExpression]; + left = [CPExpression expressionForFunction:@"_mul" arguments:[CPArray arrayWithObjects:left, right, nil]]; + } + else if ([self scanString:@"/" intoString:NULL]) + { + right = [self parsePowerExpression]; + left = [CPExpression expressionForFunction:@"_div" arguments:[CPArray arrayWithObjects:left, right, nil]]; + } + else + { + return left; + } + } +} + +- (CPExpression)parseAdditionExpression +{ + var left = [self parseMultiplicationExpression]; + + while (YES) + { + var right; + + if ([self scanString:@"+" intoString:NULL]) + { + right = [self parseMultiplicationExpression]; + left = [CPExpression expressionForFunction:@"_add" arguments:[CPArray arrayWithObjects:left, right, nil]]; + } + else if ([self scanString:@"-" intoString:NULL]) + { + right = [self parseMultiplicationExpression]; + left = [CPExpression expressionForFunction:@"_sub" arguments:[CPArray arrayWithObjects:left, right, nil]]; + } + else + { + return left; + } + } +} + +- (CPExpression)parseBinaryExpression +{ + var left = [self parseAdditionExpression]; + + while (YES) + { + var right; + + if ([self scanString:@":=" intoString:NULL]) // assignment + { + // check left to be a variable? + right = [self parseAdditionExpression]; + // FIXME + } + else + { + return left; + } + } +} + +@end + +@import "CPCompoundPredicate.j" +@import "CPComparisonPredicate.j" + +@import "CPExpression.j" +@import "CPExpression_operator.j" +@import "CPExpression_aggregate.j" +@import "CPExpression_assignment.j" diff --git a/Foundation/Foundation.j b/Foundation/Foundation.j index d6d0822bd..c09ee38e1 100755 --- a/Foundation/Foundation.j +++ b/Foundation/Foundation.j @@ -24,12 +24,15 @@ @import "CPBundle.j" @import "CPCharacterSet.j" @import "CPCoder.j" +@import "CPComparisonPredicate.j" +@import "CPCompoundPredicate.j" @import "CPData.j" @import "CPDate.j" @import "CPDictionary.j" @import "CPEnumerator.j" @import "CPException.j" @import "CPFormatter.j" +@import "CPExpression.j" @import "CPIndexSet.j" @import "CPInvocation.j" @import "CPJSONPConnection.j" @@ -45,6 +48,7 @@ @import "CPObjJRuntime.j" @import "CPOperation.j" @import "CPOperationQueue.j" +@import "CPPredicate.j" @import "CPPropertyListSerialization.j" @import "CPRange.j" @import "CPRunLoop.j" diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j new file mode 100644 index 000000000..80a76e197 --- /dev/null +++ b/Tests/Foundation/CPPredicateTest.j @@ -0,0 +1,187 @@ +@import + +@implementation CPPredicateTest : OJTestCase +{ + CPDictionary dict; +} + +- (id)init +{ + self = [super init]; + if (self != nil) + { + var d, + objects; + + dict = [[CPDictionary alloc] init]; + [dict setObject: @"A Title" forKey:@"title"]; + + var keys = [CPArray arrayWithObjects:@"Name",@"Age",@"Children",nil]; + objects = [CPArray arrayWithObjects:@"John",[CPNumber numberWithInt:34],[CPArray arrayWithObjects:@"Kid1", @"Kid2", nil],nil]; + + d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; + [dict setObject:d forKey:@"Record1"]; + + objects = [CPArray arrayWithObjects:@"Mary",[CPNumber numberWithInt:30],[CPArray arrayWithObjects:@"Kid1", @"Girl1", nil],nil]; + + d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; + [dict setObject:d forKey:@"Record2"]; + + } + return self; +} + +- (void)testExpressionsInit +{ + var expression_keypath = [CPExpression expressionForKeyPath:@"name"]; + [self assertNotNull:expression_keypath message:"KeyPath Expression should not be nil"]; + + var expression_str = [CPExpression expressionForConstantValue:@"j[a-z]an"]; + [self assertNotNull:expression_str message:"ConstantValue Expression should not be nil"]; + + var expression_num = [CPExpression expressionForConstantValue:[CPNumber numberWithInt:1]]; + [self assertNotNull:expression_num message:"ConstantValue Expression should not be nil"]; + + var expression_collection = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d",nil]]; + [self assertNotNull:expression_collection message:"ConstantValue Expression should not be nil"]; + + var expression_var = [CPExpression expressionForVariable:@"variable"]; + [self assertNotNull:expression_var message:"Variable Expression should not be nil"]; + + var expression_function = [CPExpression expressionForFunction:@"sum:" arguments:[CPArray arrayWithObjects:expression_num,expression_num,nil]]; + [self assertNotNull:expression_function message:"Function Expression should not be nil"]; + + var expression_self = [CPExpression expressionForEvaluatedObject]; + [self assertNotNull:expression_self message:"Function Expression should not be nil"]; + + var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num,expression_function,nil]]; + [self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"]; + + var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]]; + [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"]; + + var set = [CPSet setWithObjects:@"a",@"b",@"d",nil]; + var array = [CPArray arrayWithObjects:@"a",@"b",@"d",nil]; + + var expression_intersect = [CPExpression expressionForIntersectSet:set with:array]; + [self assertNotNull:expression_intersect message:"IntersectSet Expression should not be nil"]; + + var expression_unionset = [CPExpression expressionForUnionSet:set with:array]; + [self assertNotNull:expression_unionset message:"UnionSet Expression should not be nil"]; + + var expression_minusset = [CPExpression expressionForMinusSet:set with:array]; + [self assertNotNull:expression_minusset message:"MinusSet Expression should not be nil"]; +} + +- (void)testFunctionExpression +{ + var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[CPArray arrayWithObjects:[CPExpression expressionForConstantValue:1],[CPExpression expressionForConstantValue:2],[CPExpression expressionForConstantValue:3],nil]]; + + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:3] modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; + + [self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"]; +} + +- (void)testVariableExpression +{ + var variable_exp = [CPExpression expressionForVariable:@"variable"]; + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:variable_exp modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; + + var variables = [CPDictionary dictionaryWithObject:20 forKey:@"variable"]; + + [self assertTrue:[pred evaluateWithObject:dict substitutionVariables:variables] message:"'"+ [pred description] + "' should be true"]; +} + +- (void)testOptions +{ + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"àa"] rightExpression:[CPExpression expressionForConstantValue:@"aà"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:3]; + [self assertTrue:[pred evaluateWithObject:nil] message:"/"+ [pred description] + "/ should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"aB"] rightExpression:[CPExpression expressionForConstantValue:@"Ab"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:1]; + [self assertTrue:[pred evaluateWithObject:nil] message:"/"+ [pred description] + "/ should be true"]; +} + +- (void)testModifier +{ + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record2.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Gi"] modifier:CPAnyPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Kid"] modifier:CPAllPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; +} + +- (void)testOperators +{ + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:"Farenight 451"] rightExpression:[CPExpression expressionForConstantValue:"(F|g)\\w+\\s\\d{3}"] modifier:CPDirectPredicateModifier type:CPMatchesPredicateOperatorType options:2]; + [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"b"] rightExpression:[CPExpression expressionForConstantValue:@"[a-c]"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:1]; + [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"Aa"] rightExpression:[CPExpression expressionForConstantValue:@"ab"] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:0]; + [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"Ac"] rightExpression:[CPExpression expressionForConstantValue:@"ab"] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:2]; + [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; + +} + +- (void)testCompoundPredicate +{ + var predOne = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Name"] rightExpression:[CPExpression expressionForConstantValue:@"J"] modifier:CPDirectPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + + var predTwo = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:[CPExpression expressionForConstantValue:[CPNumber numberWithInt:40]] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:0]; + + var pred = [[CPCompoundPredicate alloc] initWithType:CPAndPredicateType subpredicates:[CPArray arrayWithObjects:predOne,predTwo,nil]]; + + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; +} + +- (void)testPredicateParsing +{ + var predicate; +// TEST String + predicate = [CPPredicate predicateWithFormat: @"%K == %@", @"Record1.Name", @"John"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"%K MATCHES[c] %@", @"Record1.Name", @"john"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"%K BEGINSWITH %@", @"Record1.Name", @"Jo"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"(%K == %@) AND (%K == %@)", @"Record1.Name", @"John", @"Record2.Name", @"Mary"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// TEST integer + predicate = [CPPredicate predicateWithFormat: @"%K == %d", @"Record1.Age", 34]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"%K < %d", @"Record1.Age", 40]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"%K BETWEEN %@", @"Record1.Age", [CPArray arrayWithObjects:[CPNumber numberWithInt: 20], [CPNumber numberWithInt:40], nil]]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"Record1.Age BETWEEN {%f,%f}", 20, 40]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"(%K == %d) OR (%K == %d)", @"Record1.Age", 34, @"Record2.Age", 34]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// TEST float + predicate = [CPPredicate predicateWithFormat: @"%K < %f", @"Record1.Age", 40.5]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"%f > %K", 40.5, @"Record1.Age"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// TEST Aggregate + predicate = [CPPredicate predicateWithFormat: @"%@ IN %K", @"Kid1", @"Record1.Children"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; +} + +@end \ No newline at end of file From 30bc304a202e302af0217f1a266fb154356ca2bb Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 4 Aug 2010 20:01:16 -0400 Subject: [PATCH 160/356] Whitespace and style fixes. --- .../CPPredicate/CPComparisonPredicate.j | 72 ++--- Foundation/CPPredicate/CPCompoundPredicate.j | 38 +-- Foundation/CPPredicate/CPPredicate.j | 250 +++++++++--------- 3 files changed, 179 insertions(+), 181 deletions(-) diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j index 25f42bed5..49336963a 100644 --- a/Foundation/CPPredicate/CPComparisonPredicate.j +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -139,7 +139,7 @@ CPBetweenPredicateOperatorType = 100; var CPComparisonPredicateModifier; var CPPredicateOperatorType; -/*! +/*! @ingroup foundation @class CPComparisonPredicate @brief CPComparisonPredicate is a subclass of CPPredicate used to compare expressions. @@ -150,7 +150,7 @@ var CPPredicateOperatorType; { CPExpression _left; CPExpression _right; - + CPComparisonPredicateModifier _modifier; CPPredicateOperatorType _type; unsigned int _options; @@ -199,7 +199,7 @@ var CPPredicateOperatorType; _type = CPCustomSelectorPredicateOperatorType; _options = 0; _customSelector = selector; - + return self; } @@ -217,7 +217,7 @@ var CPPredicateOperatorType; _left = left; _right = right; _modifier = modifier; - _type = type; + _type = type; _options = (type != CPMatchesPredicateOperatorType && type != CPLikePredicateOperatorType && type != CPBeginsWithPredicateOperatorType && @@ -226,7 +226,7 @@ var CPPredicateOperatorType; type != CPContainsPredicateOperatorType) ? 0 : options; _customSelector = NULL; - + return self; } @@ -307,18 +307,18 @@ var CPPredicateOperatorType; } var options; - + switch (_options) { case CPCaseInsensitivePredicateOption: options = "[c]"; - break; + break; case CPDiacriticInsensitivePredicateOption: options = "[d]"; - break; + break; case CPCaseInsensitivePredicateOption | CPDiacriticInsensitivePredicateOption: options = "[cd]"; - break; + break; default: options = ""; break; @@ -384,7 +384,7 @@ var CPPredicateOperatorType; } - (BOOL)_evaluateValue:lhs rightValue:rhs -{ +{ var leftIsNil = (lhs == nil || [lhs isEqual:[CPNull null]]), rightIsNil = (rhs == nil || [rhs isEqual:[CPNull null]]); @@ -393,7 +393,7 @@ var CPPredicateOperatorType; (_type == CPEqualToPredicateOperatorType || _type == CPLessThanOrEqualToPredicateOperatorType || _type == CPGreaterThanOrEqualToPredicateOperatorType)); - + var string_compare_options = 0; // left and right should be casted first [CAST()] following 10.5 rules. @@ -414,15 +414,15 @@ var CPPredicateOperatorType; case CPMatchesPredicateOperatorType: var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g"; if (_options & CPDiacriticInsensitivePredicateOption) - { + { lhs = lhs.stripDiacritics(); rhs = rhs.stripDiacritics(); } - + return (new RegExp(rhs,commut)).test(lhs); - case CPLikePredicateOperatorType: + case CPLikePredicateOperatorType: if (_options & CPDiacriticInsensitivePredicateOption) - { + { lhs = lhs.stripDiacritics(); rhs = rhs.stripDiacritics(); } @@ -447,13 +447,13 @@ var CPPredicateOperatorType; { if (![rhs respondsToSelector: @selector(objectEnumerator)]) [CPException raise:CPInvalidArgumentException reason:@"The right hand side for an IN operator must be a collection"]; - + var e = [rhs objectEnumerator], value; while (value = [e nextObject]) - if ([value isEqual:lhs]) + if ([value isEqual:lhs]) return YES; - + return NO; } @@ -461,38 +461,38 @@ var CPPredicateOperatorType; string_compare_options |= CPCaseInsensitiveSearch; if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch; - + return ([rhs rangeOfString:lhs options:string_compare_options].location != CPNotFound); case CPCustomSelectorPredicateOperatorType: - return [lhs performSelector:_customSelector withObject:rhs]; - case CPContainsPredicateOperatorType: + return [lhs performSelector:_customSelector withObject:rhs]; + case CPContainsPredicateOperatorType: if (![lhs isKindOfClass: [CPString class]]) { if (![lhs respondsToSelector: @selector(objectEnumerator)]) [CPException raise:CPInvalidArgumentException reason:@"The left hand side for a CONTAINS operator must be a collection or a string"]; - + var e = [lhs objectEnumerator], value; while (value = [e nextObject]) - if ([value isEqual:rhs]) + if ([value isEqual:rhs]) return YES; - + return NO; } - + if (_options & CPCaseInsensitivePredicateOption) string_compare_options |= CPCaseInsensitiveSearch; if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch; - - return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound); + + return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound); case CPBetweenPredicateOperatorType: if ([lhs count] < 2) [CPException raise:CPInvalidArgumentException reason:@"The right hand side for a BETWEEN operator must contain 2 objects"]; var lower = [rhs objectAtIndex:0], upper = [rhs objectAtIndex:1]; - + return ([lhs compare:lower] == CPOrderedDescending && [lhs compare:upper] == CPOrderedAscending); default: return NO; @@ -508,13 +508,13 @@ var CPPredicateOperatorType; { var left = _left, right = _right; - - if(variables != nil) + + if (variables != nil) { left = [left _expressionWithSubstitutionVariables:variables]; right = [right _expressionWithSubstitutionVariables:variables]; } - + var leftValue = [left expressionValueWithObject:object context:nil], rightValue = [right expressionValueWithObject:object context:nil]; @@ -532,7 +532,7 @@ var CPPredicateOperatorType; while (value = [e nextObject]) { var eval = [self _evaluateValue:value rightValue:rightValue]; - if (eval != result) + if (eval != result) return eval; } @@ -556,7 +556,7 @@ var CPPredicateOperatorType; _options = [coder decodeIntForKey:@"CPComparisonPredicateOptions"]; _customSelector = [coder decodeObjectForKey:@"CPComparisonPredicateCustomSelector"]; } - + return self; } @@ -590,8 +590,8 @@ String.prototype.escapeForRegExp = function() if (!foundChar) return this; - var result = ""; - var sourceIndex; + var result = "", + sourceIndex; for (var i = 0; i < this.length; ++i) { var sourceIndex = source.indexOf(this.charAt(i)); @@ -600,6 +600,6 @@ String.prototype.escapeForRegExp = function() else result += this.charAt(i); } - + return result; } diff --git a/Foundation/CPPredicate/CPCompoundPredicate.j b/Foundation/CPPredicate/CPCompoundPredicate.j index 86262ece2..1fff80f4a 100644 --- a/Foundation/CPPredicate/CPCompoundPredicate.j +++ b/Foundation/CPPredicate/CPCompoundPredicate.j @@ -48,7 +48,7 @@ var CPCompoundPredicateType; { _type = type; _predicates = predicates; - + return self; } @@ -105,7 +105,7 @@ var CPCompoundPredicateType; { var subp = [CPArray array], i; - + for (i = 0; i < [subp count]; i++) { var p = [subp objectAtIndex:i], @@ -113,7 +113,7 @@ var CPCompoundPredicateType; [subp addObject:sp]; } - + return [[CPCompoundPredicate alloc] initWithType:_type subpredicates:subp]; } @@ -123,39 +123,39 @@ var CPCompoundPredicateType; args = [CPArray array], count = [_predicates count], i; - + if (count == 0) return @"TRUPREDICATE"; - + for (i = 0; i < count; i++) { var subpredicate = [_predicates objectAtIndex:i], precedence = [subpredicate predicateFormat]; - + if ([subpredicate isKindOfClass:[CPCompoundPredicate class]] && [[subpredicate subpredicates] count]> 1 && [subpredicate compoundPredicateType] != _type) precedence = [CPString stringWithFormat:@"(%s)",precedence]; - + if (precedence != nil) [args addObject:precedence]; } - + switch (_type) { case CPNotPredicateType: result += "NOT %s" + [args objectAtIndex:0]; - break; + break; case CPAndPredicateType: result += [args objectAtIndex:0]; for (var j = 1; j < [args count]; j++) result += " AND " + [args objectAtIndex:j]; break; case CPOrPredicateType: - result += [args objectAtIndex:0]; - for(var j=1;j<[args count];j++) + result += [args objectAtIndex:0]; + for (var j = 1; j < [args count]; j++) result += " OR " + [args objectAtIndex:j]; break; - } - + } + return result; } @@ -169,14 +169,14 @@ var CPCompoundPredicateType; var result = NO, count = [_predicates count], i; - + if (count == 0) return YES; - + for (i = 0; i < count; i++) { var predicate = [_predicates objectAtIndex:i]; - + switch (_type) { case CPNotPredicateType: @@ -186,14 +186,14 @@ var CPCompoundPredicateType; result = [predicate evaluateWithObject:object substitutionVariables:variables]; else result = result && [predicate evaluateWithObject:object substitutionVariables:variables]; - break; + break; case CPOrPredicateType: if ([predicate evaluateWithObject:object substitutionVariables:variables]) return YES; break; } } - + return result; } @@ -209,7 +209,7 @@ var CPCompoundPredicateType; _predicates = [coder decodeObjectForKey:@"CPCompoundPredicateSubpredicates"]; _type = [coder decodeIntForKey:@"CPCompoundPredicateType"]; } - + return self; } diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index 780346bcb..d65a1eeaa 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -5,7 +5,7 @@ @import @import -/*! +/*! @ingroup foundation @class CPPredicate @brief The CPPredicate class is used to define logical conditions used to constrain a search either for a fetch or for in-memory filtering. @@ -16,14 +16,14 @@ Case/diacritic insensitive lookups, such as name contains[cd] "itroen"\n Logical operations, such as (firstName like "Mark") OR (lastName like "Adderley")\n “Between” predicates such as date between {$YESTERDAY, $TOMORROW}.\n - + You can create predicates for relationships, such as: group.name like "work*"\n ALL children.age > 12\n ANY children.age > 12\n You can create predicates for operations, such as @sum.items.price < 1000. - + You can also create predicates that include variables, so that the predicate can be pre-defined before substituting concrete values at runtime with evaluateWithObject:substitutionVariables: method. */ @@ -37,12 +37,11 @@ @param … A comma-separated list of arguments to substitute into format. @return A new predicate formed by creating a new string with format and parsing the result. */ - + (CPPredicate)predicateWithFormat:(CPString) format, ... { if (!format) [CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"]; - + var args = Array.prototype.slice.call(arguments, 3); return [self predicateWithFormat:arguments[2] argumentArray:args]; } @@ -57,10 +56,10 @@ { if (!format) [CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"]; - - var s = [[CPPredicateScanner alloc] initWithString:format args:arguments]; - var p = [s parse]; - + + var s = [[CPPredicateScanner alloc] initWithString:format args:arguments], + p = [s parse]; + return p; } @@ -104,7 +103,7 @@ */ - (BOOL)evaluateWithObject:(id)object { - // IMPLEMENTED BY SUBCLASSES + // IMPLEMENTED BY SUBCLASSES } /*! @@ -115,7 +114,7 @@ */ - (BOOL)evaluateWithObject:(id)object substitutionVariables:(CPDictionary)variables { - // IMPLEMENTED BY SUBCLASSES + // IMPLEMENTED BY SUBCLASSES } // Getting Format Information @@ -166,26 +165,26 @@ var count = [self count], result = [CPArray array], i; - + for (i = 0; i < count; i++) { var object = [self objectAtIndex:i]; - + if ([predicate evaluateWithObject:object]) [result addObject:object]; } - + return result; } - (void)filterUsingPredicate:(CPPredicate)predicate { var count = [self count]; - + while (--count >= 0) { var object = [self objectAtIndex:count]; - + if (![predicate evaluateWithObject:object]) [self removeObjectAtIndex:count]; } @@ -200,26 +199,26 @@ var count = [self count], result = [CPSet set], i; - + for (i = 0; i < count; i++) { var object = [self objectAtIndex:i]; - + if ([predicate evaluateWithObject:object]) [result addObject:object]; } - + return result; } - (void)filterUsingPredicate:(CPPredicate)predicate { var count = [self count]; - + while (--count >= 0) { var object = [self objectAtIndex:count]; - + if (![predicate evaluateWithObject:object]) [self removeObjectAtIndex:count]; } @@ -232,10 +231,10 @@ function(newValue)\ {\ var oldValue = variable;\ if (typeof newValue != 'undefined')\ - variable = newValue;\ + variable = newValue;\ return oldValue;\ } - + @implementation CPPredicateScanner : CPScanner { CPEnumerator _args; @@ -261,27 +260,27 @@ function(newValue)\ { var loc = [self scanLocation]; var c; - + [self setCaseSensitive:NO]; if (![self scanString:key intoString:NULL]) return NO; - + if ([self isAtEnd]) return YES; - + c = [[self string] characterAtIndex:[self scanLocation]]; if (![[CPCharacterSet alphanumericCharacterSet] characterIsMember:c]) return YES; - + [self setScanLocation:loc]; - + return NO; } - (CPPredicate) parse { var r = nil; - + try { [self setCharactersToBeSkipped:[CPCharacterSet whitespaceCharacterSet]]; @@ -294,9 +293,9 @@ function(newValue)\ finally { if (![self isAtEnd]) - CPLogConsole(@"Format string contains extra characters: \""+[self string]+"\""); + CPLogConsole(@"Format string contains extra characters: \""+[self string]+"\""); } - + return r; } @@ -308,11 +307,11 @@ function(newValue)\ - (CPPredicate) parseAnd { var l = [self parseOr]; - + while ([self scanPredicateKeyword:@"AND"] || [self scanPredicateKeyword:@"&&"]) { var r = [self parseOr]; - + if ([r isKindOfClass:[CPCompoundPredicate class]] && [r compoundPredicateType] == CPAndPredicateType) { if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPAndPredicateType) @@ -342,17 +341,17 @@ function(newValue)\ if ([self scanString:@"(" intoString:NULL]) { var r = [self parsePredicate]; - + if (![self scanString:@")" intoString:NULL]) - [CPException raise:CPInvalidArgumentException reason:@"Missing ) in compound predicate"]; - + [CPException raise:CPInvalidArgumentException reason:@"Missing ) in compound predicate"]; + return r; } - + if ([self scanPredicateKeyword:@"NOT"] || [self scanPredicateKeyword:@"!"]) { return [CPCompoundPredicate notPredicateWithSubpredicate:[self parseNot]]; - } + } if ([self scanPredicateKeyword:@"TRUEPREDICATE"]) { return [CPPredicate predicateWithValue:YES]; @@ -361,7 +360,7 @@ function(newValue)\ { return [CPPredicate predicateWithValue:NO]; } - + return [self parseComparison]; } @@ -371,7 +370,7 @@ function(newValue)\ while ([self scanPredicateKeyword:@"OR"] || [self scanPredicateKeyword:@"||"]) { var r = [self parseNot]; - + if ([r isKindOfClass:[CPCompoundPredicate class]] && [r compoundPredicateType] == CPOrPredicateType) { if ([l isKindOfClass:[CPCompoundPredicate class]] && [l compoundPredicateType] == CPOrPredicateType) @@ -397,7 +396,7 @@ function(newValue)\ } - (CPPredicate) parseComparison -{ +{ var modifier = CPDirectPredicateModifier, type = 0, opts = 0, @@ -406,7 +405,7 @@ function(newValue)\ p, negate = NO, swap = NO; - + if ([self scanPredicateKeyword:@"ANY"]) { modifier = CPAnyPredicateModifier; @@ -425,7 +424,7 @@ function(newValue)\ modifier = CPAllPredicateModifier; negate = YES; } - + left = [self parseExpression]; if ([self scanString:@"!=" intoString:NULL] || [self scanString:@"<>" intoString:NULL]) { @@ -478,35 +477,35 @@ function(newValue)\ } else if ([self scanPredicateKeyword:@"BETWEEN"]) { - var exp = [self parseSimpleExpression]; - var a = [exp constantValue]; - var lower, upper; - var lexp, uexp; - var lp, up; - + var exp = [self parseSimpleExpression], + a = [exp constantValue], + lower, upper, + lexp, uexp, + lp, up; + if (![a isKindOfClass:[CPArray class]]) [CPException raise:CPInvalidArgumentException reason:@"BETWEEN operator requires array argument"]; - + lower = [a objectAtIndex:0]; upper = [a objectAtIndex:1]; lexp = [CPExpression expressionForConstantValue:lower]; uexp = [CPExpression expressionForConstantValue:upper]; - lp = [CPComparisonPredicate predicateWithLeftExpression:left + lp = [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:lexp - modifier:modifier - type:CPGreaterThanPredicateOperatorType + modifier:modifier + type:CPGreaterThanPredicateOperatorType options:opts]; - up = [CPComparisonPredicate predicateWithLeftExpression:left + up = [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:uexp - modifier:modifier - type:CPLessThanPredicateOperatorType + modifier:modifier + type:CPLessThanPredicateOperatorType options:opts]; return [CPCompoundPredicate andPredicateWithSubpredicates: [CPArray arrayWithObjects:lp, up, nil]]; } else [CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]]; - + if ([self scanString:@"[cd]" intoString:NULL]) { opts = CPCaseInsensitivePredicateOption | CPDiacriticInsensitivePredicateOption; @@ -519,23 +518,23 @@ function(newValue)\ { opts = CPDiacriticInsensitivePredicateOption; } - + right = [self parseExpression]; - + if (swap == YES) { var tmp = left; - + left = right; right = tmp; } - - p = [CPComparisonPredicate predicateWithLeftExpression:left + + p = [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:right - modifier:modifier - type:type + modifier:modifier + type:type options:opts]; - + return negate ? [CPCompoundPredicate notPredicateWithSubpredicate:p]:p; } @@ -550,41 +549,41 @@ function(newValue)\ location, ident, dbl; - + if ([self scanDouble:REFERENCE(dbl)]) return [CPExpression expressionForConstantValue:[CPNumber numberWithDouble:dbl]]; - + // FIXME: handle integer, hex constants, 0x 0o 0b if ([self scanString:@"-" intoString:NULL]) - return [CPExpression expressionForFunction:@"chs" arguments:[CPArray arrayWithObject:[self parseExpression]]]; - + return [CPExpression expressionForFunction:@"chs" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + if ([self scanString:@"(" intoString:NULL]) { var arg = [self parseExpression]; - + if (![self scanString:@")" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing ) in expression"]; - + return arg; } - + if ([self scanString:@"{" intoString:NULL]) { var a = [CPMutableArray arrayWithCapacity:10]; - + if ([self scanString:@"}" intoString:NULL]) return [CPExpression expressionForConstantValue:a]; - + [a addObject:[self parseExpression]]; while ([self scanString:@"," intoString:NULL]) [a addObject:[self parseExpression]]; - + if (![self scanString:@"}" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing } in aggregate"]; - + return [CPExpression expressionForConstantValue:a]; } - + if ([self scanPredicateKeyword:@"NULL"] || [self scanPredicateKeyword:@"NIL"]) { return [CPExpression expressionForConstantValue:[CPNull null]]; @@ -601,33 +600,33 @@ function(newValue)\ { return [CPExpression expressionForEvaluatedObject]; } - + if ([self scanString:@"$" intoString:NULL]) { var variable = [self parseExpression]; - + if (![variable keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid variable identifier: " + variable]; - + return [CPExpression expressionForVariable:[variable keyPath]]; } - + location = [self scanLocation]; - + if ([self scanString:@"%" intoString:NULL]) { if ([self isAtEnd] == NO) { var c = [[self string] characterAtIndex:[self scanLocation]]; - + switch (c) { case '%':// '%%' is treated as '%' location = [self scanLocation]; - break; + break; case 'K': [self setScanLocation:[self scanLocation] + 1]; - return [CPExpression expressionForKeyPath:[self nextArg]]; + return [CPExpression expressionForKeyPath:[self nextArg]]; case '@': case 'c': case 'C': @@ -646,7 +645,7 @@ function(newValue)\ case 'g': case 'G': [self setScanLocation:[self scanLocation] + 1]; - return [CPExpression expressionForConstantValue:[self nextArg]]; + return [CPExpression expressionForConstantValue:[self nextArg]]; case 'h': [self scanString:@"h" intoString:NULL]; if ([self isAtEnd] == NO) @@ -658,7 +657,7 @@ function(newValue)\ return [CPExpression expressionForConstantValue:[self nextArg]]; } } - break; + break; case 'q': [self scanString:@"q" intoString:NULL]; if ([self isAtEnd] == NO) @@ -673,80 +672,80 @@ function(newValue)\ break; } } - + [self setScanLocation:location]; } - + if ([self scanString:@"\"" intoString:NULL]) { - var skip = [self charactersToBeSkipped]; - var str; - + var skip = [self charactersToBeSkipped], + str; + [self setCharactersToBeSkipped:nil]; if ([self scanUpToString:@"\"" intoString:REFERENCE(str)] == NO) { [self setCharactersToBeSkipped:skip]; [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location]; } - + [self scanString:@"\"" intoString:NULL]; [self setCharactersToBeSkipped:skip]; - + return [CPExpression expressionForConstantValue:str]; } if ([self scanString:@"'" intoString:NULL]) { - var skip = [self charactersToBeSkipped]; - var str; - + var skip = [self charactersToBeSkipped], + str; + [self setCharactersToBeSkipped:nil]; if ([self scanUpToString:@"'" intoString:REFERENCE(str)] == NO) { [self setCharactersToBeSkipped:skip]; [CPException raise:CPInvalidArgumentException reason:@"Invalid single quoted literal at "+location]; } - + [self scanString:@"'" intoString:NULL]; [self setCharactersToBeSkipped:skip]; - + return [CPExpression expressionForConstantValue:str]; } - + if ([self scanString:@"@" intoString:NULL]) { var e = [self parseExpression]; - + if (![e keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: "+e]; - + return [CPExpression expressionForKeyPath:[e keyPath]+"@"]; } - + [self scanString:@"#" intoString:NULL]; if (!identifier) identifier = [CPCharacterSet characterSetWithCharactersInString:@"_$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"]; - + if (![self scanCharactersFromSet:identifier intoString:REFERENCE(ident)]) [CPException raise:CPInvalidArgumentException reason:@"Missing identifier: "+[[self string] substringFromIndex:[self scanLocation]]]; - + return [CPExpression expressionForKeyPath:ident]; } - (CPExpression)parseFunctionalExpression { var left = [self parseSimpleExpression]; - + while (YES) { if ([self scanString:@"(" intoString:NULL]) - { - // function - this parser allows for (max)(a, b, c) to be properly + { + // function - this parser allows for (max)(a, b, c) to be properly // recognized and even (%K)(a, b, c) if %K evaluates to "max" var args = [CPMutableArray arrayWithCapacity:5]; - + if (![left keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid function identifier: " + left]; - + if (![self scanString:@")" intoString:NULL]) { // any arguments @@ -757,7 +756,7 @@ function(newValue)\ // more arguments [args addObject:[self parseExpression]]; } - + if (![self scanString:@")" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing ) in function arguments"]; } @@ -789,17 +788,16 @@ function(newValue)\ { // keypath - this parser allows for (a).(b.c) // to be properly recognized - // and even %K.((%K)) if the first %K evaluates to "a" and the + // and even %K.((%K)) if the first %K evaluates to "a" and the // second %K to "b.c" - var right; - + if (![left keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid left keypath:" + left]; - - right = [self parseExpression]; + + var right = [self parseExpression]; if (![right keyPath]) - [CPException raise:CPInvalidArgumentException reason:@"Invalid right keypath:" + left]; - + [CPException raise:CPInvalidArgumentException reason:@"Invalid right keypath:" + right]; + // concatenate left = [CPExpression expressionForKeyPath:[left keyPath]+ "." + [right keyPath]]; } @@ -814,11 +812,11 @@ function(newValue)\ - (CPExpression)parsePowerExpression { var left = [self parseFunctionalExpression]; - + while (YES) { var right; - + if ([self scanString:@"**" intoString:NULL]) { right = [self parseFunctionalExpression]; @@ -834,11 +832,11 @@ function(newValue)\ - (CPExpression)parseMultiplicationExpression { var left = [self parsePowerExpression]; - + while (YES) { var right; - + if ([self scanString:@"*" intoString:NULL]) { right = [self parsePowerExpression]; @@ -859,11 +857,11 @@ function(newValue)\ - (CPExpression)parseAdditionExpression { var left = [self parseMultiplicationExpression]; - + while (YES) { var right; - + if ([self scanString:@"+" intoString:NULL]) { right = [self parseMultiplicationExpression]; @@ -884,11 +882,11 @@ function(newValue)\ - (CPExpression)parseBinaryExpression { var left = [self parseAdditionExpression]; - + while (YES) { var right; - + if ([self scanString:@":=" intoString:NULL]) // assignment { // check left to be a variable? From c694c96a3241a11bebd6fafb9f9b994a7ccf0eba Mon Sep 17 00:00:00 2001 From: cacaodev Date: Mon, 2 Nov 2009 23:55:07 +0100 Subject: [PATCH 161/356] CPPredicate & co style cleaning --- Foundation/CPPredicate/CPCompoundPredicate.j | 11 +++++++---- Foundation/CPPredicate/CPExpression_aggregate.j | 2 +- Foundation/CPPredicate/CPPredicate.j | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Foundation/CPPredicate/CPCompoundPredicate.j b/Foundation/CPPredicate/CPCompoundPredicate.j index 1fff80f4a..7ba504e6a 100644 --- a/Foundation/CPPredicate/CPCompoundPredicate.j +++ b/Foundation/CPPredicate/CPCompoundPredicate.j @@ -104,9 +104,10 @@ var CPCompoundPredicateType; - (CPPredicate)predicateWithSubstitutionVariables:(CPDictionary)variables { var subp = [CPArray array], + count = [subp count]; i; - for (i = 0; i < [subp count]; i++) + for (i = 0; i < count; i++) { var p = [subp objectAtIndex:i], sp = [p predicateWithSubstitutionVariables:variables]; @@ -125,7 +126,7 @@ var CPCompoundPredicateType; i; if (count == 0) - return @"TRUPREDICATE"; + return @"TRUPREDICATE"; for (i = 0; i < count; i++) { @@ -146,12 +147,14 @@ var CPCompoundPredicateType; break; case CPAndPredicateType: result += [args objectAtIndex:0]; - for (var j = 1; j < [args count]; j++) + var count = [args count]; + for (var j = 1; j < count; j++) result += " AND " + [args objectAtIndex:j]; break; case CPOrPredicateType: result += [args objectAtIndex:0]; - for (var j = 1; j < [args count]; j++) + var count = [args count]; + for (var j = 1; j < count; j++) result += " OR " + [args objectAtIndex:j]; break; } diff --git a/Foundation/CPPredicate/CPExpression_aggregate.j b/Foundation/CPPredicate/CPExpression_aggregate.j index 01a123b4c..90b25c8ec 100644 --- a/Foundation/CPPredicate/CPExpression_aggregate.j +++ b/Foundation/CPPredicate/CPExpression_aggregate.j @@ -84,7 +84,7 @@ count = [_aggregate count], result = "{"; - for (i = 0;i < count;i++) + for (i = 0; i < count; i++) result = result + [CPString stringWithFormat:@"%s%s", [[_aggregate objectAtIndex:i] description], (i + 1 < count) ? @", " : @""]; result = result + "}"; diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index d65a1eeaa..ce06129dd 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -181,7 +181,7 @@ { var count = [self count]; - while (--count >= 0) + while (count--) { var object = [self objectAtIndex:count]; From a3c0590218964c04b6c8326637235067f221ac9b Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 22:32:03 -0400 Subject: [PATCH 162/356] Fixed with CPPredicate: [CPArray arrayWithObjects:...] should no longer be terminated with a nil in Cappuccino. --- Foundation/CPPredicate/CPPredicate.j | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index ce06129dd..bd992b978 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -330,7 +330,7 @@ function(newValue)\ } else { - l = [CPCompoundPredicate andPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r, nil]]; + l = [CPCompoundPredicate andPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r]]; } } return l; @@ -389,7 +389,7 @@ function(newValue)\ } else { - l = [CPCompoundPredicate orPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r, nil]]; + l = [CPCompoundPredicate orPredicateWithSubpredicates:[CPArray arrayWithObjects:l, r]]; } } return l; @@ -501,7 +501,7 @@ function(newValue)\ type:CPLessThanPredicateOperatorType options:opts]; return [CPCompoundPredicate andPredicateWithSubpredicates: - [CPArray arrayWithObjects:lp, up, nil]]; + [CPArray arrayWithObjects:lp, up]]; } else [CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]]; @@ -779,7 +779,7 @@ function(newValue)\ } else { - left = [CPExpression expressionForFunction:@"index" arguments:[CPArray arrayWithObjects:left, [self parseExpression], nil]]; + left = [CPExpression expressionForFunction:@"index" arguments:[CPArray arrayWithObjects:left, [self parseExpression]]]; } if (![self scanString:@"]" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"]; @@ -820,7 +820,7 @@ function(newValue)\ if ([self scanString:@"**" intoString:NULL]) { right = [self parseFunctionalExpression]; - left = [CPExpression expressionForFunction:@"pow" arguments:[CPArray arrayWithObjects:left, right, nil]]; + left = [CPExpression expressionForFunction:@"pow" arguments:[CPArray arrayWithObjects:left, right]]; } else { @@ -840,12 +840,12 @@ function(newValue)\ if ([self scanString:@"*" intoString:NULL]) { right = [self parsePowerExpression]; - left = [CPExpression expressionForFunction:@"_mul" arguments:[CPArray arrayWithObjects:left, right, nil]]; + left = [CPExpression expressionForFunction:@"_mul" arguments:[CPArray arrayWithObjects:left, right]]; } else if ([self scanString:@"/" intoString:NULL]) { right = [self parsePowerExpression]; - left = [CPExpression expressionForFunction:@"_div" arguments:[CPArray arrayWithObjects:left, right, nil]]; + left = [CPExpression expressionForFunction:@"_div" arguments:[CPArray arrayWithObjects:left, right]]; } else { @@ -865,12 +865,12 @@ function(newValue)\ if ([self scanString:@"+" intoString:NULL]) { right = [self parseMultiplicationExpression]; - left = [CPExpression expressionForFunction:@"_add" arguments:[CPArray arrayWithObjects:left, right, nil]]; + left = [CPExpression expressionForFunction:@"_add" arguments:[CPArray arrayWithObjects:left, right]]; } else if ([self scanString:@"-" intoString:NULL]) { right = [self parseMultiplicationExpression]; - left = [CPExpression expressionForFunction:@"_sub" arguments:[CPArray arrayWithObjects:left, right, nil]]; + left = [CPExpression expressionForFunction:@"_sub" arguments:[CPArray arrayWithObjects:left, right]]; } else { From 63dfb8a2270ff4bca7dd14b2c1dc9c7e04028169 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 22:38:19 -0400 Subject: [PATCH 163/356] CPPredicate optimization: early out in failing AND expression. --- Foundation/CPPredicate/CPCompoundPredicate.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Foundation/CPPredicate/CPCompoundPredicate.j b/Foundation/CPPredicate/CPCompoundPredicate.j index 7ba504e6a..55cd1ed0b 100644 --- a/Foundation/CPPredicate/CPCompoundPredicate.j +++ b/Foundation/CPPredicate/CPCompoundPredicate.j @@ -189,6 +189,8 @@ var CPCompoundPredicateType; result = [predicate evaluateWithObject:object substitutionVariables:variables]; else result = result && [predicate evaluateWithObject:object substitutionVariables:variables]; + if (!result) + return NO; break; case CPOrPredicateType: if ([predicate evaluateWithObject:object substitutionVariables:variables]) From 1b5efdfc5b3712f5f90f60a23b298bf77ab26c22 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 22:40:59 -0400 Subject: [PATCH 164/356] Fixed with CPPredicate tests: [CPArray arrayWithObjects] don't take a final nil anymore in Cappuccino. --- Tests/Foundation/CPPredicateTest.j | 90 +++++++++++++++--------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index 80a76e197..443dca209 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -12,21 +12,21 @@ { var d, objects; - + dict = [[CPDictionary alloc] init]; [dict setObject: @"A Title" forKey:@"title"]; - - var keys = [CPArray arrayWithObjects:@"Name",@"Age",@"Children",nil]; - objects = [CPArray arrayWithObjects:@"John",[CPNumber numberWithInt:34],[CPArray arrayWithObjects:@"Kid1", @"Kid2", nil],nil]; - - d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; - [dict setObject:d forKey:@"Record1"]; - - objects = [CPArray arrayWithObjects:@"Mary",[CPNumber numberWithInt:30],[CPArray arrayWithObjects:@"Kid1", @"Girl1", nil],nil]; - d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; + var keys = [CPArray arrayWithObjects:@"Name",@"Age",@"Children"]; + objects = [CPArray arrayWithObjects:@"John",[CPNumber numberWithInt:34],[CPArray arrayWithObjects:@"Kid1", @"Kid2"]]; + + d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; + [dict setObject:d forKey:@"Record1"]; + + objects = [CPArray arrayWithObjects:@"Mary",[CPNumber numberWithInt:30],[CPArray arrayWithObjects:@"Kid1", @"Girl1"]]; + + d = [CPDictionary dictionaryWithObjects:objects forKeys:keys]; [dict setObject:d forKey:@"Record2"]; - + } return self; } @@ -35,34 +35,34 @@ { var expression_keypath = [CPExpression expressionForKeyPath:@"name"]; [self assertNotNull:expression_keypath message:"KeyPath Expression should not be nil"]; - + var expression_str = [CPExpression expressionForConstantValue:@"j[a-z]an"]; [self assertNotNull:expression_str message:"ConstantValue Expression should not be nil"]; - + var expression_num = [CPExpression expressionForConstantValue:[CPNumber numberWithInt:1]]; [self assertNotNull:expression_num message:"ConstantValue Expression should not be nil"]; - - var expression_collection = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d",nil]]; + + var expression_collection = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]]; [self assertNotNull:expression_collection message:"ConstantValue Expression should not be nil"]; - + var expression_var = [CPExpression expressionForVariable:@"variable"]; [self assertNotNull:expression_var message:"Variable Expression should not be nil"]; - var expression_function = [CPExpression expressionForFunction:@"sum:" arguments:[CPArray arrayWithObjects:expression_num,expression_num,nil]]; + var expression_function = [CPExpression expressionForFunction:@"sum:" arguments:[CPArray arrayWithObjects:expression_num,expression_num]]; [self assertNotNull:expression_function message:"Function Expression should not be nil"]; var expression_self = [CPExpression expressionForEvaluatedObject]; [self assertNotNull:expression_self message:"Function Expression should not be nil"]; - var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num,expression_function,nil]]; + var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num,expression_function]]; [self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"]; - + var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]]; [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"]; - - var set = [CPSet setWithObjects:@"a",@"b",@"d",nil]; - var array = [CPArray arrayWithObjects:@"a",@"b",@"d",nil]; - + + var set = [CPSet setWithObjects:@"a",@"b",@"d"]; + var array = [CPArray arrayWithObjects:@"a",@"b",@"d"]; + var expression_intersect = [CPExpression expressionForIntersectSet:set with:array]; [self assertNotNull:expression_intersect message:"IntersectSet Expression should not be nil"]; @@ -75,10 +75,10 @@ - (void)testFunctionExpression { - var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[CPArray arrayWithObjects:[CPExpression expressionForConstantValue:1],[CPExpression expressionForConstantValue:2],[CPExpression expressionForConstantValue:3],nil]]; + var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[CPArray arrayWithObjects:[CPExpression expressionForConstantValue:1],[CPExpression expressionForConstantValue:2],[CPExpression expressionForConstantValue:3]]]; var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:3] modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; - + [self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"]; } @@ -88,7 +88,7 @@ var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:variable_exp modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; var variables = [CPDictionary dictionaryWithObject:20 forKey:@"variable"]; - + [self assertTrue:[pred evaluateWithObject:dict substitutionVariables:variables] message:"'"+ [pred description] + "' should be true"]; } @@ -96,17 +96,17 @@ { var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"àa"] rightExpression:[CPExpression expressionForConstantValue:@"aà"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:3]; [self assertTrue:[pred evaluateWithObject:nil] message:"/"+ [pred description] + "/ should be true"]; - + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"aB"] rightExpression:[CPExpression expressionForConstantValue:@"Ab"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:1]; - [self assertTrue:[pred evaluateWithObject:nil] message:"/"+ [pred description] + "/ should be true"]; + [self assertTrue:[pred evaluateWithObject:nil] message:"/"+ [pred description] + "/ should be true"]; } - (void)testModifier { - var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record2.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Gi"] modifier:CPAnyPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record2.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Gi"] modifier:CPAnyPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; - - pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Kid"] modifier:CPAllPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Children"] rightExpression:[CPExpression expressionForConstantValue:@"Kid"] modifier:CPAllPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; } @@ -120,7 +120,7 @@ pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"Aa"] rightExpression:[CPExpression expressionForConstantValue:@"ab"] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:0]; [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; - + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"Ac"] rightExpression:[CPExpression expressionForConstantValue:@"ab"] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:2]; [self assertTrue:[pred evaluateWithObject:nil] message:"'"+ [pred description] + "' should be true"]; @@ -129,11 +129,11 @@ - (void)testCompoundPredicate { var predOne = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Name"] rightExpression:[CPExpression expressionForConstantValue:@"J"] modifier:CPDirectPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; - + var predTwo = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:[CPExpression expressionForConstantValue:[CPNumber numberWithInt:40]] modifier:CPDirectPredicateModifier type:CPLessThanPredicateOperatorType options:0]; - - var pred = [[CPCompoundPredicate alloc] initWithType:CPAndPredicateType subpredicates:[CPArray arrayWithObjects:predOne,predTwo,nil]]; - + + var pred = [[CPCompoundPredicate alloc] initWithType:CPAndPredicateType subpredicates:[CPArray arrayWithObjects:predOne,predTwo]]; + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; } @@ -143,33 +143,33 @@ // TEST String predicate = [CPPredicate predicateWithFormat: @"%K == %@", @"Record1.Name", @"John"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - + predicate = [CPPredicate predicateWithFormat: @"%K MATCHES[c] %@", @"Record1.Name", @"john"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - + predicate = [CPPredicate predicateWithFormat: @"%K BEGINSWITH %@", @"Record1.Name", @"Jo"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - + predicate = [CPPredicate predicateWithFormat: @"(%K == %@) AND (%K == %@)", @"Record1.Name", @"John", @"Record2.Name", @"Mary"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; // TEST integer predicate = [CPPredicate predicateWithFormat: @"%K == %d", @"Record1.Age", 34]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - + predicate = [CPPredicate predicateWithFormat: @"%K < %d", @"Record1.Age", 40]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - - predicate = [CPPredicate predicateWithFormat: @"%K BETWEEN %@", @"Record1.Age", [CPArray arrayWithObjects:[CPNumber numberWithInt: 20], [CPNumber numberWithInt:40], nil]]; + + predicate = [CPPredicate predicateWithFormat: @"%K BETWEEN %@", @"Record1.Age", [CPArray arrayWithObjects:[CPNumber numberWithInt: 20], [CPNumber numberWithInt:40]]]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; predicate = [CPPredicate predicateWithFormat: @"Record1.Age BETWEEN {%f,%f}", 20, 40]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; - + predicate = [CPPredicate predicateWithFormat: @"(%K == %d) OR (%K == %d)", @"Record1.Age", 34, @"Record2.Age", 34]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; -// TEST float +// TEST float predicate = [CPPredicate predicateWithFormat: @"%K < %f", @"Record1.Age", 40.5]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; @@ -181,7 +181,7 @@ [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"]; - [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; } @end \ No newline at end of file From df358ccc4220d0138fc288cde5d5ff8a6c211789 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 4 Aug 2010 21:27:01 -0400 Subject: [PATCH 165/356] Fix failing CPPredicate unit tests: comment out test for unimplemented expressionForSubquery, finish CPExpression_unionset and fix typo in CPExpression expressionForIntersectSet. --- Foundation/CPPredicate/CPExpression.j | 16 +++++----- .../CPPredicate/CPExpression_unionset.j | 32 +++++++++---------- Tests/Foundation/CPPredicateTest.j | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Foundation/CPPredicate/CPExpression.j b/Foundation/CPPredicate/CPExpression.j index 03b31012c..64b43375b 100644 --- a/Foundation/CPPredicate/CPExpression.j +++ b/Foundation/CPPredicate/CPExpression.j @@ -45,7 +45,7 @@ CPIntersectSetExpressionType = 8; */ CPMinusSetExpressionType = 9; -/*! +/*! @ingroup foundation @class CPExpression @brief CPExpression is used to represent expressions in a predicate. @@ -69,7 +69,7 @@ CPMinusSetExpressionType = 9; - (id)initWithExpressionType:(int)type { _type = type; - + return self; } @@ -141,7 +141,7 @@ CPMinusSetExpressionType = 9; @param right An expression that evaluates to a collection object (an instance of CPArray, CPSet, or CPDictionary). @return A new CPExpression object that represents the intersection of left and right. */ -+ (CPExpression)expressionForIntersectSetSet:(CPExpression)left with:(CPExpression)right ++ (CPExpression)expressionForIntersectSet:(CPExpression)left with:(CPExpression)right { return [[CPExpression_intersectset alloc] initWithLeft:left right:right]; } @@ -167,9 +167,9 @@ CPMinusSetExpressionType = 9; If there is a mismatch between the number of parameters expected and the number you provide during evaluation, an exception may be raised or missing parameters may simply be replaced by nil (which occurs depends on how many parameters are provided, and whether you have over- or underflow). @return A new expression that invokes the function name using the parameters in parameters. - + The name parameter can be one of the following predefined functions: - @verbatim + @verbatim name parameter array contents returns ------------------------------------------------------------------------------------------------------------------------------------- sum: CPExpression instances representing numbers CPNumber @@ -196,7 +196,7 @@ CPMinusSetExpressionType = 9; trunc: one CPExpression instance representing a number CPNumber uppercase: one CPExpression instance representing a string CPString lowercase: one CPExpression instance representing a string CPString - random none CPNumber (integer) + random none CPNumber (integer) random: one CPExpression instance representing a number CPNumber (integer) such that 0 <= rand < param now none [CPDate now] bitwiseAnd:with: two CPExpression instances representing numbers CPNumber (numbers will be treated as CPInteger) @@ -211,7 +211,7 @@ CPMinusSetExpressionType = 9; */ + (CPExpression)expressionForFunction:(CPString)function_name arguments:(CPArray)parameters { - return [[CPExpression_function alloc] initWithSelector:CPSelectorFromString(function_name) arguments:parameters]; + return [[CPExpression_function alloc] initWithSelector:CPSelectorFromString(function_name) arguments:parameters]; } /*! @@ -224,7 +224,7 @@ CPMinusSetExpressionType = 9; */ + (CPExpression)expressionForFunction:(CPExpression)target selectorName:(CPString)function_name arguments:(CPArray)parameters { - return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(function_name) arguments:parameters]; + return [[CPExpression_function alloc] initWithTarget:target selector:CPSelectorFromString(function_name) arguments:parameters]; } diff --git a/Foundation/CPPredicate/CPExpression_unionset.j b/Foundation/CPPredicate/CPExpression_unionset.j index cb99edee6..45c9d137e 100644 --- a/Foundation/CPPredicate/CPExpression_unionset.j +++ b/Foundation/CPPredicate/CPExpression_unionset.j @@ -1,22 +1,22 @@ @import "CPExpression.j" -@implementation CPExpression_unionset +@implementation CPExpression_unionset : CPExpression - (id)initWithLeft:(CPExpression)left right:(CPExpression)right { [super initWithExpressionType:CPUnionSetExpressionType]; _left = left; _right = right; - + return self; } - (id)initWithCoder:(CPCoder)coder { - var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"]; - var right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; - + var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"], + right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; + return [self initWithLeft:left right:right]; } @@ -30,33 +30,33 @@ { if (self == object) return YES; - - if (object.isa != self.isa - || [object expressionType] != [self expressionType] - || ![[object leftExpression] isEqual:[self leftExpression]] - || ![[object rightExpression] isEqual:[self rightExpression]]) + + if (object.isa != self.isa + || [object expressionType] != [self expressionType] + || ![[object leftExpression] isEqual:[self leftExpression]] + || ![[object rightExpression] isEqual:[self rightExpression]]) return NO; - + return YES; } - (id)expressionValueWithObject:object context:(CPDictionary )context -{ - var right = [_right expressionValueWithObject:object context:context]; +{ + var right = [_right expressionValueWithObject:object context:context]; if (![right respondsToSelector: @selector(objectEnumerator)]) [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; - var left = [_left expressionValueWithObject:object context:context]; + var left = [_left expressionValueWithObject:object context:context]; if (![left isKindOfClass:[CPSet set]]) [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; var unionset = [CPSet setWithSet:left], e = [right objectEnumerator], item; - + while (item = [e nextObject]) [unionset addObject:item]; - + return [CPExpression expressionForConstantValue:unionset]; } diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index 443dca209..c2caff399 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -58,7 +58,7 @@ [self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"]; var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]]; - [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"]; + // [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"]; var set = [CPSet setWithObjects:@"a",@"b",@"d"]; var array = [CPArray arrayWithObjects:@"a",@"b",@"d"]; From 750cd3c25846e314de316f33adea5917c7f25e4d Mon Sep 17 00:00:00 2001 From: cacaodev Date: Thu, 5 Aug 2010 11:51:58 +0200 Subject: [PATCH 166/356] CPComparisonPredicate : Fixed a bug where *lhs custom_selector: nil* was always returning false. Test nil on left and/or right with some operators. --- .../CPPredicate/CPComparisonPredicate.j | 2 +- Tests/Foundation/CPPredicateTest.j | 40 ++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j index 49336963a..8f5a9726b 100644 --- a/Foundation/CPPredicate/CPComparisonPredicate.j +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -388,7 +388,7 @@ var CPPredicateOperatorType; var leftIsNil = (lhs == nil || [lhs isEqual:[CPNull null]]), rightIsNil = (rhs == nil || [rhs isEqual:[CPNull null]]); - if (leftIsNil || rightIsNil) + if ((leftIsNil || rightIsNil) && _type != CPCustomSelectorPredicateOperatorType) return (leftIsNil == rightIsNil && (_type == CPEqualToPredicateOperatorType || _type == CPLessThanOrEqualToPredicateOperatorType || diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index c2caff399..242ac8efc 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -137,6 +137,35 @@ [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; } +- (void)testNilComparisons +{ +// Custom Selector Predicate + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Name"] rightExpression:[CPExpression expressionForConstantValue:nil] customSelector:@selector(yes:)]; + + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:nil] rightExpression:[CPExpression expressionForConstantValue:nil] customSelector:@selector(yes:)]; + + [self assertFalse:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be false"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Name"] rightExpression:[CPExpression expressionForConstantValue:nil] modifier:CPDirectPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + + [self assertFalse:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be false"]; + +// Predicates with operators + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:[CPExpression expressionForConstantValue:nil] modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; + + [self assertFalse:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be false"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:nil] rightExpression:[CPExpression expressionForConstantValue:nil] modifier:CPDirectPredicateModifier type:CPGreaterThanOrEqualToPredicateOperatorType options:0]; + + [self assertTrue:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be true"]; + + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:nil] rightExpression:[CPExpression expressionForConstantValue:nil] modifier:CPDirectPredicateModifier type:CPBeginsWithPredicateOperatorType options:0]; + + [self assertFalse:[pred evaluateWithObject:dict] message:"'"+ [pred description] + "' should be false"]; +} + - (void)testPredicateParsing { var predicate; @@ -184,4 +213,13 @@ [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; } -@end \ No newline at end of file +@end + +@implementation CPObject (PredicateTesting) + +- (BOOL)yes:(id)object +{ + return YES; +} + +@end From 998c2f19cfcea15a3bf39ef4ccc7d2c600fa31a2 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 22:41:28 -0400 Subject: [PATCH 167/356] Performance tester for CPArrayController. --- Tests/AppKit/CPArrayControllerPerformance.j | 64 +++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Tests/AppKit/CPArrayControllerPerformance.j diff --git a/Tests/AppKit/CPArrayControllerPerformance.j b/Tests/AppKit/CPArrayControllerPerformance.j new file mode 100644 index 000000000..fef9c9c4a --- /dev/null +++ b/Tests/AppKit/CPArrayControllerPerformance.j @@ -0,0 +1,64 @@ +@import +@import +@import + +@implementation CPArrayControllerPerformance : OJTestCase + +- (void)testRearrangeObjects +{ + var ELEMENTS = 200, + REPEATS = 50, + ac = [CPArrayController new], + array = []; + + for (var i=0; i= last) + [self fail:"array values should be descending (position: "+j+")"]; + last = sorted[j]; + } + } + + + var end = (new Date).getTime(); + + CPLog.warn("testRearrangeObjects: "+(end-start)+"ms"); +} + +@end + +@implementation Sortable : CPObject +{ + int a @accessors; + int b @accessors; +} + +@end \ No newline at end of file From 21614e15b22eed7bbc13b5c9ba0bd3eef6fcf45a Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 9 Aug 2010 14:05:58 -0500 Subject: [PATCH 168/356] Draw column header lines by default. --- AppKit/CPTableHeaderView.j | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index be8d64798..202de9d73 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -187,6 +187,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal _isResizing = NO; _isDragging = NO; _isTrackingColumn = NO; + _drawsColumnLines = YES; _columnOldWidth = 0.0; @@ -656,7 +657,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal @end -var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey"; +var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey", + CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines"; @implementation CPTableHeaderView (CPCoding) @@ -666,6 +668,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey"; { [self _init]; _tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey]; + _drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines]; } return self; @@ -675,6 +678,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey"; { [super encodeWithCoder:aCoder]; [aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey]; + [aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines]; } @end \ No newline at end of file From b346d761d8459feec242765a63a1bc53d4f2a4ad Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 9 Aug 2010 14:13:04 -0500 Subject: [PATCH 169/356] Fix bug so we can drag items below the last child index in the outlineView. --- AppKit/CPOutlineView.j | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index f3bb21bac..414249a0b 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -624,7 +624,7 @@ CPOutlineViewDropOnItemIndex = -1; if (_dropItem) { [_dropOperationFeedbackView blink]; - [CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO]; //[self expandItem:_dropItem]; + [CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO]; } } @@ -645,10 +645,18 @@ CPOutlineViewDropOnItemIndex = -1; _shouldRetargetChildIndex = YES; // set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex - var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo, - retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem; + var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo; - _retargetedDropRow = [self rowForItem:retargetedChildItem]; + if (_retargedChildIndex === [retargetedItemInfo.children count]) + { + var retargetedChildItem = [retargetedItemInfo.children lastObject]; + _retargetedDropRow = [self rowForItem:retargetedChildItem] + 1; + } + else + { + var retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem; + _retargetedDropRow = [self rowForItem:retargetedChildItem]; + } } - (void)_draggingEnded From 271bb00147d6cd6a03b839420583144bb2930c80 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 9 Aug 2010 16:14:12 -0400 Subject: [PATCH 170/356] Marginally faster filter and sort in CPArrayController's arrangeObjects (4% in the performance tester.) Reduced memory usage when both a filter and a sort order are applied. Cleanup of the tester and a filter only test run. --- AppKit/CPArrayController.j | 19 ++++++--- Foundation/CPPredicate/CPPredicate.j | 11 ++--- Tests/AppKit/CPArrayControllerPerformance.j | 46 +++++++++++++++------ 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 4953c3016..3e3dd1778 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -197,14 +197,21 @@ - (CPArray)arrangeObjects:(CPArray)objects { - var sortedObjects = objects; + var filterPredicate = [self filterPredicate], + sortDescriptors = [self sortDescriptors]; - if ([self filterPredicate]) - sortedObjects = [sortedObjects filteredArrayUsingPredicate:[self filterPredicate]]; - if ([self sortDescriptors]) - sortedObjects = [sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]]; + if (filterPredicate && sortDescriptors) + { + var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate]; + [sortedObjects sortUsingDescriptors:sortDescriptors]; + return sortedObjects; + } + else if (filterPredicate) + return [objects filteredArrayUsingPredicate:filterPredicate]; + else if (sortDescriptors) + return [objects sortedArrayUsingDescriptors:sortDescriptors]; - return sortedObjects; + return [objects copy]; } - (void)rearrangeObjects diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index bd992b978..18a0c5b51 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -168,10 +168,9 @@ for (i = 0; i < count; i++) { - var object = [self objectAtIndex:i]; - + var object = self[i]; if ([predicate evaluateWithObject:object]) - [result addObject:object]; + result.push(object); } return result; @@ -183,10 +182,8 @@ while (count--) { - var object = [self objectAtIndex:count]; - - if (![predicate evaluateWithObject:object]) - [self removeObjectAtIndex:count]; + if (![predicate evaluateWithObject:self[count]]) + splice(count, 1); } } diff --git a/Tests/AppKit/CPArrayControllerPerformance.j b/Tests/AppKit/CPArrayControllerPerformance.j index fef9c9c4a..083f9b343 100644 --- a/Tests/AppKit/CPArrayControllerPerformance.j +++ b/Tests/AppKit/CPArrayControllerPerformance.j @@ -7,11 +7,12 @@ - (void)testRearrangeObjects { var ELEMENTS = 200, - REPEATS = 50, + REPEATS = 25, ac = [CPArrayController new], array = []; - for (var i=0; i Date: Mon, 9 Aug 2010 12:19:30 -0400 Subject: [PATCH 171/356] Fix for issue #818 (NSView does not read hidden flag) --- Tools/nib2cib/NSView.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/nib2cib/NSView.j b/Tools/nib2cib/NSView.j index 8e0c8c219..0a1b5afe7 100644 --- a/Tools/nib2cib/NSView.j +++ b/Tools/nib2cib/NSView.j @@ -43,7 +43,7 @@ { _tag = -1; - if([aCoder containsValueForKey:@"NSTag"]) + if ([aCoder containsValueForKey:@"NSTag"]) _tag = [aCoder decodeIntForKey:@"NSTag"]; _bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); @@ -61,7 +61,7 @@ _autoresizesSubviews = vFlags & (1 << 8); _hitTests = YES; - _isHidden = NO;//[aCoder decodeObjectForKey:CPViewIsHiddenKey]; + _isHidden = vFlags & 0x80000000; _opacity = 1.0;//[aCoder decodeIntForKey:CPViewOpacityKey]; _themeAttributes = {}; From 627c300b4a8d7fc41013039519413049477262dd Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 9 Aug 2010 14:19:37 -0400 Subject: [PATCH 172/356] Switched to using bit mask constants --- Tools/nib2cib/NSView.j | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Tools/nib2cib/NSView.j b/Tools/nib2cib/NSView.j index 0a1b5afe7..b42ebf8b0 100644 --- a/Tools/nib2cib/NSView.j +++ b/Tools/nib2cib/NSView.j @@ -26,6 +26,10 @@ @import +var NSViewAutoresizingMask = 0x3F, + NSViewAutoresizesSubviewsMask = 1 << 8, + NSViewHiddenMask = 1 << 31; + @implementation CPView (NSCoding) - (id)NS_initWithCoder:(CPCoder)aCoder @@ -57,11 +61,11 @@ var vFlags = [aCoder decodeIntForKey:@"NSvFlags"]; - _autoresizingMask = vFlags & 0x3F; - _autoresizesSubviews = vFlags & (1 << 8); + _autoresizingMask = vFlags & NSViewAutoresizingMask; + _autoresizesSubviews = vFlags & NSViewAutoresizesSubviewsMask; _hitTests = YES; - _isHidden = vFlags & 0x80000000; + _isHidden = vFlags & NSViewHiddenMask; _opacity = 1.0;//[aCoder decodeIntForKey:CPViewOpacityKey]; _themeAttributes = {}; From 8d635c7a5a4a68ea4c2c97549104339883b4089a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 29 Jul 2010 21:40:40 -0400 Subject: [PATCH 173/356] Moved ArrayController1 test into the Manual folder. --- Tests/{AppKit => Manual}/ArrayController1/AppController.j | 0 Tests/{AppKit => Manual}/ArrayController1/Info.plist | 0 Tests/{AppKit => Manual}/ArrayController1/Resources/MainMenu.cib | 0 Tests/{AppKit => Manual}/ArrayController1/index-debug.html | 0 Tests/{AppKit => Manual}/ArrayController1/index.html | 0 Tests/{AppKit => Manual}/ArrayController1/main.j | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename Tests/{AppKit => Manual}/ArrayController1/AppController.j (100%) rename Tests/{AppKit => Manual}/ArrayController1/Info.plist (100%) rename Tests/{AppKit => Manual}/ArrayController1/Resources/MainMenu.cib (100%) rename Tests/{AppKit => Manual}/ArrayController1/index-debug.html (100%) rename Tests/{AppKit => Manual}/ArrayController1/index.html (100%) rename Tests/{AppKit => Manual}/ArrayController1/main.j (100%) diff --git a/Tests/AppKit/ArrayController1/AppController.j b/Tests/Manual/ArrayController1/AppController.j similarity index 100% rename from Tests/AppKit/ArrayController1/AppController.j rename to Tests/Manual/ArrayController1/AppController.j diff --git a/Tests/AppKit/ArrayController1/Info.plist b/Tests/Manual/ArrayController1/Info.plist similarity index 100% rename from Tests/AppKit/ArrayController1/Info.plist rename to Tests/Manual/ArrayController1/Info.plist diff --git a/Tests/AppKit/ArrayController1/Resources/MainMenu.cib b/Tests/Manual/ArrayController1/Resources/MainMenu.cib similarity index 100% rename from Tests/AppKit/ArrayController1/Resources/MainMenu.cib rename to Tests/Manual/ArrayController1/Resources/MainMenu.cib diff --git a/Tests/AppKit/ArrayController1/index-debug.html b/Tests/Manual/ArrayController1/index-debug.html similarity index 100% rename from Tests/AppKit/ArrayController1/index-debug.html rename to Tests/Manual/ArrayController1/index-debug.html diff --git a/Tests/AppKit/ArrayController1/index.html b/Tests/Manual/ArrayController1/index.html similarity index 100% rename from Tests/AppKit/ArrayController1/index.html rename to Tests/Manual/ArrayController1/index.html diff --git a/Tests/AppKit/ArrayController1/main.j b/Tests/Manual/ArrayController1/main.j similarity index 100% rename from Tests/AppKit/ArrayController1/main.j rename to Tests/Manual/ArrayController1/main.j From 96958d26c700b7fc75fc5b3f6477d24c87e02028 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 9 Aug 2010 17:22:14 -0500 Subject: [PATCH 174/356] Accidental globals. --- AppKit/CPTableView.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index f41462277..31693cc35 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2021,9 +2021,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex], bounds = CPRectMake(0.0, 0.0, [tableColumn width], CPRectGetHeight([self _exposedRect]) + 23.0), columnRect = [self rectOfColumn:theColumnIndex], - headerView = [tableColumn headerView]; + headerView = [tableColumn headerView], + row = [_exposedRows firstIndex]; - row = [_exposedRows firstIndex]; while (row !== CPNotFound) { var dataView = [self _newDataViewForRow:row tableColumn:tableColumn], @@ -2046,7 +2046,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var headerFrame = [headerView frame]; headerFrame.origin = CPPointMakeZero(); - columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame]; + var columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame]; [columnHeaderView setStringValue:[headerView stringValue]]; [columnHeaderView setThemeState:[headerView themeState]]; [dragView addSubview:columnHeaderView]; From 13b2a886f347e50bfc8dfdb011a1f379bd3c1d60 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 9 Aug 2010 17:36:33 -0500 Subject: [PATCH 175/356] Changed CPRect and CPPoint functions to _CG --- AppKit/CPTableHeaderView.j | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 202de9d73..a80b0e79b 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -151,8 +151,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal @implementation CPTableHeaderView : CPView { - CPPoint _mouseDownLocation; - CPPoint _previousTrackingLocation; + CGPoint _mouseDownLocation; + CGPoint _previousTrackingLocation; int _activeColumn; int _pressedColumn; @@ -179,8 +179,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal - (void)_init { - _mouseDownLocation = CPPointMakeZero(); - _previousTrackingLocation = CPPointMakeZero(); + _mouseDownLocation = _CGPointMakeZero(); + _previousTrackingLocation = _CGPointMakeZero(); _activeColumn = -1; _pressedColumn = -1; @@ -214,8 +214,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var headerRect = [self bounds], columnRect = [_tableView rectOfColumn:aColumnIndex]; - headerRect.origin.x = CPRectGetMinX(columnRect); - headerRect.size.width = CPRectGetWidth(columnRect); + headerRect.origin.x = _CGRectGetMinX(columnRect); + headerRect.size.width = _CGRectGetWidth(columnRect); return headerRect; } @@ -274,7 +274,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal currentLocation.x -= 5.0; var columnIndex = [self columnAtPoint:currentLocation], - shouldResize = [self shouldResizeTableColumn:columnIndex at:CPPointMake(currentLocation.x + 5.0, currentLocation.y)]; + shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)]; if (type === CPLeftMouseUp) { @@ -318,7 +318,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [self continueResizingTableColumn:_activeColumn at:currentLocation]; else { - if (_activeColumn === columnIndex && CPRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation)) + if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation)) { if (_isTrackingColumn && _pressedColumn !== -1) { @@ -336,24 +336,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; } -- (void)startTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { [self _setPressedColumn:aColumnIndex]; } -- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { if ([self _shouldDragTableColumn:aColumnIndex at:aPoint]) { var columnRect = [self headerRectOfColumn:aColumnIndex], - offset = CPPointMakeZero(), + offset = _CGPointMakeZero(), view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset], - viewLocation = CPPointMakeZero(); + viewLocation = _CGPointMakeZero(); - viewLocation.x = ( CPRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x ); - viewLocation.y = CPRectGetMinY(columnRect) + offset.y; + viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x ); + viewLocation.y = _CGRectGetMinY(columnRect) + offset.y; - [self dragView:view at:viewLocation offset:CPSizeMakeZero() event:[CPApp currentEvent] + [self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent] pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES]; return NO; @@ -362,24 +362,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal return YES; } -- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { return _isTrackingColumn && _activeColumn === aColumnIndex && - CPRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint); + _CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint); } -- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { [self _setPressedColumn:CPNotFound]; [self _updateResizeCursor:[CPApp currentEvent]]; } -- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0; } -- (CPRect)_headerRectOfLastVisibleColumn +- (CGRect)_headerRectOfLastVisibleColumn { var tableColumns = [_tableView tableColumns], columnIndex = [tableColumns count]; @@ -395,7 +395,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal return nil; } -- (void)_constrainDragView:(CPView)theDragView at:(CPPoint)aPoint +- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint { var tableColumns = [_tableView tableColumns], lastColumnRect = [self _headerRectOfLastVisibleColumn]; @@ -412,7 +412,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect))); // Make sure the column cannot move vertically - frame.origin.y = CPRectGetMinY(lastColumnRect); + frame.origin.y = _CGRectGetMinY(lastColumnRect); // Convert the calculated origin back to the window coordinate system frame.origin = [self convertPoint:frame.origin toView:nil]; @@ -431,7 +431,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [_tableView _setDraggedColumn:_activeColumn]; } -- (void)draggedView:(CPView)aView beganAt:(CPPoint)aPoint +- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint { _isDragging = YES; @@ -441,7 +441,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [self setNeedsDisplay:YES]; } -- (void)draggedView:(CPView)aView movedTo:(CPPoint)aPoint +- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint { [self _constrainDragView:aView at:aPoint]; @@ -487,7 +487,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [self setNeedsDisplay:YES]; } -- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { if (_isResizing) return YES; @@ -495,10 +495,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal if (_isTrackingColumn) return NO; - return [_tableView allowsColumnResizing] && CPRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint); + return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint); } -- (void)startResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { _isResizing = YES; @@ -508,7 +508,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [_tableView setDisableAutomaticResizing:YES]; } -- (void)continueResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex], newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x; @@ -528,7 +528,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal } } -- (void)stopResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint +- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint { var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex]; [tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth]; From 33e4a082d63b1d3237dcb013c69e206c4bb137e8 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 9 Aug 2010 18:43:11 -0500 Subject: [PATCH 176/356] Some visual changes to column dragging to make it a bit more like cocoa. --- AppKit/CPTableHeaderView.j | 26 +++++++++++++------------- AppKit/CPTableView.j | 34 ++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index a80b0e79b..0fc8806e1 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -71,7 +71,7 @@ var inset = [self currentValueForThemeAttribute:@"text-inset"], bounds = [self bounds]; - [_textField setFrame:CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)]; + [_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)]; [_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; [_textField setFont:[self currentValueForThemeAttribute:@"text-font"]]; [_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]]; @@ -233,11 +233,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal - (CGRect)_cursorRectForColumn:(int)column { if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask)) - return CGRectMakeZero(); + return _CGRectMakeZero(); var rect = [self headerRectOfColumn:column]; - rect.origin.x = CGRectGetMaxX(rect) - 5; + rect.origin.x = _CGRectGetMaxX(rect) - 5; rect.size.width = 20; return rect; @@ -409,7 +409,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal frame.origin = [self convertPoint:frame.origin fromView:nil]; // This effectively clamps the value between the minimum and maximum - frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect))); + frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect))); // Make sure the column cannot move vertically frame.origin.y = _CGRectGetMinY(lastColumnRect); @@ -451,9 +451,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var hoverPoint = CGPointCreateCopy(aPoint); if (aPoint.x < _previousTrackingLocation.x) - hoverPoint = CGPointMake(CGRectGetMinX(dragWindowFrame), CGRectGetMinY(dragWindowFrame)); + hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame)); else if (aPoint.x > _previousTrackingLocation.x) - hoverPoint = CGPointMake(CGRectGetMaxX(dragWindowFrame), CGRectGetMinY(dragWindowFrame)); + hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame)); // Convert the hover point from the global coordinate system to windows' coordinate system hoverPoint = [[self window] convertGlobalToBase:hoverPoint]; @@ -465,7 +465,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal if (hoveredColumn !== -1) { var columnRect = [self headerRectOfColumn:hoveredColumn], - columnCenterPoint = [self convertPoint:CGPointMake(CGRectGetMidX(columnRect), CGRectGetMidY(columnRect)) fromView:self]; + columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self]; if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x) [self _moveColumn:_activeColumn toColumn:hoveredColumn]; else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x) @@ -551,7 +551,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y), overColumn = [self columnAtPoint:mouseOverLocation]; - if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation)) + if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation)) { var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn], width = [tableColumn width]; @@ -639,20 +639,20 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal var columnIndex = columnsArray[columnArrayIndex], columnToStroke = [self headerRectOfColumn:columnIndex]; - columnMaxX = CGRectGetMaxX(columnToStroke); + columnMaxX = _CGRectGetMaxX(columnToStroke); - CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke))); - CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke))); + CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke))); + CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke))); } CGContextClosePath(context); CGContextStrokePath(context); - if (_isDragging) + /*if (_isDragging) { CGContextSetFillColor(context, [CPColor grayColor]); CGContextFillRect(context, [self headerRectOfColumn:_activeColumn]) - } + }*/ } @end diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 31693cc35..6a0388374 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2017,7 +2017,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset { - var dragView = [[CPView alloc] initWithFrame:CPRectMakeZero()]; + var dragView = [[_CPColumnDragView alloc] initWithFrame:CPRectMakeZero()]; tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex], bounds = CPRectMake(0.0, 0.0, [tableColumn width], CPRectGetHeight([self _exposedRect]) + 23.0), columnRect = [self rectOfColumn:theColumnIndex], @@ -2482,15 +2482,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self drawBackgroundInClipRect:exposedRect]; [self drawGridInClipRect:exposedRect]; [self highlightSelectionInClipRect:exposedRect]; - - if (_draggedColumnIndex === -1) - return; - - var context = [[CPGraphicsContext currentContext] graphicsPort], - columnRect = [self rectOfColumn:_draggedColumnIndex]; - - CGContextSetFillColor(context, [CPColor grayColor]); - CGContextFillRect(context, columnRect); } - (void)drawBackgroundInClipRect:(CGRect)aRect @@ -3709,3 +3700,26 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [CPTimer scheduledTimerWithTimeInterval:0.27 callback:showCallback repeats:NO]; } @end + +@implementation _CPColumnDragView : CPView +- (void)drawRect:(CGRect)aRect +{ + var context = [[CPGraphicsContext currentContext] graphicsPort]; + + CGContextSetStrokeColor(context, [CPColor grayColor]); + + var points = [ + _CGPointMake(0.5, 0), + _CGPointMake(0.5, aRect.size.height) + ]; + + CGContextStrokeLineSegments(context, points, 2); + + points = [ + _CGPointMake(aRect.size.width - 0.5, 0), + _CGPointMake(aRect.size.width - 0.5, aRect.size.height) + ]; + + CGContextStrokeLineSegments(context, points, 2); +} +@end From b7d1dfa75f4d021775db067e97b7be7af6b53db4 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Tue, 10 Aug 2010 11:09:19 +0200 Subject: [PATCH 177/356] CPArray sorting: improve performance by 40% (JSC) replacing native js sort() with the merge-sort algorithm. Test with ojunit CPArrayPerformance.j --- Foundation/CPArray.j | 65 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 54081fdf0..cb19f0edb 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -1316,19 +1316,7 @@ CPEnumerationReverse = 1 << 1; - (CPArray)sortUsingDescriptors:(CPArray)descriptors { - var count = [descriptors count]; - - sort(function(lhs, rhs) - { - var i = 0, - result = CPOrderedSame; - - while (i < count) - if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) - return result; - - return result; - }); + [self sortUsingFunction:compareObjectsUsingDescriptors context:descriptors]; } /*! @@ -1338,7 +1326,36 @@ CPEnumerationReverse = 1 << 1; */ - (void)sortUsingFunction:(Function)aFunction context:(id)aContext { - sort(function(lhs, rhs) { return aFunction(lhs, rhs, aContext); }); + var h, i, j, k, l, m, n = [self count]; + var A, B = []; + + for (h = 1; h < n; h += h) + { + for (m = n - 1 - h; m >= 0; m -= h + h) + { + l = m - h + 1; + if (l < 0) + l = 0; + + for (i = 0, j = l; j <= m; i++, j++) + B[i] = self[j]; + + for (i = 0, k = l; k < j && j <= m + h; k++) + { + A = self[j]; + if (aFunction(A, B[i], aContext) == CPOrderedDescending) + self[k] = B[i++]; + else + { + self[k] = A; + j++; + } + } + + while (k < j) + self[k++] = B[i++]; + } + } } /*! @@ -1347,11 +1364,29 @@ CPEnumerationReverse = 1 << 1; */ - (void)sortUsingSelector:(SEL)aSelector { - sort(function(lhs, rhs) { return objj_msgSend(lhs, aSelector, rhs); }); + [self sortUsingFunction:selectorCompare context:aSelector]; } @end +var selectorCompare = function selectorCompare(object1, object2, selector) +{ + return [object1 performSelector:selector withObject:object2]; +} + +// sort using sort descriptors +var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors) +{ + var result, + i = 0, + n = [descriptors count]; + + while (i < n && result == CPOrderedSame); + result = [descriptors[i++] compareObject:lhs withObject:rhs]; + + return result; +} + @implementation CPArray (CPCoding) - (id)initWithCoder:(CPCoder)aCoder From 20ec557655f3e0a1ae93eb3ca1b912ad9ff22969 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Tue, 10 Aug 2010 20:53:08 -0500 Subject: [PATCH 178/356] Initial reorganization of CPTableView testing. --- .../TableTest/{ => OldTest}/AppController.j | 0 .../Manual/TableTest/{ => OldTest}/Info.plist | 0 .../{ => OldTest}/Resources/spinner.gif | Bin .../TableTest/{ => OldTest}/index-debug.html | 0 .../Manual/TableTest/{ => OldTest}/index.html | 0 Tests/Manual/TableTest/{ => OldTest}/main.j | 0 .../TableTest/TestTemplate_AppController.j | 79 ++++++++++++++++++ 7 files changed, 79 insertions(+) rename Tests/Manual/TableTest/{ => OldTest}/AppController.j (100%) rename Tests/Manual/TableTest/{ => OldTest}/Info.plist (100%) rename Tests/Manual/TableTest/{ => OldTest}/Resources/spinner.gif (100%) rename Tests/Manual/TableTest/{ => OldTest}/index-debug.html (100%) rename Tests/Manual/TableTest/{ => OldTest}/index.html (100%) rename Tests/Manual/TableTest/{ => OldTest}/main.j (100%) create mode 100644 Tests/Manual/TableTest/TestTemplate_AppController.j diff --git a/Tests/Manual/TableTest/AppController.j b/Tests/Manual/TableTest/OldTest/AppController.j similarity index 100% rename from Tests/Manual/TableTest/AppController.j rename to Tests/Manual/TableTest/OldTest/AppController.j diff --git a/Tests/Manual/TableTest/Info.plist b/Tests/Manual/TableTest/OldTest/Info.plist similarity index 100% rename from Tests/Manual/TableTest/Info.plist rename to Tests/Manual/TableTest/OldTest/Info.plist diff --git a/Tests/Manual/TableTest/Resources/spinner.gif b/Tests/Manual/TableTest/OldTest/Resources/spinner.gif similarity index 100% rename from Tests/Manual/TableTest/Resources/spinner.gif rename to Tests/Manual/TableTest/OldTest/Resources/spinner.gif diff --git a/Tests/Manual/TableTest/index-debug.html b/Tests/Manual/TableTest/OldTest/index-debug.html similarity index 100% rename from Tests/Manual/TableTest/index-debug.html rename to Tests/Manual/TableTest/OldTest/index-debug.html diff --git a/Tests/Manual/TableTest/index.html b/Tests/Manual/TableTest/OldTest/index.html similarity index 100% rename from Tests/Manual/TableTest/index.html rename to Tests/Manual/TableTest/OldTest/index.html diff --git a/Tests/Manual/TableTest/main.j b/Tests/Manual/TableTest/OldTest/main.j similarity index 100% rename from Tests/Manual/TableTest/main.j rename to Tests/Manual/TableTest/OldTest/main.j diff --git a/Tests/Manual/TableTest/TestTemplate_AppController.j b/Tests/Manual/TableTest/TestTemplate_AppController.j new file mode 100644 index 000000000..65f12eee2 --- /dev/null +++ b/Tests/Manual/TableTest/TestTemplate_AppController.j @@ -0,0 +1,79 @@ +/* + * AppController.j + * TestTemplate + * + * Created by You on August 10, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ + CPTableView table; + CPTableColumn columnA; + CPTableColumn columnB; + CPTableColumn columnC; + CPTableColumn columnD; + +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var scroll = [[CPScrollView alloc] initWithFrame:CGRectMake(100,100,700,400)]; + + table = [[CPTableView alloc] initWithFrame:CGRectMakeZero()]; + [table setDataSource:self]; + [table setAllowsColumnReordering:NO]; + [table setAllowsColumnSelection:YES]; + [table setUsesAlternatingRowBackgroundColors:YES]; + + + columnA = [[CPTableColumn alloc] initWithIdentifier:"A"]; + [table addTableColumn:columnA]; + [[columnA headerView] setStringValue:"A"]; + [columnA setWidth:175]; + + columnB = [[CPTableColumn alloc] initWithIdentifier:"B"]; + [table addTableColumn:columnB]; + [[columnB headerView] setStringValue:"B"]; + [columnB setWidth:175] + + columnC = [[CPTableColumn alloc] initWithIdentifier:"C"]; + [table addTableColumn:columnC]; + [[columnC headerView] setStringValue:"C"]; + [columnC setWidth:175]; + + columnD = [[CPTableColumn alloc] initWithIdentifier:"D"]; + [table addTableColumn:columnD]; + [[columnD headerView] setStringValue:"D"]; + [columnD setWidth:175]; + + columnE = [[CPTableColumn alloc] initWithIdentifier:"E"]; + [table addTableColumn:columnE]; + [[columnE headerView] setStringValue:"E"]; + [columnE setWidth:175]; + + [scroll setDocumentView:table]; + + [contentView addSubview:scroll]; + + [theWindow orderFront:self]; + +} + +- (int)numberOfRowsInTableView:(id)tableView +{ + return 10000; +} + +- (id)tableView:(id)tableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow +{ + return "Column " + [aColumn identifier] + " Row " + aRow; +} + +@end From 583753367882494b5e55c2b9ddfb08f9b5e4db96 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Tue, 10 Aug 2010 20:58:04 -0500 Subject: [PATCH 179/356] Use a default TableView. --- Tests/Manual/TableTest/TestTemplate_AppController.j | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Tests/Manual/TableTest/TestTemplate_AppController.j b/Tests/Manual/TableTest/TestTemplate_AppController.j index 65f12eee2..6f3b1440a 100644 --- a/Tests/Manual/TableTest/TestTemplate_AppController.j +++ b/Tests/Manual/TableTest/TestTemplate_AppController.j @@ -28,10 +28,6 @@ table = [[CPTableView alloc] initWithFrame:CGRectMakeZero()]; [table setDataSource:self]; - [table setAllowsColumnReordering:NO]; - [table setAllowsColumnSelection:YES]; - [table setUsesAlternatingRowBackgroundColors:YES]; - columnA = [[CPTableColumn alloc] initWithIdentifier:"A"]; [table addTableColumn:columnA]; From 088a5c7166e5c0c3a919996e30e63aa2f126fe82 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 11 Aug 2010 10:34:33 -0400 Subject: [PATCH 180/356] Remove extra call to _init in -initWithCoder: --- AppKit/CPSearchField.j | 2 -- 1 file changed, 2 deletions(-) diff --git a/AppKit/CPSearchField.j b/AppKit/CPSearchField.j index 66260ecf7..1035110b9 100644 --- a/AppKit/CPSearchField.j +++ b/AppKit/CPSearchField.j @@ -798,8 +798,6 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey", { if (self = [super initWithCoder:coder]) { - [self _init]; - _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey]; _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey]; From 1e490f17966dfaa60344c1b496d1068c27328d9d Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 15:59:04 -0500 Subject: [PATCH 181/356] Fix for column reordering with hidden columns. Closes #637 --- AppKit/CPTableHeaderView.j | 10 +++++----- AppKit/CPTableView.j | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 0fc8806e1..c8a316a7a 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -427,16 +427,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal [_tableView moveColumn:aFromIndex toColumn:aToIndex]; _activeColumn = aToIndex; _pressedColumn = _activeColumn; - - [_tableView _setDraggedColumn:_activeColumn]; } - (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint { _isDragging = YES; - [[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:YES]; - [_tableView _setDraggedColumn:_activeColumn]; + var column = [[_tableView tableColumns] objectAtIndex:_activeColumn]; + + [[column headerView] setHidden:YES]; + [_tableView _setDraggedColumn:column]; [self setNeedsDisplay:YES]; } @@ -480,7 +480,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal _isDragging = NO; _isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached - [_tableView _setDraggedColumn:-1]; + [_tableView _setDraggedColumn:nil]; [[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO]; [self stopTrackingTableColumn:_activeColumn at:aLocation]; diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 6a0388374..56e314374 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -214,7 +214,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing); BOOL _lastColumnShouldSnap; - int _draggedColumnIndex; + CPTableColumn _draggedColumn; CPArray _differedColumnDataToRemove; } @@ -329,7 +329,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (!_cornerView) _cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))]; - _draggedColumnIndex = -1; + _draggedColumn = nil; /* //gradients for the source list when CPTableView is NOT first responder or the window is NOT key // FIX ME: we need to actually implement this. @@ -750,14 +750,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self setNeedsLayout]; } -- (void)_setDraggedColumn:(int)aColumnIndex +- (void)_setDraggedColumn:(CPTableColumn)aColumn { - if (_draggedColumnIndex === aColumnIndex) + if (_draggedColumn === aColumn) return; - _draggedColumnIndex = aColumnIndex; + _draggedColumn = aColumn; - [self reloadDataForRowIndexes:_exposedRows columnIndexes:[CPIndexSet indexSetWithIndex:aColumnIndex]]; + [self reloadDataForRowIndexes:_exposedRows columnIndexes:[CPIndexSet indexSetWithIndex:[_tableColumns indexOfObject:aColumn]]]; } /*! @@ -2219,6 +2219,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self _unloadDataViewsInRows:previouslyExposedRows columns:obscuredColumns]; [self _unloadDataViewsInRows:obscuredRows columns:previouslyExposedColumns]; [self _unloadDataViewsInRows:obscuredRows columns:obscuredColumns]; + [self _unloadDataViewsInRows:newlyExposedRows columns:newlyExposedColumns]; [self _loadDataViewsInRows:previouslyExposedRows columns:newlyExposedColumns]; [self _loadDataViewsInRows:newlyExposedRows columns:previouslyExposedColumns]; @@ -2284,9 +2285,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; for (; rowIndex < rowsCount; ++rowIndex) { var row = rowArray[rowIndex], - dataView = _dataViewsForTableColumns[tableColumnUID][row]; + dataView = [_dataViewsForTableColumns[tableColumnUID] objectAtIndex:row]; - _dataViewsForTableColumns[tableColumnUID][row] = nil; + [_dataViewsForTableColumns[tableColumnUID] replaceObjectAtIndex:row withObject:nil]; [self _enqueueReusableDataView:dataView]; } @@ -2315,7 +2316,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var column = columnArray[columnIndex], tableColumn = _tableColumns[column]; - if ([tableColumn isHidden] || columnIndex === _draggedColumnIndex) + if ([tableColumn isHidden] || tableColumn === _draggedColumn) continue; var tableColumnUID = [tableColumn UID]; From c8f6e1258611b51c211c1f853139b924d8058521 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Wed, 11 Aug 2010 16:32:01 -0500 Subject: [PATCH 182/356] CPTableView: Implement -drawRow:clipRect: . The method is called only when a tableview subclass implements it for performance reasons. DrawRowTest demonstrating the feature. Conflicts: AppKit/CPTableView.j --- AppKit/CPTableView.j | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 56e314374..7f5f20c0c 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -337,6 +337,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _sourceListInactiveTopLineColor = [CPColor colorWithCalibratedRed:(173.0/255.0) green:(187.0/255.0) blue:(209.0/255.0) alpha:1.0]; _sourceListInactiveBottomLineColor = [CPColor colorWithCalibratedRed:(150.0/255.0) green:(161.0/255.0) blue:(183.0/255.0) alpha:1.0];*/ _differedColumnDataToRemove = [ ]; + _implementsCustomDrawRow = [self implementsSelector:@selector(drawRow:clipRect:)]; } /*! @@ -2751,6 +2752,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; CGContextStrokePath(context); } +- (void)_drawRows:(CPIndexSet)rowsIndexes clipRect:(CGRect)clipRect +{ + var row = [rowsIndexes firstIndex]; + + while (row !== CPNotFound) + { + [self drawRow:row clipRect:CGRectIntersection(clipRect, [self rectOfRow:row])]; + row = [rowsIndexes indexGreaterThanIndex:row]; + } +} + +- (void)drawRow:(CPInteger)row clipRect:(CGRect)rect +{ + // This method does currently nothing in cappuccino. Can be overriden by subclasses. +} + - (void)layoutSubviews { [self load]; From 15356b617b531e30edd88530150544d7fd4721e5 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Wed, 11 Aug 2010 14:55:14 +0200 Subject: [PATCH 183/356] DrawRowTest that was announced in the previous commit --- .../TableTest/DrawRowTest/AppController.j | 108 ++++++++++++++++++ Tests/Manual/TableTest/DrawRowTest/Info.plist | 12 ++ Tests/Manual/TableTest/DrawRowTest/Jakefile | 93 +++++++++++++++ .../DrawRowTest/Resources/spinner.gif | Bin 0 -> 1849 bytes .../TableTest/DrawRowTest/index-debug.html | 104 +++++++++++++++++ Tests/Manual/TableTest/DrawRowTest/index.html | 79 +++++++++++++ Tests/Manual/TableTest/DrawRowTest/main.j | 18 +++ 7 files changed, 414 insertions(+) create mode 100644 Tests/Manual/TableTest/DrawRowTest/AppController.j create mode 100644 Tests/Manual/TableTest/DrawRowTest/Info.plist create mode 100644 Tests/Manual/TableTest/DrawRowTest/Jakefile create mode 100644 Tests/Manual/TableTest/DrawRowTest/Resources/spinner.gif create mode 100644 Tests/Manual/TableTest/DrawRowTest/index-debug.html create mode 100644 Tests/Manual/TableTest/DrawRowTest/index.html create mode 100644 Tests/Manual/TableTest/DrawRowTest/main.j diff --git a/Tests/Manual/TableTest/DrawRowTest/AppController.j b/Tests/Manual/TableTest/DrawRowTest/AppController.j new file mode 100644 index 000000000..dc020ba72 --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/AppController.j @@ -0,0 +1,108 @@ +/* + * AppController.j + * TestTemplate + * + * Created by You on August 10, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import + + +@implementation AppController : CPObject +{ + CPTableView table; + CPTableColumn columnA; + CPTableColumn columnB; + CPTableColumn columnC; + CPTableColumn columnD; + +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask], + contentView = [theWindow contentView]; + + var scroll = [[CPScrollView alloc] initWithFrame:CGRectMake(100,100,700,400)]; + + table = [[TableViewDrawRow alloc] initWithFrame:CGRectMakeZero()]; + [table setDataSource:self]; + + columnA = [[CPTableColumn alloc] initWithIdentifier:"A"]; + [table addTableColumn:columnA]; + [[columnA headerView] setStringValue:"A"]; + [columnA setWidth:175]; + + columnB = [[CPTableColumn alloc] initWithIdentifier:"B"]; + [table addTableColumn:columnB]; + [[columnB headerView] setStringValue:"B"]; + [columnB setWidth:175] + + columnC = [[CPTableColumn alloc] initWithIdentifier:"C"]; + [table addTableColumn:columnC]; + [[columnC headerView] setStringValue:"C"]; + [columnC setWidth:175]; + + columnD = [[CPTableColumn alloc] initWithIdentifier:"D"]; + [table addTableColumn:columnD]; + [[columnD headerView] setStringValue:"D"]; + [columnD setWidth:175]; + + columnE = [[CPTableColumn alloc] initWithIdentifier:"E"]; + [table addTableColumn:columnE]; + [[columnE headerView] setStringValue:"E"]; + [columnE setWidth:175]; + + [scroll setDocumentView:table]; + + [contentView addSubview:scroll]; + + [theWindow orderFront:self]; + +} + +- (int)numberOfRowsInTableView:(id)tableView +{ + return 10000; +} + +- (id)tableView:(id)tableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow +{ + return "Column " + [aColumn identifier] + " Row " + aRow; +} + +@end + +var BADGE_HEIGHT = 15.0, + ROW_RIGHT_MARGIN = 10.0; +var randomColors = {}; + +@implementation TableViewDrawRow : CPTableView + ++ (CPColor)colorForRow:(CPInteger)aRow +{ + var rowStr = String(aRow); + if (randomColors[rowStr] == nil) + randomColors[rowStr] = [CPColor randomColor]; + + return randomColors[rowStr]; +} + +- (void)drawRow:(CPInteger)aRow clipRect:(CGRect)clipRect +{ + var viewRect = [self frameOfDataViewAtColumn:[self columnWithIdentifier:@"A"] row:aRow], + badgeWidth = CGRectGetWidth(viewRect)/5, + badgePath = [CPBezierPath bezierPath]; + + var badgeFrame = CGRectMake(CGRectGetMaxX(viewRect) - badgeWidth - ROW_RIGHT_MARGIN, + CGRectGetMidY(viewRect) - BADGE_HEIGHT / 2.0, + badgeWidth, + BADGE_HEIGHT); + + [badgePath appendBezierPathWithRoundedRect:badgeFrame xRadius:(BADGE_HEIGHT/2.0) yRadius:(BADGE_HEIGHT/2.0)]; + [[TableViewDrawRow colorForRow:aRow] setFill]; + [badgePath fill]; +} + +@end diff --git a/Tests/Manual/TableTest/DrawRowTest/Info.plist b/Tests/Manual/TableTest/DrawRowTest/Info.plist new file mode 100644 index 000000000..b66b60433 --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/Info.plist @@ -0,0 +1,12 @@ + + + + + CPApplicationDelegateClass + AppController + CPBundleName + DrawRowTest + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/TableTest/DrawRowTest/Jakefile b/Tests/Manual/TableTest/DrawRowTest/Jakefile new file mode 100644 index 000000000..a1ef79223 --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/Jakefile @@ -0,0 +1,93 @@ +/* + * Jakefile + * DrawRowTest + * + * Created by You on August 11, 2010. + * Copyright 2010, Your Company 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 ("DrawRowTest", function(task) +{ + task.setBuildIntermediatesPath(FILE.join("Build", "DrawRowTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("DrawRowTest"); + task.setIdentifier("com.yourcompany.DrawRowTest"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("DrawRowTest"); + task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", ["DrawRowTest"], 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", "DrawRowTest", "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", "DrawRowTest", "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", "DrawRowTest")); + OS.system(["press", "-f", FILE.join("Build", "Release", "DrawRowTest"), FILE.join("Build", "Deployment", "DrawRowTest")]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", "DrawRowTest")); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "DrawRowTest"), FILE.join("Build", "Desktop", "DrawRowTest", "DrawRowTest.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", "DrawRowTest", "DrawRowTest.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, "DrawRowTest")); + print("----------------------------"); +} diff --git a/Tests/Manual/TableTest/DrawRowTest/Resources/spinner.gif b/Tests/Manual/TableTest/DrawRowTest/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/TableTest/DrawRowTest/index-debug.html b/Tests/Manual/TableTest/DrawRowTest/index-debug.html new file mode 100644 index 000000000..434bd3ad3 --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/index-debug.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + DrawRowTest + + + + + + + + + + + + + + +
+
+ + + +
+
+ + + diff --git a/Tests/Manual/TableTest/DrawRowTest/index.html b/Tests/Manual/TableTest/DrawRowTest/index.html new file mode 100644 index 000000000..1db8fa36b --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/index.html @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + DrawRowTest + + + + + + + + + + + + +
+
+ + + +
+
+ + + + diff --git a/Tests/Manual/TableTest/DrawRowTest/main.j b/Tests/Manual/TableTest/DrawRowTest/main.j new file mode 100644 index 000000000..48abc83d4 --- /dev/null +++ b/Tests/Manual/TableTest/DrawRowTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * DrawRowTest + * + * Created by You on August 11, 2010. + * Copyright 2010, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} From 4fc894e430c3b06737d2ece65c44d14ff8de6493 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 11 Aug 2010 15:29:28 -0400 Subject: [PATCH 184/356] Fix for issue #820 (horizontal grid drawn incorrectly with no rows) --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 7f5f20c0c..a343975db 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2568,7 +2568,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var exposedRows = [self rowsInRect:aRect]; row = exposedRows.location, lastRow = CPMaxRange(exposedRows) - 1, - rowY = 0.0, + rowY = -0.5, minX = _CGRectGetMinX(aRect), maxX = _CGRectGetMaxX(aRect); From 5b1ca8a7f9f11444595fa1985d2c9110d24c0de9 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 2 Aug 2010 12:06:06 -0400 Subject: [PATCH 185/356] Fix for issue #807 (NSTextField sets text color unconditionally, which causes theme lookup failure later) --- Tools/nib2cib/NSTextField.j | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSTextField.j b/Tools/nib2cib/NSTextField.j index d9d935085..1368ea40e 100644 --- a/Tools/nib2cib/NSTextField.j +++ b/Tools/nib2cib/NSTextField.j @@ -54,7 +54,12 @@ [self setPlaceholderString:[cell placeholderString]]; - [self setTextColor:[cell textColor]]; + var textColor = [cell textColor], + defaultColor = [self currentValueForThemeAttribute:@"text-color"]; + + // Don't change the text color if it is not the default, that messes up the theme lookups later + if (![textColor isEqual:defaultColor]) + [self setTextColor:[cell textColor]]; var frame = [self frame]; From 66f84ede6ede2d7b032d295353e6f1b51ea7e523 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Thu, 29 Jul 2010 13:23:52 -0400 Subject: [PATCH 186/356] Fix for issue #799 (NSFont replaces LucidaGrande-Bold 13 with the theme font) --- Tools/nib2cib/NSFont.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSFont.j b/Tools/nib2cib/NSFont.j index 41643eb22..a08990d11 100644 --- a/Tools/nib2cib/NSFont.j +++ b/Tools/nib2cib/NSFont.j @@ -31,7 +31,7 @@ fontName = [aCoder decodeObjectForKey:@"NSName"], size = [aCoder decodeDoubleForKey:@"NSSize"]; - if ((fontName === "LucidaGrande" || fontName === "LucidaGrande-Bold") && size === 13) + if (fontName === "LucidaGrande" && size === 13) { CPLog.debug("Removing default IB font: <"+fontName+", "+size+"> for theme default font."); return nil; From 567f54c9f95c73267d822600d3897d3219cb60ed Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 17:32:50 -0500 Subject: [PATCH 187/356] Fix global from error in previous mergre. --- AppKit/CPTableView.j | 1 + 1 file changed, 1 insertion(+) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index a343975db..779ceedf0 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -213,6 +213,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing); BOOL _lastColumnShouldSnap; + BOOL _implementsCustomDrawRow; CPTableColumn _draggedColumn; CPArray _differedColumnDataToRemove; From a0bcae2404d3e4f0c07f3090dd69c40696ca036e Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 11 Aug 2010 18:52:21 -0400 Subject: [PATCH 188/356] The Cocoa default is always to draw column lines, this wasn't being set in CPTableColumnView. --- Tools/nib2cib/NSTableHeaderView.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/nib2cib/NSTableHeaderView.j b/Tools/nib2cib/NSTableHeaderView.j index ab68dc1cd..d86d39629 100644 --- a/Tools/nib2cib/NSTableHeaderView.j +++ b/Tools/nib2cib/NSTableHeaderView.j @@ -36,6 +36,8 @@ _bounds.size.height = 23; _frame.size.height = 23; } + + _drawsColumnLines = YES; } return self; From 952bb4bb7c8ca5df2d2628f84005d942a53d5a5b Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Fri, 18 Jun 2010 11:39:30 -0400 Subject: [PATCH 189/356] added CPShadow shadowViewEnclosingView --- AppKit/CPShadowView.j | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/AppKit/CPShadowView.j b/AppKit/CPShadowView.j index 36cfabdad..72fb69620 100644 --- a/AppKit/CPShadowView.j +++ b/AppKit/CPShadowView.j @@ -93,6 +93,31 @@ var LIGHT_LEFT_INSET = 3.0, ]]]; } ++ (id)shadowViewEnclosingView:(CPView)aView +{ + return [self shadowViewEnclosingView:aView withWeight:CPLightShadow]; +} + ++ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight +{ + var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]]; + [shadowView setWeight:aWeight]; + + var size = [shadowView frame].size, + width = size.width - [shadowView leftInset] - [shadowView rightInset], + height = size.height - [shadowView topInset] - [shadowView bottomInset], + enclosingView = [aView superview]; + + [shadowView setHitTests:[aView hitTests]]; + [shadowView setAutoresizingMask:[aView autoresizingMask]]; + [aView removeFromSuperview]; + [shadowView addSubview:aView]; + [aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)] + [enclosingView addSubview:shadowView]; + + return shadowView; +} + - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; From 6b8e10cb2ed28e0ebbdf6a220cdf2405b593cd5c Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 11 Aug 2010 19:20:10 -0400 Subject: [PATCH 190/356] Whitespace cleanup of CPShadowView. --- AppKit/CPShadowView.j | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/AppKit/CPShadowView.j b/AppKit/CPShadowView.j index 72fb69620..c1aaac6f5 100644 --- a/AppKit/CPShadowView.j +++ b/AppKit/CPShadowView.j @@ -35,12 +35,12 @@ CPHeavyShadow = 1; var CPShadowViewLightBackgroundColor = nil, CPShadowViewHeavyBackgroundColor = nil; - + var LIGHT_LEFT_INSET = 3.0, LIGHT_RIGHT_INSET = 3.0, LIGHT_TOP_INSET = 3.0, LIGHT_BOTTOM_INSET = 5.0, - + HEAVY_LEFT_INSET = 7.0, HEAVY_RIGHT_INSET = 7.0, HEAVY_TOP_INSET = 5.0, @@ -61,32 +61,32 @@ var LIGHT_LEFT_INSET = 3.0, return; var bundle = [CPBundle bundleForClass:[self class]]; - + CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: [ [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)], - + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)], nil, [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)], - + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)] ]]]; - + CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: [ [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)], - + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)], nil, [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)], - + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)] @@ -102,35 +102,35 @@ var LIGHT_LEFT_INSET = 3.0, { var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]]; [shadowView setWeight:aWeight]; - + var size = [shadowView frame].size, width = size.width - [shadowView leftInset] - [shadowView rightInset], height = size.height - [shadowView topInset] - [shadowView bottomInset], enclosingView = [aView superview]; - + [shadowView setHitTests:[aView hitTests]]; [shadowView setAutoresizingMask:[aView autoresizingMask]]; [aView removeFromSuperview]; [shadowView addSubview:aView]; [aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)] [enclosingView addSubview:shadowView]; - + return shadowView; } - (id)initWithFrame:(CGRect)aFrame { self = [super initWithFrame:aFrame]; - + if (self) { _weight = CPLightShadow; - + [self setBackgroundColor:CPShadowViewLightBackgroundColor]; - + [self setHitTests:NO]; } - + return self; } @@ -138,9 +138,9 @@ var LIGHT_LEFT_INSET = 3.0, { if (_weight == aWeight) return; - + _weight = aWeight; - + if (_weight == CPLightShadow) [self setBackgroundColor:CPShadowViewLightBackgroundColor]; @@ -172,7 +172,7 @@ var LIGHT_LEFT_INSET = 3.0, { if (_weight == CPLightShadow) return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET; - + return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET; } @@ -180,7 +180,7 @@ var LIGHT_LEFT_INSET = 3.0, { if (_weight == CPLightShadow) return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET; - + return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET; } From 4b8cc3e6d110a0e370805d32bf7d6e2800940f49 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 18:39:16 -0500 Subject: [PATCH 191/356] Table column drag view should draw lines the same color as the parent tableview. --- AppKit/CPTableView.j | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 779ceedf0..66f5bf125 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2019,9 +2019,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; */ - (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset { - var dragView = [[_CPColumnDragView alloc] initWithFrame:CPRectMakeZero()]; + var dragView = [[_CPColumnDragView alloc] initWithLineColor:[self gridColor]]; tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex], - bounds = CPRectMake(0.0, 0.0, [tableColumn width], CPRectGetHeight([self _exposedRect]) + 23.0), + bounds = CPRectMake(0.0, 0.0, [tableColumn width], _CGRectGetHeight([self _exposedRect]) + 23.0), columnRect = [self rectOfColumn:theColumnIndex], headerView = [tableColumn headerView], row = [_exposedRows firstIndex]; @@ -2035,7 +2035,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; dataViewFrame.origin.x = 0.0; // Offset by table header height - scroll position - dataViewFrame.origin.y = ( CPRectGetMinY(dataViewFrame) - CPRectGetMinY([self _exposedRect]) ) + 23.0; + dataViewFrame.origin.y = ( _CGRectGetMinY(dataViewFrame) - _CGRectGetMinY([self _exposedRect]) ) + 23.0; [dataView setFrame:dataViewFrame]; [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; @@ -2046,7 +2046,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // Add the column header view var headerFrame = [headerView frame]; - headerFrame.origin = CPPointMakeZero(); + headerFrame.origin = _CGPointMakeZero(); var columnHeaderView = [[_CPTableColumnHeaderView alloc] initWithFrame:headerFrame]; [columnHeaderView setStringValue:[headerView stringValue]]; @@ -3721,11 +3721,25 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", @end @implementation _CPColumnDragView : CPView +{ + CPColor _lineColor; +} + +- (id)initWithLineColor:(CPColor)aColor +{ + self = [super initWithFrame:_CGRectMakeZero()]; + + if (self) + _lineColor = aColor; + + return self; +} + - (void)drawRect:(CGRect)aRect { var context = [[CPGraphicsContext currentContext] graphicsPort]; - CGContextSetStrokeColor(context, [CPColor grayColor]); + CGContextSetStrokeColor(context, _lineColor); var points = [ _CGPointMake(0.5, 0), From ed52b44f8bb1c9660a4bf93a171122a2b1572cd3 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 19:07:13 -0500 Subject: [PATCH 192/356] Removed redundent methods in the tableview. Closes #822 --- AppKit/CPTableView.j | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 66f5bf125..27884902d 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2021,7 +2021,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { var dragView = [[_CPColumnDragView alloc] initWithLineColor:[self gridColor]]; tableColumn = [[self tableColumns] objectAtIndex:theColumnIndex], - bounds = CPRectMake(0.0, 0.0, [tableColumn width], _CGRectGetHeight([self _exposedRect]) + 23.0), + bounds = CPRectMake(0.0, 0.0, [tableColumn width], _CGRectGetHeight([self visibleRect]) + 23.0), columnRect = [self rectOfColumn:theColumnIndex], headerView = [tableColumn headerView], row = [_exposedRows firstIndex]; @@ -2035,7 +2035,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; dataViewFrame.origin.x = 0.0; // Offset by table header height - scroll position - dataViewFrame.origin.y = ( _CGRectGetMinY(dataViewFrame) - _CGRectGetMinY([self _exposedRect]) ) + 23.0; + dataViewFrame.origin.y = ( _CGRectGetMinY(dataViewFrame) - _CGRectGetMinY([self visibleRect]) ) + 23.0; [dataView setFrame:dataViewFrame]; [dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]]; @@ -2175,16 +2175,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return objectValue; } -- (CGRect)_exposedRect -{ - var superview = [self superview]; - - if (![superview isKindOfClass:[CPClipView class]]) - return [self bounds]; - - return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview]; -} - - (void)load { if (_reloadAllRows) @@ -2197,7 +2187,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; _reloadAllRows = NO; } - var exposedRect = [self _exposedRect], + var exposedRect = [self visibleRect], exposedRows = [CPIndexSet indexSetWithIndexesInRange:[self rowsInRect:exposedRect]], exposedColumns = [self columnIndexesInRect:exposedRect], obscuredRows = [_exposedRows copy], @@ -2459,16 +2449,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))]; } -- (CGRect)exposedClipRect -{ - var superview = [self superview]; - - if (![superview isKindOfClass:[CPClipView class]]) - return [self bounds]; - - return [self convertRect:CGRectIntersection([superview bounds], [self frame]) fromView:superview]; -} - - (void)setNeedsDisplay:(BOOL)aFlag { [super setNeedsDisplay:aFlag]; @@ -2480,7 +2460,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; // FIX ME: All three of these methods will likely need to be rewritten for 1.0 // We've got grid drawing in highlightSelection and crap everywhere. - var exposedRect = [self _exposedRect]; + var exposedRect = [self visibleRect]; [self drawBackgroundInClipRect:exposedRect]; [self drawGridInClipRect:exposedRect]; @@ -3165,7 +3145,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; var row = [self _proposedRowAtPoint:location], dragOperation = [self _validateDrop:sender proposedRow:row proposedDropOperation:dropOperation]; - exposedClipRect = [self exposedClipRect]; + exposedClipRect = [self visibleRect]; if(_retargetedDropRow !== nil) row = _retargetedDropRow; @@ -3174,7 +3154,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; if (dropOperation === CPTableViewDropOn && row >= [self numberOfRows]) row = [self numberOfRows] - 1; - var rect = CPRectMakeZero(); + var rect = _CGRectMakeZero(); if (row === -1) rect = exposedClipRect; From ad33d1648ce36c382a171cee8898b54ad60a859f Mon Sep 17 00:00:00 2001 From: David Hess Date: Wed, 7 Jul 2010 00:05:40 -0500 Subject: [PATCH 193/356] Patch to CPSlider to invert its value in vertical mode so that max value is represented at the top of the track instead of the bottom. --- AppKit/CPSlider.j | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AppKit/CPSlider.j b/AppKit/CPSlider.j index b448becd0..36f951f5c 100644 --- a/AppKit/CPSlider.j +++ b/AppKit/CPSlider.j @@ -198,7 +198,7 @@ CPCircularSlider = 1; else if ([self isVertical]) { knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0; - knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height); + knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height); } else { @@ -320,7 +320,7 @@ CPCircularSlider = 1; var minValue = [self minValue]; - return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue; + return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue; } else { From fd9a753170f660ad61584f6586cf8f0d6390fa20 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Sat, 24 Jul 2010 09:49:50 -0400 Subject: [PATCH 194/356] Port of NSGraphics --- AppKit/CPGraphics.j | 122 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 AppKit/CPGraphics.j diff --git a/AppKit/CPGraphics.j b/AppKit/CPGraphics.j new file mode 100644 index 000000000..3044acf7e --- /dev/null +++ b/AppKit/CPGraphics.j @@ -0,0 +1,122 @@ +/* + * CPGraphics.j + * AppKit + * + * Created by Francisco Tolmasky. + * Copyright 2010, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 "CPColor.j" +@import "CPGraphicsContext.j" + +#include "CoreGraphics/CGGeometry.h" + + +function CPDrawGrayBezel(aRect) +{ + var context = [[CPGraphicsContext currentContext] graphicsPort]; + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]); + + var y = _CGRectGetMinY(aRect) + 0.5; + + CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y); + CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y); + CGContextStrokePath(context); + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]); + CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y); + CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); + CGContextStrokePath(context); + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]); + CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); + CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y); + CGContextStrokePath(context); + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]); + + var x = _CGRectGetMaxX(aRect) - 0.5; + + CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0); + CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect)); + + CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5); + CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5); + + x = _CGRectGetMinX(aRect) + 0.5; + + CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect)); + CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0); + + CGContextStrokePath(context); +} + +function CPDrawGroove(aRect, drawTopBorder) +{ + var context = [[CPGraphicsContext currentContext] graphicsPort]; + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0/255.0 alpha:1.0]); + + var y = _CGRectGetMinY(aRect) + 0.5; + + CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y); + CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y); + + var x = _CGRectGetMaxX(aRect) - 1.5; + + CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0); + CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0); + + y = _CGRectGetMaxY(aRect) - 1.5; + + CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); + CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y); + + x = _CGRectGetMinX(aRect) + 0.5; + + CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect)); + CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect)); + + CGContextStrokePath(context); + + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor whiteColor]); + + var rect = _CGRectOffset(aRect, 1.0, 1.0); + + rect.size.width -= 1.0; + rect.size.height -= 1.0; + CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5)); + + if (drawTopBorder) + { + CGContextBeginPath(context); + CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]); + + y = _CGRectGetMinY(aRect) + 2.5; + + CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y); + CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y); + CGContextStrokePath(context); + } +} From fcf9c0bc8438ec956937053accf52743445c9397 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 27 Jul 2010 16:42:50 -0400 Subject: [PATCH 195/356] Full support for all NSScrollView border types, beginnings of a new tableview tester that shows dynamic changing of border type. --- AppKit/CPScrollView.j | 197 +++- Tests/Manual/NewTableTest/AppController.j | 60 ++ Tests/Manual/NewTableTest/Info.plist | 12 + .../NewTableTest/Resources/MainMenu.cib | 1 + .../NewTableTest/Resources/MainMenu.xib | 845 ++++++++++++++++++ .../Manual/NewTableTest/Resources/spinner.gif | Bin 0 -> 1849 bytes Tests/Manual/NewTableTest/index-debug.html | 94 ++ Tests/Manual/NewTableTest/index.html | 68 ++ Tests/Manual/NewTableTest/main.j | 18 + Tools/nib2cib/NSScrollView.j | 2 + 10 files changed, 1263 insertions(+), 34 deletions(-) create mode 100644 Tests/Manual/NewTableTest/AppController.j create mode 100644 Tests/Manual/NewTableTest/Info.plist create mode 100644 Tests/Manual/NewTableTest/Resources/MainMenu.cib create mode 100644 Tests/Manual/NewTableTest/Resources/MainMenu.xib create mode 100644 Tests/Manual/NewTableTest/Resources/spinner.gif create mode 100644 Tests/Manual/NewTableTest/index-debug.html create mode 100644 Tests/Manual/NewTableTest/index.html create mode 100755 Tests/Manual/NewTableTest/main.j diff --git a/AppKit/CPScrollView.j b/AppKit/CPScrollView.j index 051195b66..b0d89c1f7 100644 --- a/AppKit/CPScrollView.j +++ b/AppKit/CPScrollView.j @@ -37,23 +37,25 @@ */ @implementation CPScrollView : CPView { - CPClipView _contentView; - CPClipView _headerClipView; - CPView _cornerView; - - BOOL _hasVerticalScroller; - BOOL _hasHorizontalScroller; - BOOL _autohidesScrollers; - - CPScroller _verticalScroller; - CPScroller _horizontalScroller; - - int _recursionCount; - - float _verticalLineScroll; - float _verticalPageScroll; - float _horizontalLineScroll; - float _horizontalPageScroll; + CPClipView _contentView; + CPClipView _headerClipView; + CPView _cornerView; + + BOOL _hasVerticalScroller; + BOOL _hasHorizontalScroller; + BOOL _autohidesScrollers; + + CPScroller _verticalScroller; + CPScroller _horizontalScroller; + + int _recursionCount; + + float _verticalLineScroll; + float _verticalPageScroll; + float _horizontalLineScroll; + float _horizontalPageScroll; + + CPBorderType _borderType; } - (id)initWithFrame:(CGRect)aFrame @@ -67,8 +69,10 @@ _horizontalLineScroll = 10.0; _horizontalPageScroll = 10.0; + + _borderType = CPNoBorder; - _contentView = [[CPClipView alloc] initWithFrame:[self bounds]]; + _contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]]; [self addSubview:_contentView]; @@ -83,6 +87,65 @@ return self; } +// Calculating Layout + ++ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType +{ + var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType], + scrollerWidth = [CPScroller scrollerWidth]; + + if (hFlag) + bounds.size.height -= scrollerWidth; + + if (vFlag) + bounds.size.width -= scrollerWidth; + + return bounds.size; +} + ++ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType +{ + var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType], + widthInset = contentSize.width - bounds.size.width, + heightInset = contentSize.height - bounds.size.height, + frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset), + scrollerWidth = [CPScroller scrollerWidth]; + + if (hFlag) + frameSize.height -= scrollerWidth; + + if (vFlag) + frameSize.width -= scrollerWidth; + + return frameSize; +} + ++ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType +{ + switch (borderType) + { + case CPLineBorder: + case CPBezelBorder: + return _CGRectInset(bounds, 1.0, 1.0); + + case CPGrooveBorder: + bounds = _CGRectInset(bounds, 2.0, 2.0); + ++bounds.origin.y; + --bounds.size.height; + + return bounds; + + case CPNoBorder: + default: + return bounds; + } +} + +- (CGRect)_insetBounds +{ + return [[self class] _insetBounds:[self bounds] borderType:_borderType]; +} + // Determining component sizes /*! Returns the size of the scroll view's content view. @@ -176,7 +239,7 @@ // [_horizontalScroller setEnabled:NO]; } - [_contentView setFrame:[self bounds]]; + [_contentView setFrame:[self _insetBounds]]; [_headerClipView setFrame:_CGRectMakeZero()]; --_recursionCount; @@ -185,7 +248,7 @@ } var documentFrame = [documentView frame], // the size of the whole document - contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers) + contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers) headerClipViewFrame = [self _headerClipViewFrame], headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame); @@ -235,11 +298,8 @@ if (shouldShowVerticalScroller) { - var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight), - verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY; - - if (shouldShowHorizontalScroller) - verticalScrollerHeight -= horizontalScrollerHeight; + var verticalScrollerY = MAX(_CGRectGetMaxY([self _cornerViewFrame]), headerClipViewHeight), + verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY; [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height]; [_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)]; @@ -255,7 +315,7 @@ { [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width]; [_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)]; - [_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)]; + [_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)]; } else if (wasShowingHorizontalScroller) { @@ -270,6 +330,30 @@ --_recursionCount; } +// Managing Graphics Attributes + +/*! + Sets the type of border to be drawn around the view. +*/ +- (void)setBorderType:(CPBorderType)borderType +{ + if (_borderType == borderType) + return; + + _borderType = borderType; + + [self reflectScrolledClipView:_contentView]; + [self setNeedsDisplay:YES]; +} + +/*! + Returns the border type drawn around the view. +*/ +- (CPBorderType)borderType +{ + return _borderType; +} + // Managing Scrollers /*! Sets the scroll view's horizontal scroller. @@ -316,8 +400,10 @@ if (_hasHorizontalScroller && !_horizontalScroller) { - [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]]; - [[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]; + var bounds = [self _insetBounds]; + + [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]]; + [[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])]; } [self reflectScrolledClipView:_contentView]; @@ -377,8 +463,10 @@ if (_hasVerticalScroller && !_verticalScroller) { - [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]]; - [[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]; + var bounds = [self _insetBounds]; + + [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth]+1))]]; + [[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))]; } [self reflectScrolledClipView:_contentView]; @@ -453,11 +541,11 @@ if (!_cornerView) return _CGRectMakeZero(); - var bounds = [self bounds], + var bounds = [self _insetBounds], frame = [_cornerView frame]; frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame); - frame.origin.y = 0; + frame.origin.y = _CGRectGetMinY(bounds); return frame; } @@ -469,7 +557,7 @@ if (!headerView) return _CGRectMakeZero(); - var frame = [self bounds]; + var frame = [self _insetBounds]; frame.size.height = _CGRectGetHeight([headerView frame]); frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]); @@ -662,6 +750,42 @@ return _verticalPageScroll; } +// CPView Overrides + +- (void)drawRect:(CPRect)aRect +{ + [super drawRect:aRect]; + + var strokeRect = [self bounds], + context = [[CPGraphicsContext currentContext] graphicsPort]; + + if (_borderType == CPNoBorder) + return; + + CGContextSetLineWidth(context, 1); + + switch (_borderType) + { + case CPLineBorder: + CGContextSetStrokeColor(context, [CPColor blackColor]); + CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5)); + break; + + case CPBezelBorder: + CPDrawGrayBezel(strokeRect); + break; + + case CPGrooveBorder: + CPDrawGroove(strokeRect, YES); + break; + + default: + break; + } +} + +// CPResponder Overrides + /*! Handles a scroll wheel event from the user. @param anEvent the scroll wheel event @@ -758,7 +882,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", CPScrollViewVScrollerKey = "CPScrollViewVScroller", CPScrollViewHScrollerKey = "CPScrollViewHScroller", CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller", - CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey"; + CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey", + CPScrollViewBorderTypeKey = "CPScrollViewBorderTypeKey"; @implementation CPScrollView (CPCoding) @@ -788,6 +913,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", _hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey]; _autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey]; + _borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey]; + _cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey]; // Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state. @@ -817,6 +944,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey]; [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey]; + + [aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey]; } @end diff --git a/Tests/Manual/NewTableTest/AppController.j b/Tests/Manual/NewTableTest/AppController.j new file mode 100644 index 000000000..103fceb50 --- /dev/null +++ b/Tests/Manual/NewTableTest/AppController.j @@ -0,0 +1,60 @@ +/* + * AppController.j + * TableCibTest + * + * Created by Francisco Tolmasky on July 5, 2009. + * Copyright 2009, 280 North, Inc. All rights reserved. + */ + +@import + +CPLogRegister(CPLogConsole); + +@implementation AppController : CPObject +{ + CPWindow theWindow; //this "outlet" is connected automatically by the Cib + CPScrollView theScrollView; + CPTableView theTableView; + CPPopupButton theBorderTypePopup; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + // This is called when the application is done loading. +} + +- (void)awakeFromCib +{ + // This is called when the cib is done loading. + // You can implement this method on any object instantiated from a Cib. + // It's a useful hook for setting up current UI values, and other things. + + // In this case, we want the window from Cib to become our full browser window + [theWindow setFullPlatformWindow:YES]; + + [theWindow setBackgroundColor:[CPColor colorWithHexString:@"f3f4f5"]]; + + [theBorderTypePopup selectItemWithTag:[theScrollView borderType]]; +} + +- (int)numberOfRowsInTableView:(CPTableView)tableView +{ + return 10; +} + +- (id)tableView:(CPTableView)tableView objectValueForTableColumn:(CPTableColumn)tableColumn row:(int)row +{ + return String((row + 1) * [[tableColumn identifier] intValue]); +} + +// Actions + +- (void)setBorder:(id)sender +{ + var type = [[sender selectedItem] tag]; + console.log('type=%d', type); + + [theScrollView setBorderType:type]; +} + +@end \ No newline at end of file diff --git a/Tests/Manual/NewTableTest/Info.plist b/Tests/Manual/NewTableTest/Info.plist new file mode 100644 index 000000000..f2ebe529d --- /dev/null +++ b/Tests/Manual/NewTableTest/Info.plist @@ -0,0 +1,12 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + TableCibTest + CPPrincipalClass + CPApplication + + diff --git a/Tests/Manual/NewTableTest/Resources/MainMenu.cib b/Tests/Manual/NewTableTest/Resources/MainMenu.cib new file mode 100644 index 000000000..5cf64541f --- /dev/null +++ b/Tests/Manual/NewTableTest/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;26E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;34E;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;2;39E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;1;0E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;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;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;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;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;85E;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;24E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;37E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;43E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;49E;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;22E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;41E;D;K;6;CP$UIDd;2;16E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;29E;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;2;86E;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;2;87E;E;D;K;10;$classnameS;10;CPScrollerK;8;$classesA;S;10;CPScrollerS;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;47E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;88E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;89E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;47E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;91E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;92E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;47E;K;18;CPControlActionKeyD;K;6;CP$UIDd;2;93E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;2;92E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;2;95E;E;D;K;10;$classnameS;6;CPMenuK;8;$classesA;S;6;CPMenuS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;21E;K;14;CPMenuTitleKeyD;K;6;CP$UIDd;2;96E;K;14;CPMenuItemsKeyD;K;6;CP$UIDd;2;97E;E;D;K;10;$classnameS;13;CPTableColumnK;8;$classesA;S;13;CPTableColumnS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;23E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;2;98E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;2;99E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;100E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;101E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;103E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;104E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;3;105E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;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;25E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;106E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;29E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;107E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;3;108E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;22E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;109E;E;D;K;6;$classD;K;6;CP$UIDd;2;25E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;110E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;29E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;107E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;1;0E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;3;108E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;22E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;109E;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;28E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;33E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;111E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;112E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;33E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;113E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;114E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;94E;K;11;$aalignmentD;K;6;CP$UIDd;2;92E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;16;CPButtonImageKeyD;K;6;CP$UIDd;1;0E;K;25;CPButtonAlternateImageKeyD;K;6;CP$UIDd;1;0E;K;16;CPButtonTitleKeyD;K;6;CP$UIDd;1;0E;K;25;CPButtonAlternateTitleKeyD;K;6;CP$UIDd;1;0E;K;32;CPButtonImageDimsWhenDisabledKeyD;K;6;CP$UIDd;1;0E;K;28;CPButtonKeyEquivalentMaskKeyD;K;6;CP$UIDd;1;0E;K;20;CPPopUpButtonMenuKeyD;K;6;CP$UIDd;2;22E;K;29;CPPopUpButtonSelectedIndexKeyD;K;6;CP$UIDd;2;92E;E;D;K;6;$classD;K;6;CP$UIDd;2;23E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;115E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;116E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;117E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;118E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;119E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;120E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;3;105E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;25E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;121E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;29E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;107E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;3;105E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;22E;K;38;CPMenuItemKeyEquivalentModifierMaskKeyD;K;6;CP$UIDd;3;109E;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;32E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;122E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;122E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;123E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;3;125E;E;D;K;10;$classnameS;17;CPTableHeaderViewK;8;$classesA;S;17;CPTableHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;35E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;126E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;127E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;127E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;126E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;29;CPTableHeaderViewTableViewKeyD;K;6;CP$UIDd;2;41E;E;D;K;6;$classD;K;6;CP$UIDd;2;25E;K;18;CPMenuItemTitleKeyD;K;6;CP$UIDd;3;128E;K;19;CPMenuItemTargetKeyD;K;6;CP$UIDd;2;29E;K;19;CPMenuItemActionKeyD;K;6;CP$UIDd;3;107E;K;21;CPMenuItemIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;16;CPMenuItemTagKeyD;K;6;CP$UIDd;3;129E;K;18;CPMenuItemStateKeyD;K;6;CP$UIDd;1;0E;K;17;CPMenuItemMenuKeyD;K;6;CP$UIDd;2;22E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;38E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;3;130E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;3;131E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;3;132E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;3;133E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;3;134E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;33E;E;D;K;10;$classnameS;11;CPTableViewK;8;$classesA;S;11;CPTableViewS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;40E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;135E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;136E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;136E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;135E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;12;$agrid-colorD;K;6;CP$UIDd;3;138E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;24;CPTableViewDataSourceKeyD;K;6;CP$UIDd;1;0E;K;22;CPTableViewDelegateKeyD;K;6;CP$UIDd;1;0E;K;23;CPTableViewRowHeightKeyD;K;6;CP$UIDd;3;139E;K;30;CPTableViewIntercellSpacingKeyD;K;6;CP$UIDd;3;140E;K;31;CPTableViewMultipleSelectionKeyD;K;6;CP$UIDd;3;141E;K;28;CPTableViewEmptySelectionKeyD;K;6;CP$UIDd;3;141E;K;30;CPTableViewColumnReorderingKeyD;K;6;CP$UIDd;3;141E;K;28;CPTableViewColumnResizingKeyD;K;6;CP$UIDd;3;141E;K;29;CPTableViewColumnSelectionKeyD;K;6;CP$UIDd;3;141E;K;26;CPTableViewTableColumnsKeyD;K;6;CP$UIDd;3;142E;K;23;CPTableViewGridColorKeyD;K;6;CP$UIDd;3;138E;K;27;CPTableViewGridStyleMaskKeyD;K;6;CP$UIDd;1;0E;K;39;CPTableViewUsesAlternatingBackgroundKeyD;K;6;CP$UIDd;3;141E;K;34;CPTableViewAlternatingRowColorsKeyD;K;6;CP$UIDd;1;0E;K;24;CPTableViewCornerViewKeyD;K;6;CP$UIDd;3;144E;K;24;CPTableViewHeaderViewKeyD;K;6;CP$UIDd;2;36E;E;D;K;6;$classD;K;6;CP$UIDd;2;19E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;47E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;145E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;146E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;47E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;147E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;92E;K;18;CPControlTargetKeyD;K;6;CP$UIDd;2;47E;K;18;CPControlActionKeyD;K;6;CP$UIDd;3;148E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;94E;K;21;CPScrollerControlSizeD;K;6;CP$UIDd;2;92E;K;24;CPScrollerKnobProportionD;K;6;CP$UIDd;3;149E;E;D;K;6;$classD;K;6;CP$UIDd;2;15E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;86E;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;44E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;33E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;150E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;151E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;33E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;113E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;12;$atext-colorD;K;6;CP$UIDd;3;152E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;105E;K;11;$aalignmentD;K;6;CP$UIDd;2;94E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;153E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;154E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;141E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;141E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;D;K;10;$classnameS;12;CPScrollViewK;8;$classesA;S;12;CPScrollViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;46E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;33E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;155E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;156E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;157E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;33E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;158E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;23;CPScrollViewContentViewD;K;6;CP$UIDd;3;135E;K;29;CPScrollViewHeaderClipViewKeyD;K;6;CP$UIDd;3;126E;K;21;CPScrollViewVScrollerD;K;6;CP$UIDd;2;20E;K;21;CPScrollViewHScrollerD;K;6;CP$UIDd;2;42E;K;23;CPScrollViewVLineScrollD;K;6;CP$UIDd;3;117E;K;23;CPScrollViewVPageScrollD;K;6;CP$UIDd;3;117E;K;23;CPScrollViewHLineScrollD;K;6;CP$UIDd;3;117E;K;23;CPScrollViewHPageScrollD;K;6;CP$UIDd;3;117E;K;24;CPScrollViewHasVScrollerD;K;6;CP$UIDd;3;160E;K;24;CPScrollViewHasHScrollerD;K;6;CP$UIDd;3;160E;K;29;CPScrollViewAutohidesScrollerD;K;6;CP$UIDd;3;160E;K;25;CPScrollViewCornerViewKeyD;K;6;CP$UIDd;3;144E;K;25;CPScrollViewBorderTypeKeyD;K;6;CP$UIDd;3;105E;E;D;K;6;$classD;K;6;CP$UIDd;2;23E;K;26;CPTableColumnIdentifierKeyD;K;6;CP$UIDd;3;161E;K;21;CPTableColumnWidthKeyD;K;6;CP$UIDd;3;162E;K;24;CPTableColumnMinWidthKeyD;K;6;CP$UIDd;3;100E;K;24;CPTableColumnMaxWidthKeyD;K;6;CP$UIDd;3;101E;K;26;CPTableColumnHeaderViewKeyD;K;6;CP$UIDd;3;163E;K;24;CPTableColumnDataViewKeyD;K;6;CP$UIDd;3;164E;K;28;CPTableColumnResizingMaskKeyD;K;6;CP$UIDd;3;105E;K;24;CPTableColumnIsHiddenKeyD;K;6;CP$UIDd;1;0E;K;28;CPSortDescriptorPrototypeKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;44E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;33E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;165E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;166E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;33E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;113E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;12;$atext-colorD;K;6;CP$UIDd;3;152E;K;17;$aline-break-modeD;K;6;CP$UIDd;3;105E;K;11;$aalignmentD;K;6;CP$UIDd;2;92E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;167E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;154E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;3;141E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;3;141E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;E;S;17;Vertical ScrollerS;13;Menu (Border)S;16;Table Column (2)S;16;Menu Item (Line)S;12;File's OwnerS;25;Text Field Cell (Border:)S;16;Menu Item (None)S;13;Pop Up ButtonS;16;Table Column (3)S;17;Menu Item (Bezel)S;12;Content ViewS;14;App ControllerS;17;Table Header ViewS;18;Menu Item (Groove)S;25;Pop Up Button Cell (None)S;15;Window (Window)S;29;Table View (Column 1, Two, 3)S;19;Horizontal ScrollerS;35;Text Field Cell (Visual Attributes)S;11;ApplicationS;31;Static Text (Visual Attributes)S;33;Bordered Scroll View (Table View)S;16;Table Column (1)S;21;Static Text (Border:)S;27;Text Field Cell (Text Cell)S;29;Text Field Cell (Text Cell)-1S;29;Text Field Cell (Text Cell)-2D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;16E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;34E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;168E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;34E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;29E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;169E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;34E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;47E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;170E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;34E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;41E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;171E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;34E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;39E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;172E;E;D;K;6;$classD;K;6;CP$UIDd;2;77E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;41E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;34E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;173E;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;2;84E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;29E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;34E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;3;174E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;39E;E;E;S;22;{{885, 16}, {15, 215}}S;19;{{0, 0}, {15, 215}}d;1;8S;17;disabled+verticald;1;0S;27;_verticalScrollerDidScroll:d;1;4f;18;0.9956896551724138S;6;BorderD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;37E;E;E;S;1;2d;3;154d;2;40d;4;1000D;K;10;$classnameS;24;_CPTableColumnHeaderViewK;8;$classesA;S;24;_CPTableColumnHeaderViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;102E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;176E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;177E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;179E;E;D;K;6;$classD;K;6;CP$UIDd;2;44E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;180E;K;6;$afontD;K;6;CP$UIDd;3;182E;K;12;$atext-colorD;K;6;CP$UIDd;3;183E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;94E;K;20;$avertical-alignmentD;K;6;CP$UIDd;3;105E;K;11;$aalignmentD;K;6;CP$UIDd;2;92E;K;15;$acontent-insetD;K;6;CP$UIDd;3;185E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;186E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;154E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;186E;E;d;1;2S;4;LineS;17;_popUpItemAction:d;1;1d;7;1048576S;4;NoneS;23;{{104, 309}, {147, 24}}S;19;{{0, 0}, {147, 24}}d;2;12S;8;borderedS;1;3d;3;188d;2;10d;22;3.4028234663852886e+38D;K;6;$classD;K;6;CP$UIDd;3;102E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;187E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;115E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;179E;E;D;K;6;$classD;K;6;CP$UIDd;2;44E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;180E;K;6;$afontD;K;6;CP$UIDd;3;188E;K;12;$atext-colorD;K;6;CP$UIDd;3;189E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;94E;K;20;$avertical-alignmentD;K;6;CP$UIDd;3;105E;K;11;$aalignmentD;K;6;CP$UIDd;2;92E;K;15;$acontent-insetD;K;6;CP$UIDd;3;190E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;186E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;154E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;186E;E;S;5;BezelS;20;{{0, 0}, {941, 593}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;45E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;49E;E;E;S;6;normalS;13;AppControllerD;K;6;$classD;K;6;CP$UIDd;3;159E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;47E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;198E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;199E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;200E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;47E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;197E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;36E;E;S;19;{{0, 0}, {899, 23}}S;6;Grooved;1;3S;28;{1.79769e+308, 1.79769e+308}S;8;CPWindowS;24;{{335, 128}, {941, 593}}d;1;7S;6;WindowD;K;6;$classD;K;6;CP$UIDd;3;159E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;47E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;195E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;136E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;196E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;47E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;21;CPViewBackgroundColorD;K;6;CP$UIDd;3;197E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;24;CPScrollViewDocumentViewD;K;6;CP$UIDd;2;41E;E;S;20;{{0, 0}, {899, 231}}D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;191E;E;d;2;23S;6;{3, 2}F;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;48E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;30E;E;E;D;K;10;$classnameS;13;_CPCornerViewK;8;$classesA;S;13;_CPCornerViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;143E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;47E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;192E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;193E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;47E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;90E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;E;S;19;{{1, 1}, {884, 15}}S;19;{{0, 0}, {884, 15}}S;8;disabledS;29;_horizontalScrollerDidScroll:f;18;0.9988888888888889S;22;{{21, 284}, {117, 25}}S;19;{{0, 0}, {117, 25}}D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;194E;E;S;17;Visual Attributesd;4;3072S;22;{{20, 20}, {901, 249}}S;20;{{0, 0}, {901, 249}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;135E;D;K;6;CP$UIDd;2;20E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;3;126E;D;K;6;CP$UIDd;3;144E;E;E;d;2;18D;K;10;$classnameS;10;CPClipViewK;8;$classesA;S;10;CPClipViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;T;S;1;1d;3;101D;K;6;$classD;K;6;CP$UIDd;3;102E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;3;201E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;K;38;_CPTableColumnHeaderViewStringValueKeyD;K;6;CP$UIDd;3;202E;K;32;_CPTableColumnHeaderViewImageKeyD;K;6;CP$UIDd;1;0E;K;31;_CPTableColumnHeaderViewFontKeyD;K;6;CP$UIDd;3;179E;E;D;K;6;$classD;K;6;CP$UIDd;2;44E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;180E;K;6;$afontD;K;6;CP$UIDd;3;203E;K;12;$atext-colorD;K;6;CP$UIDd;3;204E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;94E;K;20;$avertical-alignmentD;K;6;CP$UIDd;3;105E;K;11;$aalignmentD;K;6;CP$UIDd;2;92E;K;15;$acontent-insetD;K;6;CP$UIDd;3;205E;K;17;CPControlValueKeyD;K;6;CP$UIDd;3;186E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;3;154E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;1;0E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;1;0E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;3;186E;E;S;21;{{41, 312}, {65, 25}}S;18;{{0, 0}, {65, 25}}S;7;Border:S;8;delegateS;18;theBorderTypePopupS;13;theScrollViewS;12;theTableViewS;9;theWindowS;10;dataSourceS;10;setBorder:S;16;{{0, 0}, {0, 0}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;207E;E;E;S;3;TwoD;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;178E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;208E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;113E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;3;141E;E;S;11;placeholderD;K;10;$classnameS;17;_CPThemeAttributeK;8;$classesA;S;17;_CPThemeAttributeS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;209E;K;5;stateD;K;6;CP$UIDd;3;210E;K;5;valueD;K;6;CP$UIDd;3;211E;E;D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;212E;K;6;valuesD;K;6;CP$UIDd;3;214E;E;D;K;10;$classnameS;21;_CPKeyedArchiverValueK;8;$classesA;S;21;_CPKeyedArchiverValueS;7;CPValueS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;184E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;215E;E;S;0;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;216E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;209E;K;5;stateD;K;6;CP$UIDd;3;210E;K;5;valueD;K;6;CP$UIDd;3;211E;E;D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;212E;K;6;valuesD;K;6;CP$UIDd;3;217E;E;D;K;6;$classD;K;6;CP$UIDd;3;184E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;215E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;218E;D;K;6;CP$UIDd;3;218E;D;K;6;CP$UIDd;3;218E;D;K;6;CP$UIDd;3;108E;E;E;S;22;{{885, 225}, {16, 23}}S;18;{{0, 0}, {16, 23}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;2;92E;D;K;6;CP$UIDd;3;108E;E;E;S;20;{{1, 1}, {899, 231}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;41E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;219E;E;S;21;{{1, 232}, {899, 17}}S;19;{{0, 0}, {899, 17}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;36E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;220E;E;E;S;8;Column 1D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;209E;K;5;stateD;K;6;CP$UIDd;3;210E;K;5;valueD;K;6;CP$UIDd;3;211E;E;D;K;6;$classD;K;6;CP$UIDd;3;181E;K;4;nameD;K;6;CP$UIDd;3;212E;K;6;valuesD;K;6;CP$UIDd;3;221E;E;D;K;6;$classD;K;6;CP$UIDd;3;184E;K;15;CPValueValueKeyD;K;6;CP$UIDd;3;215E;E;D;K;10;$classnameS;19;_CPImageAndTextViewK;8;$classesA;S;19;_CPImageAndTextViewS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;206E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;103E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;103E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;158E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;E;S;32;Lucida Grande, Arial, sans-serifS;4;fontS;21;selectedTableDataViewD;K;6;$classD;K;6;CP$UIDd;3;178E;K;13;CPFontNameKeyD;K;6;CP$UIDd;3;208E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;3;113E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;3;160E;E;S;10;text-colorD;K;10;$classnameS;19;CPMutableDictionaryK;8;$classesA;S;19;CPMutableDictionaryS;12;CPDictionaryS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;3;213E;K;10;CP.objectsD;K;21;selectedTableDataViewD;K;6;CP$UIDd;3;197E;K;6;normalD;K;6;CP$UIDd;3;222E;E;E;S;39;{"top":0,"right":0,"bottom":0,"left":5}D;K;6;$classD;K;6;CP$UIDd;3;206E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;119E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;119E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;158E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;E;D;K;6;$classD;K;6;CP$UIDd;3;213E;K;10;CP.objectsD;K;21;selectedTableDataViewD;K;6;CP$UIDd;3;197E;K;6;normalD;K;6;CP$UIDd;3;223E;E;E;f;18;0.8980392156862745D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;108E;D;K;6;CP$UIDd;3;108E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;206E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;3;163E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;3;175E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;3;175E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;3;163E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;3;158E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;3;124E;E;D;K;6;$classD;K;6;CP$UIDd;3;213E;K;10;CP.objectsD;K;21;selectedTableDataViewD;K;6;CP$UIDd;3;197E;K;6;normalD;K;6;CP$UIDd;3;224E;E;E;D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;225E;E;D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;226E;E;D;K;6;$classD;K;6;CP$UIDd;3;137E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;3;227E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;108E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;108E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;228E;D;K;6;CP$UIDd;3;108E;E;E;f;3;0.2E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/Manual/NewTableTest/Resources/MainMenu.xib b/Tests/Manual/NewTableTest/Resources/MainMenu.xib new file mode 100644 index 000000000..a6706fa49 --- /dev/null +++ b/Tests/Manual/NewTableTest/Resources/MainMenu.xib @@ -0,0 +1,845 @@ + + + + 1050 + 10F569 + 762 + 1038.29 + 461.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 762 + + + YES + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + YES + + + YES + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + 7 + 2 + {{335, 157}, {941, 593}} + 1946157056 + Window + NSWindow + + {1.79769e+308, 1.79769e+308} + + + 256 + + YES + + + 274 + + YES + + + 2304 + + YES + + + 256 + {899, 231} + + + YES + + + 256 + {899, 17} + + + + + + + -2147483392 + {{885, 1}, {16, 17}} + + + + + YES + + 1 + 101 + 40 + 1000 + + 75628096 + 2048 + Column 1 + + LucidaGrande + 11 + 3100 + + + 3 + MC4zMzMzMzI5ODU2AA + + + 6 + System + headerTextColor + + 3 + MAA + + + + + 337772096 + 2048 + Text Cell + + LucidaGrande + 13 + 1044 + + + + 6 + System + controlBackgroundColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + 3 + YES + YES + + + + 2 + 154 + 40 + 1000 + + 75628096 + 2048 + Two + + + + + + 337772096 + 2048 + Text Cell + + + + + + 3 + YES + YES + + + + 3 + 188 + 10 + 3.4028234663852886e+38 + + 75628096 + 2048 + 3 + + + 6 + System + headerColor + + 3 + MQA + + + + + + 337772096 + 2048 + Text Cell + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 23 + 35651584 + + + 4 + 15 + 0 + YES + 0 + + + {{1, 17}, {899, 231}} + + + + + + 4 + + + + -2147483392 + {{885, 18}, {15, 215}} + + + + _doScroller: + 0.99568965517241381 + + + + -2147483392 + {{1, 233}, {884, 15}} + + + 1 + + _doScroller: + 0.99888888888888894 + + + + 2304 + + YES + + + {{1, 0}, {899, 17}} + + + + + + 4 + + + + {{20, 324}, {901, 249}} + + + + 562 + + + + + + QSAAAEEgAABByAAAQcgAAA + + + + 292 + {{25, 288}, {109, 17}} + + + YES + + 68288064 + 272630784 + Visual Attributes + + + + 6 + System + controlColor + + + + + + + + 292 + {{104, 256}, {147, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 129 + + + 400 + 75 + + + None + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + Border + + YES + + + + Line + + 1048576 + 2147483647 + + + _popUpItemAction: + 1 + + + + + Bezel + + 1048576 + 2147483647 + + + _popUpItemAction: + 2 + + + + + Groove + + 2147483647 + + + _popUpItemAction: + 3 + + + + + + 1 + YES + YES + 2 + + + + + 292 + {{45, 260}, {57, 17}} + + + YES + + 68288064 + 4195328 + Border: + + + + + + + + {941, 593} + + + + {{0, 0}, {1440, 878}} + {1.79769e+308, 1.79769e+308} + + + AppController + + + + + YES + + + delegate + + + + 451 + + + + theWindow + + + + 459 + + + + dataSource + + + + 500 + + + + setBorder: + + + + 518 + + + + theTableView + + + + 519 + + + + theScrollView + + + + 520 + + + + theBorderTypePopup + + + + 521 + + + + + YES + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 371 + + + YES + + + + + + 372 + + + YES + + + + + + + + + 450 + + + + + 489 + + + YES + + + + + + + + + 490 + + + + + 491 + + + + + 492 + + + YES + + + + + + + + 494 + + + YES + + + + + + 495 + + + YES + + + + + + 496 + + + + + 497 + + + + + 501 + + + YES + + + + + + 502 + + + + + 504 + + + + + 512 + + + YES + + + + + + 513 + + + + + 505 + + + YES + + + + + + 506 + + + YES + + + + + + 507 + + + YES + + + + + + + + + 516 + + + + + 508 + + + + + 509 + + + + + 510 + + + + + 514 + + + YES + + + + + + 515 + + + + + + + YES + + YES + -3.IBPluginDependency + 371.IBEditorWindowLastContentRect + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 371.editorWindowContentRectSynchronizationRect + 371.windowTemplate.maxSize + 372.IBPluginDependency + 489.IBPluginDependency + 490.IBPluginDependency + 491.IBPluginDependency + 492.IBPluginDependency + 494.IBPluginDependency + 495.IBPluginDependency + 496.IBPluginDependency + 497.IBPluginDependency + 505.IBPluginDependency + 506.IBPluginDependency + 507.IBEditorWindowLastContentRect + 507.IBPluginDependency + 508.IBPluginDependency + 509.IBPluginDependency + 510.IBPluginDependency + 512.IBPluginDependency + 513.IBPluginDependency + 514.IBPluginDependency + 515.IBPluginDependency + 516.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + {{387, 319}, {941, 593}} + com.apple.InterfaceBuilder.CocoaPlugin + {{387, 319}, {941, 593}} + + {{33, 99}, {480, 360}} + {3.40282e+38, 3.40282e+38} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{465, 510}, {147, 83}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 521 + + + + YES + + AppController + NSObject + + setBorder: + id + + + YES + + YES + theBorderTypePopup + theScrollView + theTableView + theWindow + + + YES + NSPopUpButton + NSScrollView + NSTableView + NSWindow + + + + IBUserSource + + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + ../adsfsdf.xcodeproj + 3 + + YES + + YES + NSMenuCheckmark + NSMenuMixedState + + + YES + {9, 8} + {7, 2} + + + + diff --git a/Tests/Manual/NewTableTest/Resources/spinner.gif b/Tests/Manual/NewTableTest/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/NewTableTest/index-debug.html b/Tests/Manual/NewTableTest/index-debug.html new file mode 100644 index 000000000..9c13f1632 --- /dev/null +++ b/Tests/Manual/NewTableTest/index-debug.html @@ -0,0 +1,94 @@ + + + + + + + + NewTableTest + + + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/Tests/Manual/NewTableTest/index.html b/Tests/Manual/NewTableTest/index.html new file mode 100644 index 000000000..e3cc20955 --- /dev/null +++ b/Tests/Manual/NewTableTest/index.html @@ -0,0 +1,68 @@ + + + + + + + + NewTableTest + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/Tests/Manual/NewTableTest/main.j b/Tests/Manual/NewTableTest/main.j new file mode 100755 index 000000000..af6279da3 --- /dev/null +++ b/Tests/Manual/NewTableTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * TableCibTest + * + * Created by Francisco Tolmasky on July 5, 2009. + * Copyright 2009, 280 North, Inc. All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tools/nib2cib/NSScrollView.j b/Tools/nib2cib/NSScrollView.j index f14c87f41..a39fdbf4d 100644 --- a/Tools/nib2cib/NSScrollView.j +++ b/Tools/nib2cib/NSScrollView.j @@ -41,6 +41,8 @@ _hasVerticalScroller = !!(flags & (1 << 4)); _hasHorizontalScroller = !!(flags & (1 << 5)); _autohidesScrollers = !!(flags & (1 << 9)); + + _borderType = flags & 0x03; //[aCoder decodeBytesForKey:"NSScrollAmts"]; _verticalLineScroll = 10.0; From 1fed798120087e0f22c36e5019ccb7f55da6c26a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 11 Aug 2010 23:07:05 -0400 Subject: [PATCH 196/356] Fixed: CPGraphics.j was not imported anywhere so the CPScrollView borders changes didn't work. Also minor code cleanup. --- AppKit/AppKit.j | 9 +++---- AppKit/CPGraphics.j | 50 +++++++++++++++++++------------------- AppKit/CPScrollView.j | 56 +++++++++++++++++++++---------------------- 3 files changed, 58 insertions(+), 57 deletions(-) diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 95bbe6201..9241c6398 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -36,8 +36,8 @@ @import "CPCibLoading.j" @import "CPCibOutletConnector.j" @import "CPClipView.j" -@import "CPCollectionViewItem.j" @import "CPCollectionView.j" +@import "CPCollectionViewItem.j" @import "CPColor.j" @import "CPColorPanel.j" @import "CPColorWell.j" @@ -53,6 +53,7 @@ @import "CPFont.j" @import "CPFontManager.j" @import "CPGeometry.j" +@import "CPGraphics.j" @import "CPImage.j" @import "CPImageView.j" @import "CPKeyBinding.j" @@ -66,17 +67,17 @@ @import "CPProgressIndicator.j" @import "CPRadio.j" @import "CPResponder.j" -@import "CPSearchField.j" -@import "CPScrollView.j" @import "CPScroller.j" +@import "CPScrollView.j" +@import "CPSearchField.j" @import "CPSecureTextField.j" @import "CPSegmentedControl.j" @import "CPShadow.j" @import "CPSlider.j" @import "CPSplitView.j" -@import "CPTabView.j" @import "CPTableColumn.j" @import "CPTableView.j" +@import "CPTabView.j" @import "CPText.j" @import "CPTextField.j" @import "CPToolbar.j" diff --git a/AppKit/CPGraphics.j b/AppKit/CPGraphics.j index 3044acf7e..baf1379e3 100644 --- a/AppKit/CPGraphics.j +++ b/AppKit/CPGraphics.j @@ -29,44 +29,44 @@ function CPDrawGrayBezel(aRect) { var context = [[CPGraphicsContext currentContext] graphicsPort]; - + CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]); - + var y = _CGRectGetMinY(aRect) + 0.5; - + CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y); CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y); CGContextStrokePath(context); - + CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]); CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y); CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); CGContextStrokePath(context); - + CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]); CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y); CGContextStrokePath(context); - + CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]); - + var x = _CGRectGetMaxX(aRect) - 0.5; - + CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0); CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect)); - + CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5); CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5); - + x = _CGRectGetMinX(aRect) + 0.5; - + CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect)); CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0); - + CGContextStrokePath(context); } @@ -76,38 +76,38 @@ function CPDrawGroove(aRect, drawTopBorder) CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0/255.0 alpha:1.0]); - + var y = _CGRectGetMinY(aRect) + 0.5; - + CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y); CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y); - + var x = _CGRectGetMaxX(aRect) - 1.5; - + CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0); CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0); - + y = _CGRectGetMaxY(aRect) - 1.5; - + CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y); CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y); - + x = _CGRectGetMinX(aRect) + 0.5; - + CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect)); CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect)); - + CGContextStrokePath(context); - + CGContextBeginPath(context); CGContextSetStrokeColor(context, [CPColor whiteColor]); - + var rect = _CGRectOffset(aRect, 1.0, 1.0); - + rect.size.width -= 1.0; rect.size.height -= 1.0; CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5)); - + if (drawTopBorder) { CGContextBeginPath(context); diff --git a/AppKit/CPScrollView.j b/AppKit/CPScrollView.j index b0d89c1f7..41dc25c94 100644 --- a/AppKit/CPScrollView.j +++ b/AppKit/CPScrollView.j @@ -40,21 +40,21 @@ CPClipView _contentView; CPClipView _headerClipView; CPView _cornerView; - + BOOL _hasVerticalScroller; BOOL _hasHorizontalScroller; BOOL _autohidesScrollers; - + CPScroller _verticalScroller; CPScroller _horizontalScroller; - + int _recursionCount; - + float _verticalLineScroll; float _verticalPageScroll; float _horizontalLineScroll; float _horizontalPageScroll; - + CPBorderType _borderType; } @@ -69,7 +69,7 @@ _horizontalLineScroll = 10.0; _horizontalPageScroll = 10.0; - + _borderType = CPNoBorder; _contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]]; @@ -93,13 +93,13 @@ { var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType], scrollerWidth = [CPScroller scrollerWidth]; - + if (hFlag) bounds.size.height -= scrollerWidth; - + if (vFlag) bounds.size.width -= scrollerWidth; - + return bounds.size; } @@ -110,13 +110,13 @@ heightInset = contentSize.height - bounds.size.height, frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset), scrollerWidth = [CPScroller scrollerWidth]; - + if (hFlag) frameSize.height -= scrollerWidth; - + if (vFlag) frameSize.width -= scrollerWidth; - + return frameSize; } @@ -127,14 +127,14 @@ case CPLineBorder: case CPBezelBorder: return _CGRectInset(bounds, 1.0, 1.0); - + case CPGrooveBorder: bounds = _CGRectInset(bounds, 2.0, 2.0); ++bounds.origin.y; --bounds.size.height; - + return bounds; - + case CPNoBorder: default: return bounds; @@ -339,9 +339,9 @@ { if (_borderType == borderType) return; - + _borderType = borderType; - + [self reflectScrolledClipView:_contentView]; [self setNeedsDisplay:YES]; } @@ -401,8 +401,8 @@ if (_hasHorizontalScroller && !_horizontalScroller) { var bounds = [self _insetBounds]; - - [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]]; + + [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]]; [[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])]; } @@ -464,8 +464,8 @@ if (_hasVerticalScroller && !_verticalScroller) { var bounds = [self _insetBounds]; - - [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth]+1))]]; + + [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]]; [[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))]; } @@ -755,13 +755,13 @@ - (void)drawRect:(CPRect)aRect { [super drawRect:aRect]; - - var strokeRect = [self bounds], - context = [[CPGraphicsContext currentContext] graphicsPort]; - + if (_borderType == CPNoBorder) return; - + + var strokeRect = [self bounds], + context = [[CPGraphicsContext currentContext] graphicsPort]; + CGContextSetLineWidth(context, 1); switch (_borderType) @@ -774,7 +774,7 @@ case CPBezelBorder: CPDrawGrayBezel(strokeRect); break; - + case CPGrooveBorder: CPDrawGroove(strokeRect, YES); break; @@ -944,7 +944,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView", [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey]; [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey]; - + [aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey]; } From dd9c085ae359506d7cedb31d7036aa4604f8b08c Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 22:33:14 -0500 Subject: [PATCH 197/356] Fix for new sort being unstable with a huge thanks to Shon Frazier. Reviewed by Me and Alexander Ljungberg. --- Foundation/CPArray.j | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index cb19f0edb..14931c0bc 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -1326,7 +1326,7 @@ CPEnumerationReverse = 1 << 1; */ - (void)sortUsingFunction:(Function)aFunction context:(id)aContext { - var h, i, j, k, l, m, n = [self count]; + var h, i, j, k, l, m, n = [self count], o; var A, B = []; for (h = 1; h < n; h += h) @@ -1343,7 +1343,8 @@ CPEnumerationReverse = 1 << 1; for (i = 0, k = l; k < j && j <= m + h; k++) { A = self[j]; - if (aFunction(A, B[i], aContext) == CPOrderedDescending) + o = aFunction(A, B[i], aContext); + if (o == CPOrderedDescending || o == CPOrderedSame) self[k] = B[i++]; else { From 233df3bdabd86995ef3d6a3d1744a868b0366e3f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 11 Aug 2010 23:28:06 -0400 Subject: [PATCH 198/356] Fixed: the "fix for column reordering with hidden columns" sometimes caused the table view to try to remove nonexistent data views and crash. The fix is to consider a nonexistent data view already removed and just move on. --- AppKit/CPTableView.j | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 27884902d..929f4a139 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -2277,9 +2277,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; for (; rowIndex < rowsCount; ++rowIndex) { var row = rowArray[rowIndex], - dataView = [_dataViewsForTableColumns[tableColumnUID] objectAtIndex:row]; + dataViews = _dataViewsForTableColumns[tableColumnUID]; - [_dataViewsForTableColumns[tableColumnUID] replaceObjectAtIndex:row withObject:nil]; + if (!dataViews || row >= dataViews.length) + continue; + + var dataView = [dataViews objectAtIndex:row]; + + [dataViews replaceObjectAtIndex:row withObject:nil]; [self _enqueueReusableDataView:dataView]; } @@ -3722,14 +3727,14 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", CGContextSetStrokeColor(context, _lineColor); var points = [ - _CGPointMake(0.5, 0), + _CGPointMake(0.5, 0), _CGPointMake(0.5, aRect.size.height) ]; CGContextStrokeLineSegments(context, points, 2); - + points = [ - _CGPointMake(aRect.size.width - 0.5, 0), + _CGPointMake(aRect.size.width - 0.5, 0), _CGPointMake(aRect.size.width - 0.5, aRect.size.height) ]; From 0b1b1bbe0b6f208251291ad109bc495782850d28 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 9 Aug 2010 10:15:30 -0400 Subject: [PATCH 199/356] Fix for issue #817 (Support for alignment and line break mode in NSTextField/CPTextField) --- AppKit/CPTextField.j | 7 +++++++ Tools/nib2cib/NSCell.j | 12 +----------- Tools/nib2cib/NSTextField.j | 3 ++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 489312f12..84037104f 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -1165,6 +1165,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey", CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey", CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey", + CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey", CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey", CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey"; @@ -1188,6 +1189,9 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", [self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]]; + [self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]]; + [self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]]; + [self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]]; } @@ -1209,6 +1213,9 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey", [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey]; + [aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey]; + [aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey]; + [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey]; } diff --git a/Tools/nib2cib/NSCell.j b/Tools/nib2cib/NSCell.j index f34f754af..9d3dedb73 100644 --- a/Tools/nib2cib/NSCell.j +++ b/Tools/nib2cib/NSCell.j @@ -67,19 +67,9 @@ _isContinuous = (flags & 0x00080100) ? YES : NO; _wraps = (flags & 0x00100000) ? NO : YES; _alignment = (flags2 & 0x1c000000) >> 26; + _lineBreakMode = (flags2 & 0x0E00) >> 9; _controlSize = (flags2 & 0xE0000) >> 17; - switch ((flags2 & 0x00000F00) >> 8) - { - case 0: _lineBreakMode = CPLineBreakByWordWrapping; break; - case 2: _lineBreakMode = CPLineBreakByCharWrapping; break; - case 6: _lineBreakMode = CPLineBreakByTruncatingHead; break; - case 8: _lineBreakMode = CPLineBreakByTruncatingTail; break; - case 10: _lineBreakMode = CPLineBreakByTruncatingMiddle; break; - case 4: - default: _lineBreakMode = CPLineBreakByClipping; break; - } - _objectValue = [aCoder decodeObjectForKey:@"NSContents"]; _font = [aCoder decodeObjectForKey:@"NSSupport"]; } diff --git a/Tools/nib2cib/NSTextField.j b/Tools/nib2cib/NSTextField.j index 1368ea40e..746879170 100644 --- a/Tools/nib2cib/NSTextField.j +++ b/Tools/nib2cib/NSTextField.j @@ -49,7 +49,8 @@ [self setBezelStyle:[cell bezelStyle]]; [self setDrawsBackground:[cell drawsBackground]]; - //[self setLineBreakMode:???]; + [self setLineBreakMode:[cell lineBreakMode]]; + [self setAlignment:[cell alignment]]; [self setTextFieldBackgroundColor:[cell backgroundColor]]; [self setPlaceholderString:[cell placeholderString]]; From ab5e2dd77473dfc781efedbd571e3a091a78b308 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 9 Aug 2010 09:55:51 -0400 Subject: [PATCH 200/356] Fix for issue #816 (NSTableView/CPTableView do not read selection highlight style and column resizing style) --- AppKit/CPTableView.j | 8 +++++++- Tools/nib2cib/NSTableView.j | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 929f4a139..3aace2d55 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -3490,11 +3490,13 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", CPTableViewTableColumnsKey = @"CPTableViewTableColumnsKey", CPTableViewRowHeightKey = @"CPTableViewRowHeightKey", CPTableViewIntercellSpacingKey = @"CPTableViewIntercellSpacingKey", + CPTableViewSelectionHighlightStyleKey = @"CPTableViewSelectionHighlightStyleKey", CPTableViewMultipleSelectionKey = @"CPTableViewMultipleSelectionKey", CPTableViewEmptySelectionKey = @"CPTableViewEmptySelectionKey", CPTableViewColumnReorderingKey = @"CPTableViewColumnReorderingKey", CPTableViewColumnResizingKey = @"CPTableViewColumnResizingKey", CPTableViewColumnSelectionKey = @"CPTableViewColumnSelectionKey", + CPTableViewColumnAutoresizingStyleKey = @"CPTableViewColumnAutoresizingStyleKey", CPTableViewGridColorKey = @"CPTableViewGridColorKey", CPTableViewGridStyleMaskKey = @"CPTableViewGridStyleMaskKey", CPTableViewUsesAlternatingBackgroundKey = @"CPTableViewUsesAlternatingBackgroundKey", @@ -3518,7 +3520,8 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _allowsColumnSelection = [aCoder decodeBoolForKey:CPTableViewColumnSelectionKey]; //Setting Display Attributes - _selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular; + _selectionHighlightStyle = [aCoder decodeIntForKey:CPTableViewSelectionHighlightStyleKey]; + _columnAutoResizingStyle = [aCoder decodeIntForKey:CPTableViewColumnAutoresizingStyleKey]; _tableColumns = [aCoder decodeObjectForKey:CPTableViewTableColumnsKey] || []; [_tableColumns makeObjectsPerformSelector:@selector(setTableView:) withObject:self]; @@ -3560,6 +3563,9 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", [aCoder encodeFloat:_rowHeight forKey:CPTableViewRowHeightKey]; [aCoder encodeSize:_intercellSpacing forKey:CPTableViewIntercellSpacingKey]; + [aCoder encodeInt:_selectionHighlightStyle forKey:CPTableViewSelectionHighlightStyleKey]; + [aCoder encodeInt:_columnAutoResizingStyle forKey:CPTableViewColumnAutoresizingStyleKey]; + [aCoder encodeBool:_allowsMultipleSelection forKey:CPTableViewMultipleSelectionKey]; [aCoder encodeBool:_allowsEmptySelection forKey:CPTableViewEmptySelectionKey]; [aCoder encodeBool:_allowsColumnReordering forKey:CPTableViewColumnReorderingKey]; diff --git a/Tools/nib2cib/NSTableView.j b/Tools/nib2cib/NSTableView.j index 49540479e..1b734fa5d 100644 --- a/Tools/nib2cib/NSTableView.j +++ b/Tools/nib2cib/NSTableView.j @@ -61,6 +61,9 @@ _usesAlternatingRowBackgroundColors = (flags & 0x00800000) ? YES : NO; _alternatingRowBackgroundColors =[[CPColor whiteColor], [CPColor colorWithHexString:@"e4e7ff"]]; + _selectionHighlightStyle = [aCoder decodeIntForKey:@"NSTableViewSelectionHighlightStyle"] || CPTableViewSelectionHighlightStyleRegular; + _columnAutoResizingStyle = [aCoder decodeIntForKey:@"NSColumnAutoresizingStyle"]; + _allowsMultipleSelection = (flags & 0x08000000) ? YES : NO; _allowsEmptySelection = (flags & 0x10000000) ? YES : NO; _allowsColumnSelection = (flags & 0x04000000) ? YES : NO; From ba33bb56d0a776d689478ae07ad76a2a8cc5c742 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 12 Aug 2010 00:08:43 -0400 Subject: [PATCH 201/356] Moved the visual table test for borders into the TableTest folder. --- .../BorderTableTest}/AppController.j | 0 .../BorderTableTest}/Info.plist | 0 .../BorderTableTest}/Resources/MainMenu.cib | 0 .../BorderTableTest}/Resources/MainMenu.xib | 0 .../BorderTableTest}/Resources/spinner.gif | Bin .../BorderTableTest}/index-debug.html | 0 .../BorderTableTest}/index.html | 0 .../BorderTableTest}/main.j | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/AppController.j (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/Info.plist (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/Resources/MainMenu.cib (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/Resources/MainMenu.xib (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/Resources/spinner.gif (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/index-debug.html (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/index.html (100%) rename Tests/Manual/{NewTableTest => TableTest/BorderTableTest}/main.j (100%) diff --git a/Tests/Manual/NewTableTest/AppController.j b/Tests/Manual/TableTest/BorderTableTest/AppController.j similarity index 100% rename from Tests/Manual/NewTableTest/AppController.j rename to Tests/Manual/TableTest/BorderTableTest/AppController.j diff --git a/Tests/Manual/NewTableTest/Info.plist b/Tests/Manual/TableTest/BorderTableTest/Info.plist similarity index 100% rename from Tests/Manual/NewTableTest/Info.plist rename to Tests/Manual/TableTest/BorderTableTest/Info.plist diff --git a/Tests/Manual/NewTableTest/Resources/MainMenu.cib b/Tests/Manual/TableTest/BorderTableTest/Resources/MainMenu.cib similarity index 100% rename from Tests/Manual/NewTableTest/Resources/MainMenu.cib rename to Tests/Manual/TableTest/BorderTableTest/Resources/MainMenu.cib diff --git a/Tests/Manual/NewTableTest/Resources/MainMenu.xib b/Tests/Manual/TableTest/BorderTableTest/Resources/MainMenu.xib similarity index 100% rename from Tests/Manual/NewTableTest/Resources/MainMenu.xib rename to Tests/Manual/TableTest/BorderTableTest/Resources/MainMenu.xib diff --git a/Tests/Manual/NewTableTest/Resources/spinner.gif b/Tests/Manual/TableTest/BorderTableTest/Resources/spinner.gif similarity index 100% rename from Tests/Manual/NewTableTest/Resources/spinner.gif rename to Tests/Manual/TableTest/BorderTableTest/Resources/spinner.gif diff --git a/Tests/Manual/NewTableTest/index-debug.html b/Tests/Manual/TableTest/BorderTableTest/index-debug.html similarity index 100% rename from Tests/Manual/NewTableTest/index-debug.html rename to Tests/Manual/TableTest/BorderTableTest/index-debug.html diff --git a/Tests/Manual/NewTableTest/index.html b/Tests/Manual/TableTest/BorderTableTest/index.html similarity index 100% rename from Tests/Manual/NewTableTest/index.html rename to Tests/Manual/TableTest/BorderTableTest/index.html diff --git a/Tests/Manual/NewTableTest/main.j b/Tests/Manual/TableTest/BorderTableTest/main.j similarity index 100% rename from Tests/Manual/NewTableTest/main.j rename to Tests/Manual/TableTest/BorderTableTest/main.j From 1e6f6879fff9b50e4908dee9b6f76a59b40aad4e Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 11 Aug 2010 23:17:38 -0500 Subject: [PATCH 202/356] Run CPArrayPerformanceTest with jake test. --- .../{CPArrayPerformance.j => CPArrayPerformanceTest.j} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Tests/Foundation/{CPArrayPerformance.j => CPArrayPerformanceTest.j} (96%) diff --git a/Tests/Foundation/CPArrayPerformance.j b/Tests/Foundation/CPArrayPerformanceTest.j similarity index 96% rename from Tests/Foundation/CPArrayPerformance.j rename to Tests/Foundation/CPArrayPerformanceTest.j index a41c16dce..f350e7ff5 100644 --- a/Tests/Foundation/CPArrayPerformance.j +++ b/Tests/Foundation/CPArrayPerformanceTest.j @@ -3,7 +3,7 @@ @import @import -@implementation CPArrayPerformance : OJTestCase +@implementation CPArrayPerformanceTest : OJTestCase - (void)testSortUsingDescriptorsSpeed { From 44fb4a9b83742b1625d40be7bd007081ee1c0b83 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Wed, 11 Aug 2010 22:39:57 -0400 Subject: [PATCH 203/356] -setIntercellSpacing should update the header as well as the table, per Cocoa (and common sense) --- AppKit/CPTableView.j | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 3aace2d55..1b35d6c75 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -539,6 +539,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self _recalculateTableColumnRanges]; [self setNeedsLayout]; + [_headerView setNeedsDisplay:YES]; + [_headerView setNeedsLayout]; } - (void)setThemeState:(int)astae From da0af131420f72068ded0b89e5c05735de53e0f8 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 12 Aug 2010 13:11:41 -0500 Subject: [PATCH 204/356] Added basic suppport for CPOutlineView in the nib2cib tool Conflicts: AppKit/CPOutlineView.j --- AppKit/CPOutlineView.j | 50 +++++++++++++++++++++++++++ Tools/nib2cib/NSAppKit.j | 1 + Tools/nib2cib/NSOutlineView.j | 65 +++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 Tools/nib2cib/NSOutlineView.j diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 414249a0b..42752caff 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -1275,6 +1275,56 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt @end + +var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey", + CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey", + CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey", + CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey"; + +@implementation CPOutlineView (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + self = [super initWithCoder:aCoder]; + + if (self) + { + // The root item has weight "0", thus represents the weight solely of its descendants. + _rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 }; + + _itemsForRows = []; + _itemInfosForItems = { }; + _disclosureControlsForRows = []; + + [self setIndentationMarkerFollowsDataView:YES]; + [self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]]; + + _outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey]; + _indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey]; + + _outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey]; + _outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey]; + + [super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]]; + } + + return self; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [super encodeWithCoder:aCoder]; + + [aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey]; + [aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey]; + + [aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey]; + [aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey]; +} + +@end + + var colorForDisclosureTriangle = function(isSelected, isHighlighted) { return isSelected ? (isHighlighted diff --git a/Tools/nib2cib/NSAppKit.j b/Tools/nib2cib/NSAppKit.j index 96a3a52b8..2348f1408 100644 --- a/Tools/nib2cib/NSAppKit.j +++ b/Tools/nib2cib/NSAppKit.j @@ -41,6 +41,7 @@ @import "NSMenu.j" @import "NSMenuItem.j" @import "NSNibConnector.j" +@import "NSOutlineView.j" @import "NSPopUpButton.j" @import "NSResponder.j" @import "NSScrollView.j" diff --git a/Tools/nib2cib/NSOutlineView.j b/Tools/nib2cib/NSOutlineView.j new file mode 100644 index 000000000..6cc600273 --- /dev/null +++ b/Tools/nib2cib/NSOutlineView.j @@ -0,0 +1,65 @@ +/* + * NSOutlineView.j + * nib2cib + * + * Created by Andreas Falk. + * Copyright 2009, Andreas Falk. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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 + + +@implementation CPOutlineView (NSCoding) + +- (id)NS_initWithCoder:(CPCoder)aCoder +{ + self = [super NS_initWithCoder:aCoder]; + + if (self) + { + if([aCoder containsValueForKey:"NSOutlineViewOutlineTableColumnKey"]) + _outlineTableColumn = [aCoder decodeObjectForKey:@"NSOutlineViewOutlineTableColumnKey"]; + else + _outlineTableColumn = [[self tableColumns] objectAtIndex:0]; + + _indentationPerLevel = [aCoder decodeFloatForKey:@"NSOutlineViewIndentationPerLevelKey"]; + + _outlineViewDataSource = [aCoder decodeObjectForKey:@"NSDataSource"]; + _outlineViewDelegate = [aCoder decodeObjectForKey:@"NSDelegate"]; + } + + return self; +} + +@end + + +@implementation NSOutlineView : CPOutlineView +{ +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + return [self NS_initWithCoder:aCoder]; +} + +- (Class)classForKeyedArchiver +{ + return [CPOutlineView class]; +} + +@end From 14fb7695827f21e53348ccd92c2f3c239c0a2967 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 12 Aug 2010 13:29:17 -0500 Subject: [PATCH 205/356] Removed ambiguity in CPDictionary keys type. Closes #700 --- Foundation/CPDictionary.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index 4fd2d46d8..da628aba6 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -425,7 +425,7 @@ @param aKey the key for the object's entry @return the object for the entry */ -- (id)objectForKey:(CPString)aKey +- (id)objectForKey:(id)aKey { var object = _buckets[aKey]; From 22c481ff274ded47fbae6a0dd56f6be17ed54eba Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 12 Aug 2010 14:18:45 -0500 Subject: [PATCH 206/356] Implemented allKeysForObject: in CPDictionary with tests. --- Foundation/CPDictionary.j | 29 +++++++++++++++++++++++++++++ Tests/Foundation/CPDictionaryTest.j | 21 +++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index da628aba6..acb4cca1e 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -337,6 +337,35 @@ return values; } +/*! + Returns a new array containing the keys corresponding to all occurrences of a given object in the receiver. + @param anObject The value to look for in the receiver. + @return A new array containing the keys corresponding to all occurrences of anObject in the receiver. If no object matching anObject is found, returns an empty array. + + Each object in the receiver is sent an isEqual: message to determine if its equal to anObject. + If the check for isEqual fails a check is made to see if the two objects are the same object. This provides compatability for JSObjects. +*/ +- (CPArray)allKeysForObject:(id)anObject +{ + var count = _keys.length, + index = 0, + matchingKeys = [], + thisKey = nil, + thisValue = nil; + + for (; index < count; ++index) + { + thisKey = _keys[index], + thisValue = _buckets[thisKey]; + if (thisValue.isa && anObject && anObject.isa && [thisValue respondsToSelector:@selector(isEqual:)] && [thisValue isEqual:anObject]) + matchingKeys.push(thisKey); + else if (thisValue === anObject) + matchingKeys.push(thisKey); + } + + return matchingKeys; +} + /*! Returns an enumerator that enumerates over all the dictionary's keys. */ diff --git a/Tests/Foundation/CPDictionaryTest.j b/Tests/Foundation/CPDictionaryTest.j index d520f7359..023177beb 100644 --- a/Tests/Foundation/CPDictionaryTest.j +++ b/Tests/Foundation/CPDictionaryTest.j @@ -17,7 +17,7 @@ } } - string_dict = [[CPDictionary alloc] initWithObjects:[@"1", @"2"] forKeys:[@"key1", @"key2"]]; + string_dict = [[CPDictionary alloc] initWithObjects:[@"1", @"2", @"This is a String", @"This is a String"] forKeys:[@"key1", @"key2", @"key3", @"key4"]]; json_dict = [CPDictionary dictionaryWithJSObject:json recursively:YES]; } @@ -90,19 +90,19 @@ - (void)testCount { - [self assert:[string_dict count] equals:2]; + [self assert:[string_dict count] equals:4]; [self assert:[json_dict count] equals:3]; } - (void)testAllKeys { - [self assert:[string_dict allKeys] equals:[@"key2", @"key1"]]; + [self assert:[string_dict allKeys] equals:[@"key4", @"key3", @"key2", @"key1"]]; [self assert:[json_dict allKeys] equals:[@"key1", @"key2", @"key3"]]; } - (void)testAllValues { - [self assert:[string_dict allValues] equals:[@"1", @"2"]]; + [self assert:[string_dict allValues] equals:[@"1", @"2", @"This is a String", @"This is a String"]]; // Had to get object from key to get test passing [self assert:[json_dict allValues] equals:[[json_dict objectForKey:@"key3"], @"This is a string", ['1', '2', '3']]]; } @@ -113,6 +113,11 @@ [self assert:[json_dict objectForKey:@"key1"] equals:['1', '2', '3']]; } +- (void)testAllKeysForObject +{ + [self assert:[string_dict allKeysForObject:@"This is a String"] equals:[@"key4", @"key3"]]; +} + - (void)testKeyEnumerator { var dict = [[CPDictionary alloc] init]; @@ -156,7 +161,7 @@ { [string_dict removeObjectForKey:@"key1"]; [json_dict removeObjectForKey:@"key1"]; - [self assert:[string_dict count] equals:1]; + [self assert:[string_dict count] equals:3]; [self assert:[json_dict count] equals:2]; } @@ -164,7 +169,7 @@ { [string_dict removeObjectsForKeys:[@"key1"]]; [json_dict removeObjectsForKeys:[@"key1", @"key2"]]; - [self assert:[string_dict count] equals:1]; + [self assert:[string_dict count] equals:3]; [self assert:[json_dict count] equals:1]; } @@ -178,10 +183,10 @@ - (void)testAddEntriesFromDictionary { - var dict = [[CPDictionary alloc] initWithObjects:[@"1", @"2"] forKeys:[@"key4", @"key5"]]; + var dict = [[CPDictionary alloc] initWithObjects:[@"1", @"2"] forKeys:[@"key5", @"key6"]]; [string_dict addEntriesFromDictionary:dict] [json_dict addEntriesFromDictionary:dict] - [self assert:[string_dict count] equals:4]; + [self assert:[string_dict count] equals:6]; [self assert:[json_dict count] equals:5]; } From 23e9fd927cf1814e7e03039b6f11f9a27b7a0f00 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Wed, 24 Feb 2010 01:19:52 +0100 Subject: [PATCH 207/356] CPBox: Made CPBezelType the default type instead of none. Slighly grayed stroke color for bezel type & fillColor for all types to better match cocoa Fix contentView autoresizingMask --- AppKit/CPBox.j | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/AppKit/CPBox.j b/AppKit/CPBox.j index 05500b550..bdff6d9c1 100644 --- a/AppKit/CPBox.j +++ b/AppKit/CPBox.j @@ -61,15 +61,16 @@ CPGrooveBorder = 3; self = [super initWithFrame:frameRect]; if (self) - { - _fillColor = [CPColor clearColor]; + { + _borderType = CPBezelBorder; + _fillColor = [CPColor colorWithWhite:0.75 alpha:0.1]; _borderColor = [CPColor blackColor]; _borderWidth = 1.0; _contentMargin = CGSizeMake(0.0, 0.0); _contentView = [[CPView alloc] initWithFrame:[self bounds]]; - + [_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [self addSubview:_contentView]; } @@ -161,6 +162,7 @@ CPGrooveBorder = 3; return; [aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)]; + [aView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [self replaceSubview:_contentView with:aView]; _contentView = aView; @@ -213,16 +215,17 @@ CPGrooveBorder = 3; bounds.size.height - _borderWidth); CGContextSetFillColor(aContext, [self fillColor]); - CGContextSetStrokeColor(aContext, [self borderColor]); CGContextSetLineWidth(aContext, _borderWidth); switch(_borderType) { - case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES); + case CPLineBorder: CGContextSetStrokeColor(aContext, [self borderColor]); + CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES); CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES); break; - case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES); + case CPBezelBorder: CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:0 alpha:0.42]); + CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES); CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]); CGContextBeginPath(aContext); CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y); From ee9da8e31ecdd919af6ed5a7dcfbd2958441c28e Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 12 Aug 2010 16:03:24 -0500 Subject: [PATCH 208/356] Only call drawRect: is the view is visible. --- AppKit/CPView.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 8066cafe5..c153dda8a 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1846,6 +1846,9 @@ setBoundsOrigin: - (void)displayRectIgnoringOpacity:(CGRect)aRect inContext:(CPGraphicsContext)aGraphicsContext { + if ([self isHidden]) + return; + #if PLATFORM(DOM) [self lockFocus]; From 1a9670ae9cf755b8e2cb6a6950dfd8c5e197d413 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Mon, 17 May 2010 12:32:56 +0200 Subject: [PATCH 209/356] made sure CPViewController calls viewDidLoad if it's view property is set directly --- AppKit/CPViewController.j | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AppKit/CPViewController.j b/AppKit/CPViewController.j index 3fffe261d..ab8c3a22e 100644 --- a/AppKit/CPViewController.j +++ b/AppKit/CPViewController.j @@ -162,8 +162,6 @@ var CPViewControllerCachedCibs; if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) [cibOwner viewControllerDidLoadCib:self]; - - [self viewDidLoad]; } return _view; @@ -189,7 +187,13 @@ var CPViewControllerCachedCibs; */ - (void)setView:(CPView)aView { + var viewWasLoaded = !_view; + _view = aView; + + // Make sure the viewDidLoad method is called if the view is set directly + if (viewWasLoaded) + [self viewDidLoad]; } @end From c8515225366bdf8daf91a8799854fd04ea57b771 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 12 Aug 2010 23:12:14 -0400 Subject: [PATCH 210/356] Fixed: if the CPWebView iframe was destroyed before its HTML loader timer fired, an error would occur. --- AppKit/CPWebView.j | 91 +++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/AppKit/CPWebView.j b/AppKit/CPWebView.j index bf36a7773..dca2637ab 100644 --- a/AppKit/CPWebView.j +++ b/AppKit/CPWebView.j @@ -50,23 +50,23 @@ CPWebViewScrollNative = 2; { CPScrollView _scrollView; CPView _frameView; - + IFrame _iframe; CPString _mainFrameURL; CPArray _backwardStack; CPArray _forwardStack; - + BOOL _ignoreLoadStart; BOOL _ignoreLoadEnd; - + id _downloadDelegate; id _frameLoadDelegate; id _policyDelegate; id _resourceLoadDelegate; id _UIDelegate; - + CPWebScriptObject _wso; - + CPString _url; CPString _html; @@ -95,10 +95,10 @@ CPWebViewScrollNative = 2; _backwardStack = []; _forwardStack = []; _scrollMode = CPWebViewScrollNative; - + [self _initDOMWithFrame:aFrame]; } - + return self; } @@ -106,52 +106,52 @@ CPWebViewScrollNative = 2; { _ignoreLoadStart = YES; _ignoreLoadEnd = YES; - + _iframe = document.createElement("iframe"); _iframe.name = "iframe_" + Math.floor(Math.random()*10000); _iframe.style.width = "100%"; _iframe.style.height = "100%"; _iframe.style.borderWidth = "0px"; _iframe.frameBorder = "0"; - + [self setDrawsBackground:YES]; - + _loadCallback = function() { // HACK: this block handles the case where we don't know about loads initiated by the user clicking a link if (!_ignoreLoadStart) { // post the start load notification [self _startedLoading]; - + if (_mainFrameURL) [_backwardStack addObject:_mainFrameURL]; - + // FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions. _mainFrameURL = _iframe.src; _mainFrameURL = _iframe.src; - + // clear the forward [_forwardStack removeAllObjects]; } else _ignoreLoadStart = NO; - + if (!_ignoreLoadEnd) { [self _finishedLoading]; } else _ignoreLoadEnd = NO; - + [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; } - + if (_iframe.addEventListener) _iframe.addEventListener("load", _loadCallback, false); else if (_iframe.attachEvent) _iframe.attachEvent("onload", _loadCallback); - - + + _frameView = [[CPView alloc] initWithFrame:[self bounds]]; [_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; @@ -159,9 +159,9 @@ CPWebViewScrollNative = 2; [_scrollView setAutohidesScrollers:YES]; [_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_scrollView setDocumentView:_frameView]; - + _frameView._DOMElement.appendChild(_iframe); - + [self _setScrollMode:_scrollMode]; [self addSubview:_scrollView]; @@ -169,7 +169,7 @@ CPWebViewScrollNative = 2; - (void)setFrameSize:(CPSize)aSize -{ +{ [super setFrameSize:aSize]; [self _resizeWebFrame]; } @@ -211,7 +211,7 @@ CPWebViewScrollNative = 2; { var visibleRect = [_frameView visibleRect]; [_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))]; - + // try to get the document size so we can correctly set the frame var win = null; try { win = [self DOMWindow]; } catch (e) {} @@ -229,7 +229,7 @@ CPWebViewScrollNative = 2; else { CPLog.warn("using default size 800*1600"); - + [_frameView setFrameSize:CGSizeMake(800, 1600)]; } @@ -242,7 +242,7 @@ CPWebViewScrollNative = 2; { if (_scrollMode == aScrollMode) return; - + [self _setScrollMode:aScrollMode]; } @@ -252,7 +252,7 @@ CPWebViewScrollNative = 2; _scrollMode = CPWebViewScrollNative; else _scrollMode = aScrollMode; - + _ignoreLoadStart = YES; _ignoreLoadEnd = YES; @@ -263,16 +263,16 @@ CPWebViewScrollNative = 2; { [_scrollView setHasHorizontalScroller:YES]; [_scrollView setHasVerticalScroller:YES]; - + _iframe.setAttribute("scrolling", "no"); } else { [_scrollView setHasHorizontalScroller:NO]; [_scrollView setHasVerticalScroller:NO]; - + _iframe.setAttribute("scrolling", "auto"); - + [_frameView setFrameSize:[_scrollView bounds].size]; } @@ -293,13 +293,13 @@ CPWebViewScrollNative = 2; [_frameView setFrameSize:[_scrollView contentSize]]; [self _startedLoading]; - + _ignoreLoadStart = YES; _ignoreLoadEnd = NO; - + _url = null; _html = aString; - + [self _load]; } @@ -308,13 +308,13 @@ CPWebViewScrollNative = 2; [self _setScrollMode:CPWebViewScrollNative]; [self _startedLoading]; - + _ignoreLoadStart = YES; _ignoreLoadEnd = NO; - + _url = _mainFrameURL; _html = null; - + [self _load]; } @@ -335,12 +335,13 @@ CPWebViewScrollNative = 2; _loadHTMLStringTimer = nil; } - // need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document + // need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document _loadHTMLStringTimer = window.setTimeout(function() { var win = [self DOMWindow]; - - win.document.write(_html); + + if (win) + win.document.write(_html); window.setTimeout(_loadCallback, 1); }, 0); @@ -372,7 +373,7 @@ CPWebViewScrollNative = 2; } - (void)setMainFrameURL:(CPString)URLString -{ +{ if (_mainFrameURL) [_backwardStack addObject:_mainFrameURL]; _mainFrameURL = URLString; @@ -389,9 +390,9 @@ CPWebViewScrollNative = 2; [_forwardStack addObject:_mainFrameURL]; _mainFrameURL = [_backwardStack lastObject]; [_backwardStack removeLastObject]; - + [self _loadMainFrameURL]; - + return YES; } return NO; @@ -405,9 +406,9 @@ CPWebViewScrollNative = 2; [_backwardStack addObject:_mainFrameURL]; _mainFrameURL = [_forwardStack lastObject]; [_forwardStack removeLastObject]; - + [self _loadMainFrameURL]; - + return YES; } return NO; @@ -630,7 +631,7 @@ CPWebViewScrollNative = 2; - (id)initWithCoder:(CPCoder)aCoder { self = [super initWithCoder:aCoder]; - + if (self) { // FIXME: encode/decode these? @@ -638,14 +639,14 @@ CPWebViewScrollNative = 2; _backwardStack = []; _forwardStack = []; _scrollMode = CPWebViewScrollNative; - + #if PLATFORM(DOM) [self _initDOMWithFrame:[self frame]]; #endif [self setBackgroundColor:[CPColor whiteColor]]; } - + return self; } From 494f39dd86cd1598cc3f2577aa7b419633f06d5e Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 12 Aug 2010 23:37:53 -0400 Subject: [PATCH 211/356] Closes #752. Removed some debug code which snuck in with the merge of fix-752-CPValueTransformerNameBindingOption. --- AppKit/CPKeyValueBinding.j | 3 --- 1 file changed, 3 deletions(-) diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 89fd10c13..1ea547e5d 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -182,9 +182,6 @@ var CPBindingOperationAnd = 0, if (valueTransformerName) { - if (valueTransformerName === @"ESIsEmptyIndexSetValueTransformer") - debugger; - valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName]; if (!valueTransformer) From 0683b46239be4d1c904483c407f53d9c8dc9cc84 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:18:25 -0400 Subject: [PATCH 212/356] Since issue #795 has not been decided on yet, make CPArrayControllerTest pass without those changes at this time. --- Tests/AppKit/CPArrayControllerTest.j | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index 2029c51ed..abdb8719c 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -12,7 +12,8 @@ [_contentArray addObject:[Person personWithName:@"Ross" age:30]]; [_contentArray addObject:[Person personWithName:@"Tom" age:15]]; - _arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; + // Copy the array since we'll reuse the original array later. Also see issue #795. + _arrayController = [[CPArrayController alloc] initWithContent:[[self contentArray] copy]]; } - (void)testInitWithContent @@ -26,7 +27,8 @@ otherContent = [@"5", @"6"]; [[self arrayController] setContent:otherContent]; - [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; + // This has not been decided on yet. See Issue #795. + // [self assertFalse:otherContent === [[self arrayController] contentArray] message:@"array controller should copy it's content"]; [self assert:otherContent equals:[[self arrayController] contentArray]]; [self assert:[_CPObservableArray class] equals:[[[self arrayController] arrangedObjects] class]]; } From bcb22c7e46853599eb37e290f6597cc45e49b239 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:28:25 -0400 Subject: [PATCH 213/356] Remove debug output from CPArrayControllerTest. --- Tests/AppKit/CPArrayControllerTest.j | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/AppKit/CPArrayControllerTest.j b/Tests/AppKit/CPArrayControllerTest.j index abdb8719c..d311ccd56 100644 --- a/Tests/AppKit/CPArrayControllerTest.j +++ b/Tests/AppKit/CPArrayControllerTest.j @@ -94,7 +94,6 @@ arrayController = [[CPArrayController alloc] initWithContent:[self contentArray]]; [arrayController setPreservesSelection:YES]; - print([self contentArray]); // Remove from middle var selectionIndexes = [CPIndexSet indexSetWithIndex:1]; From 4c0057e66af505d10dc5c4b8263f3235e2f96d31 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 13 Aug 2010 14:37:26 -0400 Subject: [PATCH 214/356] Undoing this change since it is no longer necessary due to an alternative solution implemented by Ross Boucher. Revert "Merge commit 'c17a3533ecae63d479b285b23ac3a490ebe8bd3c'" This reverts commit 039f2ce449fe4767ffb5991b76732c7db5794fc4, reversing changes made to 494f39dd86cd1598cc3f2577aa7b419633f06d5e. --- AppKit/CPArrayController.j | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/AppKit/CPArrayController.j b/AppKit/CPArrayController.j index 6843f79c6..b04f4e0f9 100644 --- a/AppKit/CPArrayController.j +++ b/AppKit/CPArrayController.j @@ -407,23 +407,16 @@ if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object]) { - var position; - if ([_sortDescriptors count] > 0) - position = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; - else - { - [_arrangedObjects addObject:object]; - position = [_arrangedObjects count] - 1; - } + var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors]; if (_selectsInsertedObjects) { - [self setSelectionIndex:position]; + [self setSelectionIndex:pos]; } else { [self willChangeValueForKey:@"selectionIndexes"]; - [_selectionIndexes shiftIndexesStartingAtIndex:position by:1]; + [_selectionIndexes shiftIndexesStartingAtIndex:pos by:1]; [self didChangeValueForKey:@"selectionIndexes"]; } } From 4eaf560ee62fe83ee73907aca7e231ed7cabfad3 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Fri, 13 Aug 2010 15:34:28 -0700 Subject: [PATCH 215/356] Fixes two bugs in compareObjectsUsingDescriptors causing test to fail: extra semi-colon after while() and uninitized "result" variable. The former masked the latter when a single sort descriptor was used. --- Foundation/CPArray.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 14931c0bc..6ee14b6af 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -1378,12 +1378,12 @@ var selectorCompare = function selectorCompare(object1, object2, selector) // sort using sort descriptors var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors) { - var result, + var result = CPOrderedSame, i = 0, n = [descriptors count]; - while (i < n && result == CPOrderedSame); - result = [descriptors[i++] compareObject:lhs withObject:rhs]; + while (i < n && result === CPOrderedSame) + result = [descriptors[i++] compareObject:lhs withObject:rhs]; return result; } From 6ce45d32dac642923c8d1b6f346ba01ad1bcb1dc Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Fri, 13 Aug 2010 15:40:33 -0700 Subject: [PATCH 216/356] Add comparison test for native sorting. --- Tests/Foundation/CPArrayPerformanceTest.j | 79 +++++++++++++++++------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/Tests/Foundation/CPArrayPerformanceTest.j b/Tests/Foundation/CPArrayPerformanceTest.j index f350e7ff5..e4d014aa5 100644 --- a/Tests/Foundation/CPArrayPerformanceTest.j +++ b/Tests/Foundation/CPArrayPerformanceTest.j @@ -3,20 +3,14 @@ @import @import +var ELEMENTS = 100, + REPEATS = 10; + @implementation CPArrayPerformanceTest : OJTestCase - (void)testSortUsingDescriptorsSpeed { - - var ELEMENTS = 1000, - REPEATS = 10, - array = []; - for (var i=0; i