]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/py/crust.py
clarified the rules for determining whether the path is absolute or relative (patch...
[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 65 self.sessionlisting = SessionListing(parent=self.notebook)
e773f79b 66 self.notebook.AddPage(page=self.sessionlisting, text='History')
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
e773f79b
RD
165 df = self.GetFont()
166 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
167 self.SetFont(font)
168
d14a1e28
RD
169 def display(self, calltip):
170 """Receiver for Shell.calltip signal."""
07b87e8d
PB
171 ## self.SetValue(calltip) # Caused refresh problem on Windows.
172 self.Clear()
173 self.AppendText(calltip)
d14a1e28
RD
174
175
02b800ce 176# TODO: Switch this to a editwindow.EditWindow
d14a1e28
RD
177class SessionListing(wx.TextCtrl):
178 """Text control containing all commands for session."""
179
180 def __init__(self, parent=None, id=-1):
65d005e4
PB
181 style = (wx.TE_MULTILINE | wx.TE_READONLY |
182 wx.TE_RICH2 | wx.TE_DONTWRAP)
183 wx.TextCtrl.__init__(self, parent, id, style=style)
e773f79b
RD
184 dispatcher.connect(receiver=self.addHistory, signal="Shell.addHistory")
185 dispatcher.connect(receiver=self.clearHistory, signal="Shell.clearHistory")
186 dispatcher.connect(receiver=self.loadHistory, signal="Shell.loadHistory")
187
188 df = self.GetFont()
189 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
190 self.SetFont(font)
191
192 def loadHistory(self, history):
193 # preload the existing history, if any
194 hist = history[:]
195 hist.reverse()
196 self.SetValue('\n'.join(hist) + '\n')
197 self.SetInsertionPointEnd()
d14a1e28 198
e773f79b
RD
199 def addHistory(self, command):
200 if command:
d14a1e28 201 self.SetInsertionPointEnd()
d14a1e28
RD
202 self.AppendText(command + '\n')
203
e773f79b
RD
204 def clearHistory(self):
205 self.SetValue("")
206
d14a1e28
RD
207
208class DispatcherListing(wx.TextCtrl):
209 """Text control containing all dispatches for session."""
210
211 def __init__(self, parent=None, id=-1):
65d005e4
PB
212 style = (wx.TE_MULTILINE | wx.TE_READONLY |
213 wx.TE_RICH2 | wx.TE_DONTWRAP)
214 wx.TextCtrl.__init__(self, parent, id, style=style)
d14a1e28
RD
215 dispatcher.connect(receiver=self.spy)
216
e773f79b
RD
217 df = self.GetFont()
218 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
219 self.SetFont(font)
220
d14a1e28
RD
221 def spy(self, signal, sender):
222 """Receiver for Any signal from Any sender."""
223 text = '%r from %s' % (signal, sender)
224 self.SetInsertionPointEnd()
225 start, end = self.GetSelection()
226 if start != end:
227 self.SetSelection(0, 0)
228 self.AppendText(text + '\n')
229
230
02b800ce
RD
231
232class CrustFrame(frame.Frame, frame.ShellFrameMixin):
d14a1e28
RD
233 """Frame containing all the PyCrust components."""
234
235 name = 'CrustFrame'
236 revision = __revision__
237
02b800ce 238
d14a1e28
RD
239 def __init__(self, parent=None, id=-1, title='PyCrust',
240 pos=wx.DefaultPosition, size=wx.DefaultSize,
241 style=wx.DEFAULT_FRAME_STYLE,
242 rootObject=None, rootLabel=None, rootIsNamespace=True,
02b800ce
RD
243 locals=None, InterpClass=None,
244 config=None, dataDir=None,
245 *args, **kwds):
d14a1e28
RD
246 """Create CrustFrame instance."""
247 frame.Frame.__init__(self, parent, id, title, pos, size, style)
02b800ce
RD
248 frame.ShellFrameMixin.__init__(self, config, dataDir)
249
250 if size == wx.DefaultSize:
251 self.SetSize((800, 600))
252
d14a1e28 253 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
d14a1e28
RD
254 self.SetStatusText(intro.replace('\n', ', '))
255 self.crust = Crust(parent=self, intro=intro,
256 rootObject=rootObject,
257 rootLabel=rootLabel,
258 rootIsNamespace=rootIsNamespace,
259 locals=locals,
02b800ce
RD
260 InterpClass=InterpClass,
261 startupScript=self.startupScript,
262 execStartupScript=self.execStartupScript,
263 *args, **kwds)
d14a1e28 264 self.shell = self.crust.shell
02b800ce 265
d14a1e28
RD
266 # Override the filling so that status messages go to the status bar.
267 self.crust.filling.tree.setStatusText = self.SetStatusText
02b800ce 268
d14a1e28
RD
269 # Override the shell so that status messages go to the status bar.
270 self.shell.setStatusText = self.SetStatusText
02b800ce 271
d14a1e28 272 self.shell.SetFocus()
02b800ce
RD
273 self.LoadSettings()
274
d14a1e28
RD
275
276 def OnClose(self, event):
277 """Event handler for closing."""
02b800ce 278 self.SaveSettings()
d14a1e28
RD
279 self.crust.shell.destroy()
280 self.Destroy()
281
02b800ce 282
d14a1e28
RD
283 def OnAbout(self, event):
284 """Display an About window."""
285 title = 'About PyCrust'
286 text = 'PyCrust %s\n\n' % VERSION + \
287 'Yet another Python shell, only flakier.\n\n' + \
288 'Half-baked by Patrick K. O\'Brien,\n' + \
289 'the other half is still in the oven.\n\n' + \
290 'Shell Revision: %s\n' % self.shell.revision + \
291 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
f2f8a5fc 292 'Platform: %s\n' % sys.platform + \
d14a1e28
RD
293 'Python Version: %s\n' % sys.version.split()[0] + \
294 'wxPython Version: %s\n' % wx.VERSION_STRING + \
02b800ce 295 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
d14a1e28
RD
296 dialog = wx.MessageDialog(self, text, title,
297 wx.OK | wx.ICON_INFORMATION)
298 dialog.ShowModal()
299 dialog.Destroy()
02b800ce
RD
300
301
4617be08
RD
302 def OnHelp(self, event):
303 """Show a help dialog."""
304 frame.ShellFrameMixin.OnHelp(self, event)
305
02b800ce
RD
306
307 def LoadSettings(self):
308 if self.config is not None:
309 frame.ShellFrameMixin.LoadSettings(self)
310 frame.Frame.LoadSettings(self, self.config)
311 self.crust.LoadSettings(self.config)
312
313
c0ab3f7f 314 def SaveSettings(self, force=False):
02b800ce
RD
315 if self.config is not None:
316 frame.ShellFrameMixin.SaveSettings(self)
c0ab3f7f 317 if self.autoSaveSettings or force:
02b800ce
RD
318 frame.Frame.SaveSettings(self, self.config)
319 self.crust.SaveSettings(self.config)
320
321
322 def DoSaveSettings(self):
323 if self.config is not None:
c0ab3f7f 324 self.SaveSettings(force=True)
02b800ce
RD
325 self.config.Flush()
326
327
328