• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /macosx-10.10.1/pyobjc-45/2.5/pyobjc/pyobjc-framework-Cocoa/Examples/AppKit/PythonBrowser/
1"""PythonBrowserModel.py -- module implementing the data model for PythonBrowser."""
2
3from Foundation import NSObject
4from AppKit import NSBeep
5from operator import getitem, setitem
6import sys
7
8
9class PythonBrowserModel(NSObject):
10
11    """This is a delegate as well as a data source for NSOutlineViews."""
12
13    def initWithObject_(self, obj):
14        self = self.init()
15        self.setObject_(obj)
16        return self
17
18    def setObject_(self, obj):
19        self.root = PythonItem("<root>", obj, None, None)
20
21    # NSOutlineViewDataSource  methods
22
23    def outlineView_numberOfChildrenOfItem_(self, view, item):
24        if item is None:
25            item = self.root
26        return len(item)
27
28    def outlineView_child_ofItem_(self, view, child, item):
29        if item is None:
30            item = self.root
31        return item.getChild(child)
32
33    def outlineView_isItemExpandable_(self, view, item):
34        if item is None:
35            item = self.root
36        return item.isExpandable()
37
38    def outlineView_objectValueForTableColumn_byItem_(self, view, col, item):
39        if item is None:
40            item = self.root
41        return getattr(item, col.identifier())
42
43    def outlineView_setObjectValue_forTableColumn_byItem_(self, view, value, col, item):
44        assert col.identifier() == "value"
45        if item.value == value:
46            return
47        try:
48            obj = eval(value, {})
49        except:
50            NSBeep()
51            print "XXX Error:", sys.exc_info()
52            print "XXX      :", repr(value)
53        else:
54            item.setValue(obj)
55
56    # delegate method
57    def outlineView_shouldEditTableColumn_item_(self, view, col, item):
58        return item.isEditable()
59
60
61# objects of these types are not eligable for expansion in the outline view
62SIMPLE_TYPES = (str, unicode, int, long, float, complex)
63
64
65def getInstanceVarNames(obj):
66    """Return a list the names of all (potential) instance variables."""
67    # Recipe from Guido
68    slots = {}
69    if hasattr(obj, "__dict__"):
70        slots.update(obj.__dict__)
71    if hasattr(obj, "__class__"):
72        slots["__class__"] = 1
73    cls = getattr(obj, "__class__", type(obj))
74    if hasattr(cls, "__mro__"):
75        for base in cls.__mro__:
76            for name, value in base.__dict__.items():
77                # XXX using callable() is a heuristic which isn't 100%
78                # foolproof.
79                if hasattr(value, "__get__") and not callable(value) and \
80                        hasattr(obj, name):
81                    slots[name] = 1
82    if "__dict__" in slots:
83        del slots["__dict__"]
84    slots = slots.keys()
85    slots.sort()
86    return slots
87
88
89class NiceError:
90
91    """Wrapper for an exception so we can display it nicely in the browser."""
92
93    def __init__(self, exc_info):
94        self.exc_info = exc_info
95
96    def __repr__(self):
97        from traceback import format_exception_only
98        lines = format_exception_only(*self.exc_info[:2])
99        assert len(lines) == 1
100        error = lines[0].strip()
101        return "*** error *** %s" %error
102
103
104class PythonItem(NSObject):
105
106    """Wrapper class for items to be displayed in the outline view."""
107
108    # We keep references to all child items (once created). This is
109    # neccesary because NSOutlineView holds on to PythonItem instances
110    # without retaining them. If we don't make sure they don't get
111    # garbage collected, the app will crash. For the same reason this
112    # class _must_ derive from NSObject, since otherwise autoreleased
113    # proxies will be fed to NSOutlineView, which will go away too soon.
114
115    def __new__(cls, *args, **kwargs):
116        # "Pythonic" constructor
117        return cls.alloc().init()
118
119    def __init__(self, name, obj, parent, setvalue):
120        self.realName = name
121        self.name = str(name)
122        self.parent = parent
123        self._setValue = setvalue
124        self.type = type(obj).__name__
125        try:
126            self.value = repr(obj)[:256]  # XXX [:256] makes it quite a bit faster for long reprs.
127            assert isinstance(self.value, str)
128        except:
129            self.value = repr(NiceError(sys.exc_info()))
130        self.object = obj
131        self.childrenEditable = 0
132        if isinstance(obj, dict):
133            self.children = obj.keys()
134            self.children.sort()
135            self._getChild = getitem
136            self._setChild = setitem
137            self.childrenEditable = 1
138        elif obj is None or isinstance(obj, SIMPLE_TYPES):
139            self._getChild = None
140            self._setChild = None
141        elif isinstance(obj, (list, tuple)):
142            self.children = range(len(obj))
143            self._getChild = getitem
144            self._setChild = setitem
145            if isinstance(obj, list):
146                self.childrenEditable = 1
147        else:
148            self.children = getInstanceVarNames(obj)
149            self._getChild = getattr
150            self._setChild = setattr
151            self.childrenEditable = 1  # XXX we don't know that...
152        self._childRefs = {}
153
154    def setValue(self, value):
155        self._setValue(self.parent, self.realName, value)
156        self.__init__(self.realName, value, self.parent, self._setValue)
157
158    def isEditable(self):
159        return self._setValue is not None
160
161    def isExpandable(self):
162        return self._getChild is not None
163
164    def getChild(self, child):
165        if self._childRefs.has_key(child):
166            return self._childRefs[child]
167
168        name = self.children[child]
169        try:
170            obj = self._getChild(self.object, name)
171        except:
172            obj = NiceError(sys.exc_info())
173        if self.childrenEditable:
174            childObj = PythonItem(name, obj, self.object, self._setChild)
175        else:
176            childObj = PythonItem(name, obj, None, None)
177        self._childRefs[child] = childObj
178        return childObj
179
180    def __len__(self):
181        return len(self.children)
182