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" 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]; 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"]]; } 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 diff --git a/AppKit/CPTableColumn.j b/AppKit/CPTableColumn.j index 59b44e97e..17b731d18 100644 --- a/AppKit/CPTableColumn.j +++ b/AppKit/CPTableColumn.j @@ -459,9 +459,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", - CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey", - CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey"; - CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey"; + CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey", + CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey", + CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey"; @implementation CPTableColumn (CPCoding) @@ -483,7 +483,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]; } @@ -503,7 +504,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/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 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, 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), diff --git a/Foundation/CPKeyValueCoding.j b/Foundation/CPKeyValueCoding.j index 104a6931f..1449899e4 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; } @@ -156,7 +151,7 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; - (id)valueForKey:(CPString)aKey { var theClass = [self class], - selector = [theClass _accessorForKey:aKey]; + selector = _accessorForKey(theClass, aKey); if (selector) return objj_msgSend(self, selector); @@ -264,6 +259,41 @@ CPUnknownUserInfoKey = @"CPUnknownUserInfoKey"; @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 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]; } } 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"]; 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"]; } diff --git a/Tools/nib2cib/NSTextField.j b/Tools/nib2cib/NSTextField.j index 8b1b1eeda..d9d935085 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]; @@ -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] + ")"); }