/Tools/nib2cib/NSClassSwapper.j

http://github.com/cacaodev/cappuccino · Unknown · 135 lines · 109 code · 26 blank · 0 comment · 0 complexity · a08117a0f6ee37689b88cc69662fb1e8 MD5 · raw file

  1. /*
  2. * NSClassSwapper.j
  3. * nib2cib
  4. *
  5. * Created by Francisco Tolmasky
  6. * Copyright 2009, 280 North, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. @import <Foundation/CPObject.j>
  23. @import <Foundation/CPString.j>
  24. @import <AppKit/_CPCibClassSwapper.j>
  25. @class Nib2Cib
  26. @global CP_NSMapClassName
  27. var NSClassSwapperClassNames = {},
  28. NSClassSwapperOriginalClassNames = {};
  29. var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
  30. _CPCibClassSwapperOriginalClassNameKey = @"_CPCibClassSwapperOriginalClassNameKey";
  31. @implementation NSClassSwapper : _CPCibClassSwapper
  32. {
  33. }
  34. + (id)swapperClassForClassName:(CPString)aClassName originalClassName:(CPString)anOriginalClassName
  35. {
  36. var swapperClassName = "$NSClassSwapper_" + aClassName + "_" + anOriginalClassName,
  37. swapperClass = objj_lookUpClass(swapperClassName);
  38. if (!swapperClass)
  39. {
  40. // If this is a userland NS class, call its KVC methods directly
  41. var nsClass = nil;
  42. if ([[[Nib2Cib sharedNib2Cib] userNSClasses] containsObject:aClassName])
  43. nsClass = objj_lookUpClass("NS_" + aClassName);
  44. var originalClass = nsClass || objj_lookUpClass(anOriginalClassName);
  45. swapperClass = objj_allocateClassPair(originalClass, swapperClassName);
  46. objj_registerClassPair(swapperClass);
  47. /*
  48. When calling userland KVC methods, they should think that the class is
  49. the NS class (not the swapper class) so that they are in their userland space,
  50. not in AppKit space. For example, this ensures that bundleForClass:[self class] will work correctly.
  51. We can accomplish this safely by changing the class of self temporarily and sending directly
  52. to self instead of to super. This swizzle is safe because NSClassSwapper and _CPCibClassSwapper
  53. do not add any ivars.
  54. */
  55. class_addMethod(swapperClass, @selector(initWithCoder:), function(self, _cmd, aCoder)
  56. {
  57. if (nsClass)
  58. {
  59. // Switch to userland temporarily
  60. self.isa = nsClass;
  61. self = objj_msgSend(self, _cmd, aCoder);
  62. self.isa = swapperClass;
  63. }
  64. else
  65. self = objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
  66. if (self)
  67. {
  68. var UID = [self UID];
  69. NSClassSwapperClassNames[UID] = aClassName;
  70. NSClassSwapperOriginalClassNames[UID] = anOriginalClassName;
  71. }
  72. return self;
  73. }, "");
  74. class_addMethod(swapperClass, @selector(classForKeyedArchiver), function(self, _cmd)
  75. {
  76. return [_CPCibClassSwapper class];
  77. }, "");
  78. class_addMethod(swapperClass, @selector(encodeWithCoder:), function(self, _cmd, aCoder)
  79. {
  80. if (nsClass)
  81. {
  82. // Switch to userland temporarily
  83. self.isa = nsClass;
  84. objj_msgSend(self, _cmd, aCoder);
  85. self.isa = swapperClass;
  86. }
  87. else
  88. objj_msgSendSuper({super_class:originalClass, receiver:self}, _cmd, aCoder);
  89. // If this is a custom NS class, lookup its archiver class so that
  90. // the correct class is swapped during unarchiving.
  91. if (nsClass)
  92. {
  93. var classForArchiver = objj_msgSend(nsClass, "classForKeyedArchiver");
  94. if (classForArchiver)
  95. aClassName = [classForArchiver className];
  96. }
  97. [aCoder encodeObject:aClassName forKey:_CPCibClassSwapperClassNameKey];
  98. [aCoder encodeObject:CP_NSMapClassName(anOriginalClassName) forKey:_CPCibClassSwapperOriginalClassNameKey];
  99. }, "");
  100. }
  101. return swapperClass;
  102. }
  103. + (id)allocWithCoder:(CPCoder)aCoder
  104. {
  105. var className = [aCoder decodeObjectForKey:@"NSClassName"],
  106. originalClassName = [aCoder decodeObjectForKey:@"NSOriginalClassName"];
  107. return [[self swapperClassForClassName:className originalClassName:originalClassName] alloc];
  108. }
  109. @end