Files
cappuccino/Tools/nib2cib/NSClassSwapper.j
T
2013-01-18 14:29:25 -08:00

132 lines
4.7 KiB
Plaintext

/*
* NSClassSwapper.j
* nib2cib
*
* 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 "Converter.j"
@global CP_NSMapClassName
var NSClassSwapperClassNames = {},
NSClassSwapperOriginalClassNames = {};
var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
_CPCibClassSwapperOriginalClassNameKey = @"_CPCibClassSwapperOriginalClassNameKey";
@implementation NSClassSwapper : _CPCibClassSwapper
{
}
+ (id)swapperClassForClassName:(CPString)aClassName originalClassName:(CPString)anOriginalClassName
{
var swapperClassName = "$NSClassSwapper_" + aClassName + "_" + anOriginalClassName,
swapperClass = objj_lookUpClass(swapperClassName);
if (!swapperClass)
{
// If this is a userland NS class, call its KVC methods directly
var nsClass = nil;
if ([[[Converter sharedConverter] userNSClasses] containsObject:aClassName])
nsClass = objj_lookUpClass("NS_" + aClassName);
var originalClass = nsClass || objj_lookUpClass(anOriginalClassName);
swapperClass = objj_allocateClassPair(originalClass, swapperClassName);
objj_registerClassPair(swapperClass);
/*
When calling userland KVC methods, they should think that the class is
the NS class (not the swapper class) so that they are in their userland space,
not in AppKit space. For example, this ensures that bundleForClass:[self class] will work correctly.
We can accomplish this safely by changing the class of self temporarily and sending directly
to self instead of to super. This swizzle is safe because NSClassSwapper and _CPCibClassSwapper
do not add any ivars.
*/
class_addMethod(swapperClass, @selector(initWithCoder:), function(self, _cmd, aCoder)
{
if (nsClass)
{
// Switch to userland temporarily
self.isa = nsClass;
self = objj_msgSend(self, _cmd, aCoder);
self.isa = swapperClass;
}
else
self = objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
if (self)
{
var UID = [self UID];
NSClassSwapperClassNames[UID] = aClassName;
NSClassSwapperOriginalClassNames[UID] = anOriginalClassName;
}
return self;
}, "");
class_addMethod(swapperClass, @selector(classForKeyedArchiver), function(self, _cmd)
{
return [_CPCibClassSwapper class];
}, "");
class_addMethod(swapperClass, @selector(encodeWithCoder:), function(self, _cmd, aCoder)
{
if (nsClass)
{
// Switch to userland temporarily
self.isa = nsClass;
objj_msgSend(self, _cmd, aCoder);
self.isa = swapperClass;
}
else
objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
// If this is a custom NS class, lookup its archiver class so that
// the correct class is swapped during unarchiving.
if (nsClass)
{
var classForArchiver = objj_msgSend(nsClass, "classForKeyedArchiver");
if (classForArchiver)
aClassName = [classForArchiver className];
}
[aCoder encodeObject:aClassName forKey:_CPCibClassSwapperClassNameKey];
[aCoder encodeObject:CP_NSMapClassName(anOriginalClassName) forKey:_CPCibClassSwapperOriginalClassNameKey];
}, "");
}
return swapperClass;
}
+ (id)allocWithCoder:(CPCoder)aCoder
{
var className = [aCoder decodeObjectForKey:@"NSClassName"],
originalClassName = [aCoder decodeObjectForKey:@"NSOriginalClassName"];
return [[self swapperClassForClassName:className originalClassName:originalClassName] alloc];
}
@end