]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/crust.py
remove gtk1 code
[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
39 # Turn off the tab-traversal style that is automatically
40 # turned on by wx.SplitterWindow. We do this because on
41 # Windows the event for Ctrl-Enter is stolen and used as a
42 # navigation key, but the Shell window uses it to insert lines.
43 style = self.GetWindowStyle()
44 self.SetWindowStyle(style & ~wx.TAB_TRAVERSAL)
45
46 self.shell = Shell(parent=self, introText=intro,
47 locals=locals, InterpClass=InterpClass,
48 startupScript=startupScript,
49 execStartupScript=execStartupScript,
50 *args, **kwds)
51 self.editor = self.shell
52 if rootObject is None:
53 rootObject = self.shell.interp.locals
54 self.notebook = wx.Notebook(parent=self, id=-1)
55 self.shell.interp.locals['notebook'] = self.notebook
56 self.filling = Filling(parent=self.notebook,
57 rootObject=rootObject,
58 rootLabel=rootLabel,
59 rootIsNamespace=rootIsNamespace)
60 # Add 'filling' to the interpreter's locals.
61 self.shell.interp.locals['filling'] = self.filling
62 self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
63
64 self.display = Display(parent=self.notebook)
65 self.notebook.AddPage(page=self.display, text='Display')
66 # Add 'pp' (pretty print) to the interpreter's locals.
67 self.shell.interp.locals['pp'] = self.display.setItem
68 self.display.nbTab = self.notebook.GetPageCount()-1
69
70 self.calltip = Calltip(parent=self.notebook)
71 self.notebook.AddPage(page=self.calltip, text='Calltip')
72
73 self.sessionlisting = SessionListing(parent=self.notebook)
74 self.notebook.AddPage(page=self.sessionlisting, text='History')
75
76 self.dispatcherlisting = DispatcherListing(parent=self.notebook)
77 self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
78
79
80 # Initialize in an unsplit mode, and check later after loading
81 # settings if we should split or not.
82 self.shell.Hide()
83 self.notebook.Hide()
84 self.Initialize(self.shell)
85 self._shouldsplit = True
86 wx.CallAfter(self._CheckShouldSplit)
87 self.SetMinimumPaneSize(100)
88
89 self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
90 self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
91 self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnSashDClick)
92
93 def _CheckShouldSplit(self):
94 if self._shouldsplit:
95 self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
96 self.lastsashpos = self.GetSashPosition()
97 else:
98 self.lastsashpos = -1
99 self.issplit = self.IsSplit()
100
101 def ToggleTools(self):
102 """Toggle the display of the filling and other tools"""
103 if self.issplit:
104 self.Unsplit()
105 else:
106 self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
107 self.lastsashpos = self.GetSashPosition()
108 self.issplit = self.IsSplit()
109
110 def ToolsShown(self):
111 return self.issplit
112
113 def OnChanged(self, event):
114 """update sash offset from the bottom of the window"""
115 self.sashoffset = self.GetSize().height - event.GetSashPosition()
116 self.lastsashpos = event.GetSashPosition()
117 event.Skip()
118
119 def OnSashDClick(self, event):
120 self.Unsplit()
121 self.issplit = False
122
123 # Make the splitter expand the top window when resized
124 def SplitterOnSize(self, event):
125 splitter = event.GetEventObject()
126 sz = splitter.GetSize()
127 splitter.SetSashPosition(sz.height - self.sashoffset, True)
128 event.Skip()
129
130
131 def LoadSettings(self, config):
132 self.shell.LoadSettings(config)
133 self.filling.LoadSettings(config)
134
135 pos = config.ReadInt('Sash/CrustPos', 400)
136 wx.CallAfter(self.SetSashPosition, pos)
137 def _updateSashPosValue():
138 sz = self.GetSize()
139 self.sashoffset = sz.height - self.GetSashPosition()
140 wx.CallAfter(_updateSashPosValue)
141 zoom = config.ReadInt('View/Zoom/Display', -99)
142 if zoom != -99:
143 self.display.SetZoom(zoom)
144 self.issplit = config.ReadInt('Sash/IsSplit', True)
145 if not self.issplit:
146 self._shouldsplit = False
147
148 def SaveSettings(self, config):
149 self.shell.SaveSettings(config)
150 self.filling.SaveSettings(config)
151
152 if self.lastsashpos != -1:
153 config.WriteInt('Sash/CrustPos', self.lastsashpos)
154 config.WriteInt('Sash/IsSplit', self.issplit)
155 config.WriteInt('View/Zoom/Display', self.display.GetZoom())
156
157
158
159
160
161 class Display(editwindow.EditWindow):
162 """STC used to display an object using Pretty Print."""
163
164 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
165 size=wx.DefaultSize,
166 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER,
167 static=False):
168 """Create Display instance."""
169 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
170 # Configure various defaults and user preferences.
171 self.SetReadOnly(True)
172 self.SetWrapMode(False)
173 if not static:
174 dispatcher.connect(receiver=self.push, signal='Interpreter.push')
175
176 def push(self, command, more):
177 """Receiver for Interpreter.push signal."""
178 self.Refresh()
179
180 def Refresh(self):
181 if not hasattr(self, "item"):
182 return
183 self.SetReadOnly(False)
184 text = pprint.pformat(self.item)
185 self.SetText(text)
186 self.SetReadOnly(True)
187
188 def setItem(self, item):
189 """Set item to pretty print in the notebook Display tab."""
190 self.item = item
191 self.Refresh()
192 if self.GetParent().GetSelection() != self.nbTab:
193 focus = wx.Window.FindFocus()
194 self.GetParent().SetSelection(self.nbTab)
195 wx.CallAfter(focus.SetFocus)
196
197
198 # TODO: Switch this to a editwindow.EditWindow
199 class Calltip(wx.TextCtrl):
200 """Text control containing the most recent shell calltip."""
201
202 def __init__(self, parent=None, id=-1):
203 style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
204 wx.TextCtrl.__init__(self, parent, id, style=style)
205 self.SetBackgroundColour(wx.Colour(255, 255, 208))
206 dispatcher.connect(receiver=self.display, signal='Shell.calltip')
207
208 df = self.GetFont()
209 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
210 self.SetFont(font)
211
212 def display(self, calltip):
213 """Receiver for Shell.calltip signal."""
214 ## self.SetValue(calltip) # Caused refresh problem on Windows.
215 self.Clear()
216 self.AppendText(calltip)
217
218
219 # TODO: Switch this to a editwindow.EditWindow
220 class SessionListing(wx.TextCtrl):
221 """Text control containing all commands for session."""
222
223 def __init__(self, parent=None, id=-1):
224 style = (wx.TE_MULTILINE | wx.TE_READONLY |
225 wx.TE_RICH2 | wx.TE_DONTWRAP)
226 wx.TextCtrl.__init__(self, parent, id, style=style)
227 dispatcher.connect(receiver=self.addHistory, signal="Shell.addHistory")
228 dispatcher.connect(receiver=self.clearHistory, signal="Shell.clearHistory")
229 dispatcher.connect(receiver=self.loadHistory, signal="Shell.loadHistory")
230
231 df = self.GetFont()
232 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
233 self.SetFont(font)
234
235 def loadHistory(self, history):
236 # preload the existing history, if any
237 hist = history[:]
238 hist.reverse()
239 self.SetValue('\n'.join(hist) + '\n')
240 self.SetInsertionPointEnd()
241
242 def addHistory(self, command):
243 if command:
244 self.SetInsertionPointEnd()
245 self.AppendText(command + '\n')
246
247 def clearHistory(self):
248 self.SetValue("")
249
250
251 class DispatcherListing(wx.TextCtrl):
252 """Text control containing all dispatches for session."""
253
254 def __init__(self, parent=None, id=-1):
255 style = (wx.TE_MULTILINE | wx.TE_READONLY |
256 wx.TE_RICH2 | wx.TE_DONTWRAP)
257 wx.TextCtrl.__init__(self, parent, id, style=style)
258 dispatcher.connect(receiver=self.spy)
259
260 df = self.GetFont()
261 font = wx.Font(df.GetPointSize(), wx.TELETYPE, wx.NORMAL, wx.NORMAL)
262 self.SetFont(font)
263
264 def spy(self, signal, sender):
265 """Receiver for Any signal from Any sender."""
266 text = '%r from %s' % (signal, sender)
267 self.SetInsertionPointEnd()
268 start, end = self.GetSelection()
269 if start != end:
270 self.SetSelection(0, 0)
271 self.AppendText(text + '\n')
272
273
274
275 class CrustFrame(frame.Frame, frame.ShellFrameMixin):
276 """Frame containing all the PyCrust components."""
277
278 name = 'CrustFrame'
279 revision = __revision__
280
281
282 def __init__(self, parent=None, id=-1, title='PyCrust',
283 pos=wx.DefaultPosition, size=wx.DefaultSize,
284 style=wx.DEFAULT_FRAME_STYLE,
285 rootObject=None, rootLabel=None, rootIsNamespace=True,
286 locals=None, InterpClass=None,
287 config=None, dataDir=None,
288 *args, **kwds):
289 """Create CrustFrame instance."""
290 frame.Frame.__init__(self, parent, id, title, pos, size, style)
291 frame.ShellFrameMixin.__init__(self, config, dataDir)
292
293 if size == wx.DefaultSize:
294 self.SetSize((800, 600))
295
296 intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
297 self.SetStatusText(intro.replace('\n', ', '))
298 self.crust = Crust(parent=self, intro=intro,
299 rootObject=rootObject,
300 rootLabel=rootLabel,
301 rootIsNamespace=rootIsNamespace,
302 locals=locals,
303 InterpClass=InterpClass,
304 startupScript=self.startupScript,
305 execStartupScript=self.execStartupScript,
306 *args, **kwds)
307 self.shell = self.crust.shell
308
309 # Override the filling so that status messages go to the status bar.
310 self.crust.filling.tree.setStatusText = self.SetStatusText
311
312 # Override the shell so that status messages go to the status bar.
313 self.shell.setStatusText = self.SetStatusText
314
315 self.shell.SetFocus()
316 self.LoadSettings()
317
318
319 def OnClose(self, event):
320 """Event handler for closing."""
321 self.SaveSettings()
322 self.crust.shell.destroy()
323 self.Destroy()
324
325
326 def OnAbout(self, event):
327 """Display an About window."""
328 title = 'About PyCrust'
329 text = 'PyCrust %s\n\n' % VERSION + \
330 'Yet another Python shell, only flakier.\n\n' + \
331 'Half-baked by Patrick K. O\'Brien,\n' + \
332 'the other half is still in the oven.\n\n' + \
333 'Shell Revision: %s\n' % self.shell.revision + \
334 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
335 'Platform: %s\n' % sys.platform + \
336 'Python Version: %s\n' % sys.version.split()[0] + \
337 'wxPython Version: %s\n' % wx.VERSION_STRING + \
338 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
339 dialog = wx.MessageDialog(self, text, title,
340 wx.OK | wx.ICON_INFORMATION)
341 dialog.ShowModal()
342 dialog.Destroy()
343
344
345 def ToggleTools(self):
346 """Toggle the display of the filling and other tools"""
347 return self.crust.ToggleTools()
348
349 def ToolsShown(self):
350 return self.crust.ToolsShown()
351
352 def OnHelp(self, event):
353 """Show a help dialog."""
354 frame.ShellFrameMixin.OnHelp(self, event)
355
356
357 def LoadSettings(self):
358 if self.config is not None:
359 frame.ShellFrameMixin.LoadSettings(self)
360 frame.Frame.LoadSettings(self, self.config)
361 self.crust.LoadSettings(self.config)
362
363
364 def SaveSettings(self, force=False):
365 if self.config is not None:
366 frame.ShellFrameMixin.SaveSettings(self)
367 if self.autoSaveSettings or force:
368 frame.Frame.SaveSettings(self, self.config)
369 self.crust.SaveSettings(self.config)
370
371
372 def DoSaveSettings(self):
373 if self.config is not None:
374 self.SaveSettings(force=True)
375 self.config.Flush()
376
377
378