mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 21:17:03 +00:00
Added CPProxy class to support better undo proxying in CPUndoManager.
Closes #370. Closes #371. Reviewed by me.
This commit is contained in:
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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<count; i++)
|
||||
[self _sendNotificationsForKey:keysComposedOfKey[i] changeOptions:changeOptions isBefore:isBefore];
|
||||
var index = 0,
|
||||
count = [dependentKeyPaths count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var key = dependentKeyPaths[index];
|
||||
|
||||
[self _sendNotificationsForKey:keyPath
|
||||
changeOptions:isBefore ? [changeOptions copy] : _changesForKey[keyPath]
|
||||
isBefore:isBefore];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -227,6 +227,7 @@ CPLog(@"Got some class: %@", inst);
|
||||
*/
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
// isa is isa.isa in class case.
|
||||
return !!class_getInstanceMethod(isa, aSelector);
|
||||
}
|
||||
|
||||
@@ -269,7 +270,7 @@ CPLog(@"Got some class: %@", inst);
|
||||
*/
|
||||
- (CPString)description
|
||||
{
|
||||
return "<" + isa.name + " 0x" + [CPString stringWithHash:[self UID]] + ">";
|
||||
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];
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user