| 1 | import objc |
|---|
| 2 | import weakref |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | class _VanillaMethods: |
|---|
| 6 | |
|---|
| 7 | def __new__(cls, wrapper): |
|---|
| 8 | self = cls.alloc().init() |
|---|
| 9 | self.setVanillaWrapper_(wrapper) |
|---|
| 10 | return self |
|---|
| 11 | |
|---|
| 12 | def setVanillaWrapper_(self, wrapper): |
|---|
| 13 | self._wrapperRef = weakref.ref(wrapper) |
|---|
| 14 | return self |
|---|
| 15 | |
|---|
| 16 | def vanillaWrapper(self): |
|---|
| 17 | try: |
|---|
| 18 | return self._wrapperRef() |
|---|
| 19 | except AttributeError: |
|---|
| 20 | return None |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | _subclasses = {} |
|---|
| 24 | def getNSSubclass(classOrName=None): |
|---|
| 25 | """Return a subclass of a given Objective-C class. |
|---|
| 26 | This subclass allows us to store a weakref to a Vanilla wrapper |
|---|
| 27 | object. This way we can always get back at it. Mainly meant to |
|---|
| 28 | translate "sender" arguments of action methods to a Vanilla object. |
|---|
| 29 | |
|---|
| 30 | The returned subclass can be instantiated from Python like this: |
|---|
| 31 | |
|---|
| 32 | >>> class Wrapper(object): pass |
|---|
| 33 | ... |
|---|
| 34 | >>> wrpr = Wrapper() |
|---|
| 35 | >>> view = getNSSubclass("NSBox")(wrpr) |
|---|
| 36 | >>> view.vanillaWrapper() is wrpr |
|---|
| 37 | True |
|---|
| 38 | |
|---|
| 39 | >>> from Foundation import NSObject |
|---|
| 40 | >>> class MyCustomNSClass(NSObject): pass |
|---|
| 41 | ... |
|---|
| 42 | >>> view = getNSSubclass(MyCustomNSClass)(wrpr) |
|---|
| 43 | >>> view.vanillaWrapper() is wrpr |
|---|
| 44 | True |
|---|
| 45 | |
|---|
| 46 | """ |
|---|
| 47 | subCls = None |
|---|
| 48 | if isinstance(classOrName, basestring): |
|---|
| 49 | cls = objc.lookUpClass(classOrName) |
|---|
| 50 | className = classOrName |
|---|
| 51 | else: |
|---|
| 52 | cls = classOrName |
|---|
| 53 | className = cls.__name__ |
|---|
| 54 | subCls = _subclasses.get(className) |
|---|
| 55 | if subCls is None: |
|---|
| 56 | vName = "V" + className |
|---|
| 57 | subCls = cls.__class__(vName, (cls,), _VanillaMethods.__dict__.copy()) |
|---|
| 58 | _subclasses[className] = subCls |
|---|
| 59 | return subCls |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | def _doctest(): |
|---|
| 63 | """ |
|---|
| 64 | >>> from AppKit import NSTextView |
|---|
| 65 | >>> sc = getNSSubclass('NSTextView') |
|---|
| 66 | >>> sc.__name__ |
|---|
| 67 | 'VNSTextView' |
|---|
| 68 | >>> issubclass(sc, NSTextView) |
|---|
| 69 | True |
|---|
| 70 | >>> hasattr(sc, 'setVanillaWrapper_') |
|---|
| 71 | True |
|---|
| 72 | >>> hasattr(sc, 'vanillaWrapper') |
|---|
| 73 | True |
|---|
| 74 | >>> # duplicate test to test caching |
|---|
| 75 | >>> sc = getNSSubclass('NSTextView') |
|---|
| 76 | >>> sc.__name__ |
|---|
| 77 | 'VNSTextView' |
|---|
| 78 | >>> issubclass(sc, NSTextView) |
|---|
| 79 | True |
|---|
| 80 | >>> class Wrapper(object): pass |
|---|
| 81 | ... |
|---|
| 82 | >>> wrpr = Wrapper() |
|---|
| 83 | >>> isinstance(sc(wrpr), NSTextView) |
|---|
| 84 | True |
|---|
| 85 | >>> # test custom class |
|---|
| 86 | >>> from Foundation import NSObject |
|---|
| 87 | >>> class TestClass(NSObject): pass |
|---|
| 88 | ... |
|---|
| 89 | >>> sc = getNSSubclass(TestClass) |
|---|
| 90 | >>> sc.__name__ |
|---|
| 91 | 'VTestClass' |
|---|
| 92 | >>> isinstance(sc(wrpr), NSObject) |
|---|
| 93 | True |
|---|
| 94 | >>> isinstance(sc(wrpr), TestClass) |
|---|
| 95 | True |
|---|
| 96 | >>> hasattr(sc, 'setVanillaWrapper_') |
|---|
| 97 | True |
|---|
| 98 | >>> hasattr(sc, 'vanillaWrapper') |
|---|
| 99 | True |
|---|
| 100 | """ |
|---|
| 101 | |
|---|
| 102 | if __name__ == "__main__": |
|---|
| 103 | import doctest |
|---|
| 104 | doctest.testmod() |
|---|