]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/crust.py
Add code to remove the selection (if any) in wxTextCtrl::WriteText for multi-line...
[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='History')
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 df = self.GetFont()
166 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
167 self.SetFont(font)
168
169 def display(self, calltip):
170 """Receiver for Shell.calltip signal."""
171 ## self.SetValue(calltip) # Caused refresh problem on Windows.
172 self.Clear()
173 self.AppendText(calltip)
174
175
176 # TODO: Switch this to a editwindow.EditWindow
177 class SessionListing(wx.TextCtrl):
178 """Text control containing all commands for session."""
179
180 def __init__(self, parent=None, id=-1):
181 style = (wx.TE_MULTILINE | wx.TE_READONLY |
182 wx.TE_RICH2 | wx.TE_DONTWRAP)
183 wx.TextCtrl.__init__(self, parent, id, style=style)
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()
198
199 def addHistory(self, command):
200 if command:
201 self.SetInsertionPointEnd()
202 self.AppendText(command + '\n')
203
204 def clearHistory(self):
205 self.SetValue("")
206
207
208 class DispatcherListing(wx.TextCtrl):
209 """Text control containing all dispatches for session."""
210
211 def __init__(self, parent=None, id=-1):
212 style = (wx.TE_MULTILINE | wx.TE_READONLY |
213 wx.TE_RICH2 | wx.TE_DONTWRAP)
214 wx.TextCtrl.__init__(self, parent, id, style=style)
215 dispatcher.connect(receiver=self.spy)
216
217 df = self.GetFont()
218 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
219 self.SetFont(font)
220
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
231
232 class CrustFrame(frame.Frame, frame.ShellFrameMixin):
233 """Frame containing all the PyCrust components."""
234
235 name = 'CrustFrame'
236 revision = __revision__
237
238
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,
243 locals=None, InterpClass=None,
244 config=None, dataDir=None,
245 *args, **kwds):
246 """Create CrustFrame instance."""
247 frame.Frame.__init__(self, parent, id, title, pos, size, style)
248 frame.ShellFrameMixin.__init__(self, config, dataDir)
249
250 if size == wx.DefaultSize:
251 self.SetSize((800, 600))
252
253 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
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,
260 InterpClass=InterpClass,
261 startupScript=self.startupScript,
262 execStartupScript=self.execStartupScript,
263 *args, **kwds)
264 self.shell = self.crust.shell
265
266 # Override the filling so that status messages go to the status bar.
267 self.crust.filling.tree.setStatusText = self.SetStatusText
268
269 # Override the shell so that status messages go to the status bar.
270 self.shell.setStatusText = self.SetStatusText
271
272 self.shell.SetFocus()
273 self.LoadSettings()
274
275
276 def OnClose(self, event):
277 """Event handler for closing."""
278 self.SaveSettings()
279 self.crust.shell.destroy()
280 self.Destroy()
281
282
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 + \
292 'Platform: %s\n' % sys.platform + \
293 'Python Version: %s\n' % sys.version.split()[0] + \
294 'wxPython Version: %s\n' % wx.VERSION_STRING + \
295 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
296 dialog = wx.MessageDialog(self, text, title,
297 wx.OK | wx.ICON_INFORMATION)
298 dialog.ShowModal()
299 dialog.Destroy()
300
301
302 def OnHelp(self, event):
303 """Show a help dialog."""
304 frame.ShellFrameMixin.OnHelp(self, event)
305
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
314 def SaveSettings(self, force=False):
315 if self.config is not None:
316 frame.ShellFrameMixin.SaveSettings(self)
317 if self.autoSaveSettings or force:
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:
324 self.SaveSettings(force=True)
325 self.config.Flush()
326
327
328