1# XXX TO DO:
2# - popup menu
3# - support partial or total redisplay
4# - more doc strings
5# - tooltips
6
7# object browser
8
9# XXX TO DO:
10# - for classes/modules, add "open source" to object browser
11
12import re
13
14from idlelib.TreeWidget import TreeItem, TreeNode, ScrolledCanvas
15
16from repr import Repr
17
18myrepr = Repr()
19myrepr.maxstring = 100
20myrepr.maxother = 100
21
22class ObjectTreeItem(TreeItem):
23    def __init__(self, labeltext, object, setfunction=None):
24        self.labeltext = labeltext
25        self.object = object
26        self.setfunction = setfunction
27    def GetLabelText(self):
28        return self.labeltext
29    def GetText(self):
30        return myrepr.repr(self.object)
31    def GetIconName(self):
32        if not self.IsExpandable():
33            return "python"
34    def IsEditable(self):
35        return self.setfunction is not None
36    def SetText(self, text):
37        try:
38            value = eval(text)
39            self.setfunction(value)
40        except:
41            pass
42        else:
43            self.object = value
44    def IsExpandable(self):
45        return not not dir(self.object)
46    def GetSubList(self):
47        keys = dir(self.object)
48        sublist = []
49        for key in keys:
50            try:
51                value = getattr(self.object, key)
52            except AttributeError:
53                continue
54            item = make_objecttreeitem(
55                str(key) + " =",
56                value,
57                lambda value, key=key, object=self.object:
58                    setattr(object, key, value))
59            sublist.append(item)
60        return sublist
61
62class InstanceTreeItem(ObjectTreeItem):
63    def IsExpandable(self):
64        return True
65    def GetSubList(self):
66        sublist = ObjectTreeItem.GetSubList(self)
67        sublist.insert(0,
68            make_objecttreeitem("__class__ =", self.object.__class__))
69        return sublist
70
71class ClassTreeItem(ObjectTreeItem):
72    def IsExpandable(self):
73        return True
74    def GetSubList(self):
75        sublist = ObjectTreeItem.GetSubList(self)
76        if len(self.object.__bases__) == 1:
77            item = make_objecttreeitem("__bases__[0] =",
78                self.object.__bases__[0])
79        else:
80            item = make_objecttreeitem("__bases__ =", self.object.__bases__)
81        sublist.insert(0, item)
82        return sublist
83
84class AtomicObjectTreeItem(ObjectTreeItem):
85    def IsExpandable(self):
86        return 0
87
88class SequenceTreeItem(ObjectTreeItem):
89    def IsExpandable(self):
90        return len(self.object) > 0
91    def keys(self):
92        return range(len(self.object))
93    def GetSubList(self):
94        sublist = []
95        for key in self.keys():
96            try:
97                value = self.object[key]
98            except KeyError:
99                continue
100            def setfunction(value, key=key, object=self.object):
101                object[key] = value
102            item = make_objecttreeitem("%r:" % (key,), value, setfunction)
103            sublist.append(item)
104        return sublist
105
106class DictTreeItem(SequenceTreeItem):
107    def keys(self):
108        keys = self.object.keys()
109        try:
110            keys.sort()
111        except:
112            pass
113        return keys
114
115from types import *
116
117dispatch = {
118    IntType: AtomicObjectTreeItem,
119    LongType: AtomicObjectTreeItem,
120    FloatType: AtomicObjectTreeItem,
121    StringType: AtomicObjectTreeItem,
122    TupleType: SequenceTreeItem,
123    ListType: SequenceTreeItem,
124    DictType: DictTreeItem,
125    InstanceType: InstanceTreeItem,
126    ClassType: ClassTreeItem,
127}
128
129def make_objecttreeitem(labeltext, object, setfunction=None):
130    t = type(object)
131    if t in dispatch:
132        c = dispatch[t]
133    else:
134        c = ObjectTreeItem
135    return c(labeltext, object, setfunction)
136
137
138def _object_browser(parent):
139    import sys
140    from Tkinter import Tk
141    root = Tk()
142    root.title("Test ObjectBrowser")
143    width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
144    root.geometry("+%d+%d"%(x, y + 150))
145    root.configure(bd=0, bg="yellow")
146    root.focus_set()
147    sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1)
148    sc.frame.pack(expand=1, fill="both")
149    item = make_objecttreeitem("sys", sys)
150    node = TreeNode(sc.canvas, None, item)
151    node.update()
152    root.mainloop()
153
154if __name__ == '__main__':
155    from idlelib.idle_test.htest import run
156    run(_object_browser)
157