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
11from reprlib import Repr
12
13from idlelib.tree import TreeItem, TreeNode, ScrolledCanvas
14
15myrepr = Repr()
16myrepr.maxstring = 100
17myrepr.maxother = 100
18
19class ObjectTreeItem(TreeItem):
20    def __init__(self, labeltext, object, setfunction=None):
21        self.labeltext = labeltext
22        self.object = object
23        self.setfunction = setfunction
24    def GetLabelText(self):
25        return self.labeltext
26    def GetText(self):
27        return myrepr.repr(self.object)
28    def GetIconName(self):
29        if not self.IsExpandable():
30            return "python"
31    def IsEditable(self):
32        return self.setfunction is not None
33    def SetText(self, text):
34        try:
35            value = eval(text)
36            self.setfunction(value)
37        except:
38            pass
39        else:
40            self.object = value
41    def IsExpandable(self):
42        return not not dir(self.object)
43    def GetSubList(self):
44        keys = dir(self.object)
45        sublist = []
46        for key in keys:
47            try:
48                value = getattr(self.object, key)
49            except AttributeError:
50                continue
51            item = make_objecttreeitem(
52                str(key) + " =",
53                value,
54                lambda value, key=key, object=self.object:
55                    setattr(object, key, value))
56            sublist.append(item)
57        return sublist
58
59class ClassTreeItem(ObjectTreeItem):
60    def IsExpandable(self):
61        return True
62    def GetSubList(self):
63        sublist = ObjectTreeItem.GetSubList(self)
64        if len(self.object.__bases__) == 1:
65            item = make_objecttreeitem("__bases__[0] =",
66                self.object.__bases__[0])
67        else:
68            item = make_objecttreeitem("__bases__ =", self.object.__bases__)
69        sublist.insert(0, item)
70        return sublist
71
72class AtomicObjectTreeItem(ObjectTreeItem):
73    def IsExpandable(self):
74        return 0
75
76class SequenceTreeItem(ObjectTreeItem):
77    def IsExpandable(self):
78        return len(self.object) > 0
79    def keys(self):
80        return range(len(self.object))
81    def GetSubList(self):
82        sublist = []
83        for key in self.keys():
84            try:
85                value = self.object[key]
86            except KeyError:
87                continue
88            def setfunction(value, key=key, object=self.object):
89                object[key] = value
90            item = make_objecttreeitem("%r:" % (key,), value, setfunction)
91            sublist.append(item)
92        return sublist
93
94class DictTreeItem(SequenceTreeItem):
95    def keys(self):
96        keys = list(self.object.keys())
97        try:
98            keys.sort()
99        except:
100            pass
101        return keys
102
103dispatch = {
104    int: AtomicObjectTreeItem,
105    float: AtomicObjectTreeItem,
106    str: AtomicObjectTreeItem,
107    tuple: SequenceTreeItem,
108    list: SequenceTreeItem,
109    dict: DictTreeItem,
110    type: ClassTreeItem,
111}
112
113def make_objecttreeitem(labeltext, object, setfunction=None):
114    t = type(object)
115    if t in dispatch:
116        c = dispatch[t]
117    else:
118        c = ObjectTreeItem
119    return c(labeltext, object, setfunction)
120
121
122def _object_browser(parent):  # htest #
123    import sys
124    from tkinter import Toplevel
125    top = Toplevel(parent)
126    top.title("Test debug object browser")
127    x, y = map(int, parent.geometry().split('+')[1:])
128    top.geometry("+%d+%d" % (x + 100, y + 175))
129    top.configure(bd=0, bg="yellow")
130    top.focus_set()
131    sc = ScrolledCanvas(top, bg="white", highlightthickness=0, takefocus=1)
132    sc.frame.pack(expand=1, fill="both")
133    item = make_objecttreeitem("sys", sys)
134    node = TreeNode(sc.canvas, None, item)
135    node.update()
136
137if __name__ == '__main__':
138    from idlelib.idle_test.htest import run
139    run(_object_browser)
140