]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/py/crust.py
Merge some 2.6-branch changes
[wxWidgets.git] / wxPython / wx / py / crust.py
CommitLineData
d14a1e28 1"""Crust combines the shell and filling into one control."""
1fded56b 2
d14a1e28
RD
3__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
4__cvsid__ = "$Id$"
5__revision__ = "$Revision$"[11:-2]
1fded56b 6
d14a1e28
RD
7import wx
8
9import os
10import pprint
02b800ce 11import re
d14a1e28
RD
12import sys
13
14import dispatcher
15import editwindow
16from filling import Filling
17import frame
18from shell import Shell
19from version import VERSION
20
d14a1e28
RD
21
22class Crust(wx.SplitterWindow):
23 """Crust based on SplitterWindow."""
24
25 name = 'Crust'
26 revision = __revision__
02b800ce 27 sashoffset = 300
d14a1e28 28
02b800ce
RD
29 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
30 size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
d14a1e28 31 name='Crust Window', rootObject=None, rootLabel=None,
02b800ce
RD
32 rootIsNamespace=True, intro='', locals=None,
33 InterpClass=None,
34 startupScript=None, execStartupScript=True,
35 *args, **kwds):
d14a1e28
RD
36 """Create Crust instance."""
37 wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
02b800ce
RD
38 self.shell = Shell(parent=self, introText=intro,
39 locals=locals, InterpClass=InterpClass,
40 startupScript=startupScript,
41 execStartupScript=execStartupScript,
d14a1e28
RD
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
02b800ce
RD
48 self.filling = Filling(parent=self.notebook,
49 rootObject=rootObject,
50 rootLabel=rootLabel,
d14a1e28
RD
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)
02b800ce 55
d14a1e28
RD
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
02b800ce
RD
60 self.display.nbTab = self.notebook.GetPageCount()-1
61
d14a1e28
RD
62 self.calltip = Calltip(parent=self.notebook)
63 self.notebook.AddPage(page=self.calltip, text='Calltip')
02b800ce 64
d14a1e28
RD
65 self.sessionlisting = SessionListing(parent=self.notebook)
66 self.notebook.AddPage(page=self.sessionlisting, text='Session')
02b800ce 67
d14a1e28
RD
68 self.dispatcherlisting = DispatcherListing(parent=self.notebook)
69 self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
02b800ce
RD
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
d14a1e28
RD
116
117
118class 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()
02b800ce
RD
149 if self.GetParent().GetSelection() != self.nbTab:
150 focus = wx.Window.FindFocus()
151 self.GetParent().SetSelection(self.nbTab)
152 wx.CallAfter(focus.SetFocus)
153
d14a1e28 154
02b800ce 155# TODO: Switch this to a editwindow.EditWindow
d14a1e28
RD
156class Calltip(wx.TextCtrl):
157 """Text control containing the most recent shell calltip."""
158
159 def __init__(self, parent=None, id=-1):
65d005e4
PB
160 style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
161 wx.TextCtrl.__init__(self, parent, id, style=style)
02b800ce 162 self.SetBackgroundColour(wx.Colour(255, 255, 208))
d14a1e28
RD
163 dispatcher.connect(receiver=self.display, signal='Shell.calltip')
164
165 def display(self, calltip):
166 """Receiver for Shell.calltip signal."""
07b87e8d
PB
167 ## self.SetValue(calltip) # Caused refresh problem on Windows.
168 self.Clear()
169 self.AppendText(calltip)
d14a1e28
RD
170
171
02b800ce 172# TODO: Switch this to a editwindow.EditWindow
d14a1e28
RD
173class SessionListing(wx.TextCtrl):
174 """Text control containing all commands for session."""
175
176 def __init__(self, parent=None, id=-1):
65d005e4
PB
177 style = (wx.TE_MULTILINE | wx.TE_READONLY |
178 wx.TE_RICH2 | wx.TE_DONTWRAP)
179 wx.TextCtrl.__init__(self, parent, id, style=style)
d14a1e28
RD
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
192class DispatcherListing(wx.TextCtrl):
193 """Text control containing all dispatches for session."""
194
195 def __init__(self, parent=None, id=-1):
65d005e4
PB
196 style = (wx.TE_MULTILINE | wx.TE_READONLY |
197 wx.TE_RICH2 | wx.TE_DONTWRAP)
198 wx.TextCtrl.__init__(self, parent, id, style=style)
d14a1e28
RD
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
02b800ce
RD
211
212class CrustFrame(frame.Frame, frame.ShellFrameMixin):
d14a1e28
RD
213 """Frame containing all the PyCrust components."""
214
215 name = 'CrustFrame'
216 revision = __revision__
217
02b800ce 218
d14a1e28
RD
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,
02b800ce
RD
223 locals=None, InterpClass=None,
224 config=None, dataDir=None,
225 *args, **kwds):
d14a1e28
RD
226 """Create CrustFrame instance."""
227 frame.Frame.__init__(self, parent, id, title, pos, size, style)
02b800ce
RD
228 frame.ShellFrameMixin.__init__(self, config, dataDir)
229
230 if size == wx.DefaultSize:
231 self.SetSize((800, 600))
232
d14a1e28 233 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
d14a1e28
RD
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,
02b800ce
RD
240 InterpClass=InterpClass,
241 startupScript=self.startupScript,
242 execStartupScript=self.execStartupScript,
243 *args, **kwds)
d14a1e28 244 self.shell = self.crust.shell
02b800ce 245
d14a1e28
RD
246 # Override the filling so that status messages go to the status bar.
247 self.crust.filling.tree.setStatusText = self.SetStatusText
02b800ce 248
d14a1e28
RD
249 # Override the shell so that status messages go to the status bar.
250 self.shell.setStatusText = self.SetStatusText
02b800ce 251
d14a1e28 252 self.shell.SetFocus()
02b800ce
RD
253 self.LoadSettings()
254
d14a1e28
RD
255
256 def OnClose(self, event):
257 """Event handler for closing."""
02b800ce 258 self.SaveSettings()
d14a1e28
RD
259 self.crust.shell.destroy()
260 self.Destroy()
261
02b800ce 262
d14a1e28
RD
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 + \
f2f8a5fc 272 'Platform: %s\n' % sys.platform + \
d14a1e28
RD
273 'Python Version: %s\n' % sys.version.split()[0] + \
274 'wxPython Version: %s\n' % wx.VERSION_STRING + \
02b800ce 275 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
d14a1e28
RD
276 dialog = wx.MessageDialog(self, text, title,
277 wx.OK | wx.ICON_INFORMATION)
278 dialog.ShowModal()
279 dialog.Destroy()
02b800ce
RD
280
281
4617be08
RD
282 def OnHelp(self, event):
283 """Show a help dialog."""
284 frame.ShellFrameMixin.OnHelp(self, event)
285
02b800ce
RD
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
c0ab3f7f 294 def SaveSettings(self, force=False):
02b800ce
RD
295 if self.config is not None:
296 frame.ShellFrameMixin.SaveSettings(self)
c0ab3f7f 297 if self.autoSaveSettings or force:
02b800ce
RD
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:
c0ab3f7f 304 self.SaveSettings(force=True)
02b800ce
RD
305 self.config.Flush()
306
307
308