]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/crust.py
Another merge of 2.6 changes
[wxWidgets.git] / wxPython / wx / py / crust.py
1 """Crust combines the shell and filling into one control."""
2
3 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
4 __cvsid__ = "$Id$"
5 __revision__ = "$Revision$"[11:-2]
6
7 import wx
8
9 import os
10 import pprint
11 import re
12 import sys
13
14 import dispatcher
15 import editwindow
16 from filling import Filling
17 import frame
18 from shell import Shell
19 from version import VERSION
20
21
22 class Crust(wx.SplitterWindow):
23 """Crust based on SplitterWindow."""
24
25 name = 'Crust'
26 revision = __revision__
27 sashoffset = 300
28
29 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
30 size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
31 name='Crust Window', rootObject=None, rootLabel=None,
32 rootIsNamespace=True, intro='', locals=None,
33 InterpClass=None,
34 startupScript=None, execStartupScript=True,
35 *args, **kwds):
36 """Create Crust instance."""
37 wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
38 self.shell = Shell(parent=self, introText=intro,
39 locals=locals, InterpClass=InterpClass,
40 startupScript=startupScript,
41 execStartupScript=execStartupScript,
42 *args, **kwds)
43 self.editor = self.shell
44 if rootObject is None:
45 rootObject = self.shell.interp.locals
46 self.notebook = wx.Notebook(parent=self, id=-1)
47 self.shell.interp.locals['notebook'] = self.notebook
48 self.filling = Filling(parent=self.notebook,
49 rootObject=rootObject,
50 rootLabel=rootLabel,
51 rootIsNamespace=rootIsNamespace)
52 # Add 'filling' to the interpreter's locals.
53 self.shell.interp.locals['filling'] = self.filling
54 self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
55
56 self.display = Display(parent=self.notebook)
57 self.notebook.AddPage(page=self.display, text='Display')
58 # Add 'pp' (pretty print) to the interpreter's locals.
59 self.shell.interp.locals['pp'] = self.display.setItem
60 self.display.nbTab = self.notebook.GetPageCount()-1
61
62 self.calltip = Calltip(parent=self.notebook)
63 self.notebook.AddPage(page=self.calltip, text='Calltip')
64
65 self.sessionlisting = SessionListing(parent=self.notebook)
66 self.notebook.AddPage(page=self.sessionlisting, text='Session')
67
68 self.dispatcherlisting = DispatcherListing(parent=self.notebook)
69 self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
70
71 self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
72 self.SetMinimumPaneSize(100)
73
74 self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
75 self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
76
77
78 def OnChanged(self, event):
79 """update sash offset from the bottom of the window"""
80 self.sashoffset = self.GetSize().height - event.GetSashPosition()
81 event.Skip()
82
83
84 # Make the splitter expand the top window when resized
85 def SplitterOnSize(self, event):
86 splitter = event.GetEventObject()
87 sz = splitter.GetSize()
88 splitter.SetSashPosition(sz.height - self.sashoffset, True)
89 event.Skip()
90
91
92 def LoadSettings(self, config):
93 self.shell.LoadSettings(config)
94 self.filling.LoadSettings(config)
95
96 pos = config.ReadInt('Sash/CrustPos', 400)
97 wx.CallAfter(self.SetSashPosition, pos)
98 def _updateSashPosValue():
99 sz = self.GetSize()
100 self.sashoffset = sz.height - self.GetSashPosition()
101 wx.CallAfter(_updateSashPosValue)
102 zoom = config.ReadInt('View/Zoom/Display', -99)
103 if zoom != -99:
104 self.display.SetZoom(zoom)
105
106
107 def SaveSettings(self, config):
108 self.shell.SaveSettings(config)
109 self.filling.SaveSettings(config)
110
111 config.WriteInt('Sash/CrustPos', self.GetSashPosition())
112 config.WriteInt('View/Zoom/Display', self.display.GetZoom())
113
114
115
116
117
118 class Display(editwindow.EditWindow):
119 """STC used to display an object using Pretty Print."""
120
121 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
122 size=wx.DefaultSize,
123 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER,
124 static=False):
125 """Create Display instance."""
126 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
127 # Configure various defaults and user preferences.
128 self.SetReadOnly(True)
129 self.SetWrapMode(False)
130 if not static:
131 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
132
133 def push(self, command, more):
134 """Receiver for Interpreter.push signal."""
135 self.Refresh()
136
137 def Refresh(self):
138 if not hasattr(self, "item"):
139 return
140 self.SetReadOnly(False)
141 text = pprint.pformat(self.item)
142 self.SetText(text)
143 self.SetReadOnly(True)
144
145 def setItem(self, item):
146 """Set item to pretty print in the notebook Display tab."""
147 self.item = item
148 self.Refresh()
149 if self.GetParent().GetSelection() != self.nbTab:
150 focus = wx.Window.FindFocus()
151 self.GetParent().SetSelection(self.nbTab)
152 wx.CallAfter(focus.SetFocus)
153
154
155 # TODO: Switch this to a editwindow.EditWindow
156 class Calltip(wx.TextCtrl):
157 """Text control containing the most recent shell calltip."""
158
159 def __init__(self, parent=None, id=-1):
160 style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
161 wx.TextCtrl.__init__(self, parent, id, style=style)
162 self.SetBackgroundColour(wx.Colour(255, 255, 208))
163 dispatcher.connect(receiver=self.display, signal='Shell.calltip')
164
165 def display(self, calltip):
166 """Receiver for Shell.calltip signal."""
167 ## self.SetValue(calltip) # Caused refresh problem on Windows.
168 self.Clear()
169 self.AppendText(calltip)
170
171
172 # TODO: Switch this to a editwindow.EditWindow
173 class SessionListing(wx.TextCtrl):
174 """Text control containing all commands for session."""
175
176 def __init__(self, parent=None, id=-1):
177 style = (wx.TE_MULTILINE | wx.TE_READONLY |
178 wx.TE_RICH2 | wx.TE_DONTWRAP)
179 wx.TextCtrl.__init__(self, parent, id, style=style)
180 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
181
182 def push(self, command, more):
183 """Receiver for Interpreter.push signal."""
184 if command and not more:
185 self.SetInsertionPointEnd()
186 start, end = self.GetSelection()
187 if start != end:
188 self.SetSelection(0, 0)
189 self.AppendText(command + '\n')
190
191
192 class DispatcherListing(wx.TextCtrl):
193 """Text control containing all dispatches for session."""
194
195 def __init__(self, parent=None, id=-1):
196 style = (wx.TE_MULTILINE | wx.TE_READONLY |
197 wx.TE_RICH2 | wx.TE_DONTWRAP)
198 wx.TextCtrl.__init__(self, parent, id, style=style)
199 dispatcher.connect(receiver=self.spy)
200
201 def spy(self, signal, sender):
202 """Receiver for Any signal from Any sender."""
203 text = '%r from %s' % (signal, sender)
204 self.SetInsertionPointEnd()
205 start, end = self.GetSelection()
206 if start != end:
207 self.SetSelection(0, 0)
208 self.AppendText(text + '\n')
209
210
211
212 class CrustFrame(frame.Frame, frame.ShellFrameMixin):
213 """Frame containing all the PyCrust components."""
214
215 name = 'CrustFrame'
216 revision = __revision__
217
218
219 def __init__(self, parent=None, id=-1, title='PyCrust',
220 pos=wx.DefaultPosition, size=wx.DefaultSize,
221 style=wx.DEFAULT_FRAME_STYLE,
222 rootObject=None, rootLabel=None, rootIsNamespace=True,
223 locals=None, InterpClass=None,
224 config=None, dataDir=None,
225 *args, **kwds):
226 """Create CrustFrame instance."""
227 frame.Frame.__init__(self, parent, id, title, pos, size, style)
228 frame.ShellFrameMixin.__init__(self, config, dataDir)
229
230 if size == wx.DefaultSize:
231 self.SetSize((800, 600))
232
233 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
234 self.SetStatusText(intro.replace('\n', ', '))
235 self.crust = Crust(parent=self, intro=intro,
236 rootObject=rootObject,
237 rootLabel=rootLabel,
238 rootIsNamespace=rootIsNamespace,
239 locals=locals,
240 InterpClass=InterpClass,
241 startupScript=self.startupScript,
242 execStartupScript=self.execStartupScript,
243 *args, **kwds)
244 self.shell = self.crust.shell
245
246 # Override the filling so that status messages go to the status bar.
247 self.crust.filling.tree.setStatusText = self.SetStatusText
248
249 # Override the shell so that status messages go to the status bar.
250 self.shell.setStatusText = self.SetStatusText
251
252 self.shell.SetFocus()
253 self.LoadSettings()
254
255
256 def OnClose(self, event):
257 """Event handler for closing."""
258 self.SaveSettings()
259 self.crust.shell.destroy()
260 self.Destroy()
261
262
263 def OnAbout(self, event):
264 """Display an About window."""
265 title = 'About PyCrust'
266 text = 'PyCrust %s\n\n' % VERSION + \
267 'Yet another Python shell, only flakier.\n\n' + \
268 'Half-baked by Patrick K. O\'Brien,\n' + \
269 'the other half is still in the oven.\n\n' + \
270 'Shell Revision: %s\n' % self.shell.revision + \
271 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
272 'Platform: %s\n' % sys.platform + \
273 'Python Version: %s\n' % sys.version.split()[0] + \
274 'wxPython Version: %s\n' % wx.VERSION_STRING + \
275 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
276 dialog = wx.MessageDialog(self, text, title,
277 wx.OK | wx.ICON_INFORMATION)
278 dialog.ShowModal()
279 dialog.Destroy()
280
281
282 def OnHelp(self, event):
283 """Show a help dialog."""
284 frame.ShellFrameMixin.OnHelp(self, event)
285
286
287 def LoadSettings(self):
288 if self.config is not None:
289 frame.ShellFrameMixin.LoadSettings(self)
290 frame.Frame.LoadSettings(self, self.config)
291 self.crust.LoadSettings(self.config)
292
293
294 def SaveSettings(self):
295 if self.config is not None:
296 frame.ShellFrameMixin.SaveSettings(self)
297 if self.autoSaveSettings:
298 frame.Frame.SaveSettings(self, self.config)
299 self.crust.SaveSettings(self.config)
300
301
302 def DoSaveSettings(self):
303 if self.config is not None:
304 self.SaveSettings()
305 self.config.Flush()
306
307
308