diff --git a/AppKit/CPAccordionView.j b/AppKit/CPAccordionView.j index b3294149b..18e6c6e5f 100644 --- a/AppKit/CPAccordionView.j +++ b/AppKit/CPAccordionView.j @@ -312,7 +312,7 @@ _contentView = aView; - [_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL]; + [_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL]; [self addSubview:_contentView]; diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index d85627b4e..10891a2b9 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -701,7 +701,7 @@ CPRunContinuesResponse = -1002; - (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender { var target = [self targetForAction:anAction to:aTarget from:aSender]; - + if (!target) return NO; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 1670ad852..c3f1fe0db 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -2369,9 +2369,21 @@ var keyViewComparator = function(a, b, context) */ - (CPUndoManager)undoManager { + // If we've ever created an undo manager, return it. + if (_undoManager) + return _undoManager; + + // If not, check to see if the document has one. + var documentUndoManager = [[_windowController document] undoManager]; + + if (documentUndoManager) + return documentUndoManager; + + // If not, check to see if the delegate has one. if (_delegateRespondsToWindowWillReturnUndoManagerSelector) return [_delegate windowWillReturnUndoManager:self]; - + + // If not, create one. if (!_undoManager) _undoManager = [[CPUndoManager alloc] init]; diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index a2c3fc2d5..459a7940c 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -373,19 +373,28 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, else if (!isBefore) [observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context]; } - + var dependentKeysMap = _nativeClass[DependentKeysKey]; if (!dependentKeysMap) return; - var keysComposedOfKey = [dependentKeysMap[aKey] allObjects]; - - if (!keysComposedOfKey) + var dependentKeyPaths = [dependentKeysMap[aKey] allObjects]; + + if (!dependentKeyPaths) return; - for (var i=0, count=keysComposedOfKey.length; i"; + return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">"; } // Sending Messages @@ -322,6 +323,7 @@ CPLog(@"Got some class: %@", inst); Used for forwarding of messages to other objects. @ignore */ +// FIXME: This should be moved to the runtime? - (void)forward:(SEL)aSelector :(marg_list)args { var signature = [self methodSignatureForSelector:aSelector]; diff --git a/Foundation/CPProxy.j b/Foundation/CPProxy.j new file mode 100644 index 000000000..c7db74969 --- /dev/null +++ b/Foundation/CPProxy.j @@ -0,0 +1,161 @@ +/* + * CPProxy.j + * Foundation + * + * Created by Francisco Tolmasky. + * Copyright 2009, 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 "CPException.j" +@import "CPInvocation.j" +@import "CPString.j" + + +@implementation CPProxy +{ +} + ++ (void)load +{ +} + ++ (void)initialize +{ +} + ++ (Class)class +{ + return self; +} + ++ (id)alloc +{ + return class_createInstance(self); +} + ++ (BOOL)respondsToSelector:(SEL)selector +{ + return !!class_getInstanceMethod(isa, aSelector); +} + +- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector +{ + [CPException raise:CPInvalidArgumentException + reason:@"-methodSignatureForSelector: called on abstract CPProxy class."]; +} + +- (void)forwardInvocation:(CPInvocation)anInvocation +{ + [CPException raise:CPInvalidArgumentException + reason:@"-methodSignatureForSelector: called on abstract CPProxy class."]; +} + +// FIXME: This should be moved to the runtime? +- (void)forward:(SEL)aSelector :(marg_list)args +{ + [CPObject methodForSelector:_cmd](self, _cmd, aSelector, args); +} + +- (unsigned)hash +{ + return [self UID]; +} + +- (unsigned)UID +{ + if (typeof self.__address === "undefined") + self.__address = _objj_generateObjectHash(); + + return __address; +} + +- (BOOL)isEqual:(id)anObject +{ + return self === object; +} + +- (id)self +{ + return self; +} + +- (Class)class +{ + return isa; +} + +- (Class)superclass +{ + return class_getSuperclass(isa); +} + +- (id)performSelector:(SEL)aSelector +{ + return objj_msgSend(self, aSelector); +} + +- (id)performSelector:(SEL)aSelector withObject:(id)anObject +{ + return objj_msgSend(self, aSelector, anObject); +} + +- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject +{ + return objj_msgSend(self, aSelector, anObject, anotherObject); +} + +- (BOOL)isProxy +{ + return YES; +} + +- (BOOL)isKindOfClass:(Class)aClass +{ + var signature = [self methodSignatureForSelector:_cmd], + invocation = [CPInvocation invocationWithMethodSignature:signature]; + + [self forwardInvocation:invocation]; + + return [invocation returnValue]; +} + +-(BOOL)isMemberOfClass:(Class)aClass +{ + var signature = [self methodSignatureForSelector:_cmd], + invocation = [CPInvocation invocationWithMethodSignature:signature]; + + [self forwardInvocation:invocation]; + + return [invocation returnValue]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + var signature = [self methodSignatureForSelector:_cmd], + invocation = [CPInvocation invocationWithMethodSignature:signature]; + + [self forwardInvocation:invocation]; + + return [invocation returnValue]; +} + +- (CPString)description +{ + return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">"; +} + +@end diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index 1223b1e29..86c9ece8d 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -22,6 +22,7 @@ @import "CPObject.j" @import "CPInvocation.j" +@import "CPProxy.j" var CPUndoManagerNormal = 0, @@ -177,8 +178,10 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", id _currentGrouping; int _state; CPString _actionName; + id _preparedTarget; - + id _undoManagerProxy; + CPArray _runLoopModes; BOOL _registeredWithRunLoop; } @@ -200,7 +203,9 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", [self setRunLoopModes:[CPDefaultRunLoopMode]]; [self setGroupsByEvent:YES]; - _performRegistered = NO; + + _undoManagerProxy = [_CPUndoManagerProxy alloc]; + _undoManagerProxy._undoManager = self; } return self; @@ -244,14 +249,14 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", { _preparedTarget = aTarget; - return self; + return _undoManagerProxy; } /* FIXME This method doesn't seem to do anything right @ignore */ --(CPMethodSignature)methodSignatureForSelector:(SEL)aSelector +- (CPMethodSignature)_methodSignatureOfPreparedTargetForSelector:(SEL)aSelector { if ([_preparedTarget respondsToSelector:aSelector]) return 1; @@ -264,7 +269,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey", target on the invocation, and adds it to the current grouping. @param anInvocation the message to record */ -- (void)forwardInvocation:(CPInvocation)anInvocation +- (void)_forwardInvocationToPreparedTarget:(CPInvocation)anInvocation { if (_disableCount > 0) return; @@ -718,3 +723,20 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey", } @end + +@implementation _CPUndoManagerProxy : CPProxy +{ + CPUndoManager _undoManager; +} + +- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector +{ + return [_undoManager _methodSignatureOfPreparedTargetForSelector:aSelector]; +} + +- (void)forwardInvocation:(CPInvocation)anInvocation +{ + [_undoManager _forwardInvocationToPreparedTarget:anInvocation]; +} + +@end