]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/crust.py
Updated manual version
[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