| 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 sys |
| 12 | |
| 13 | import dispatcher |
| 14 | import editwindow |
| 15 | from filling import Filling |
| 16 | import frame |
| 17 | from shell import Shell |
| 18 | from version import VERSION |
| 19 | |
| 20 | |
| 21 | class Crust(wx.SplitterWindow): |
| 22 | """Crust based on SplitterWindow.""" |
| 23 | |
| 24 | name = 'Crust' |
| 25 | revision = __revision__ |
| 26 | |
| 27 | def __init__(self, parent, id=-1, pos=wx.DefaultPosition, |
| 28 | size=wx.DefaultSize, style=wx.SP_3D, |
| 29 | name='Crust Window', rootObject=None, rootLabel=None, |
| 30 | rootIsNamespace=True, intro='', locals=None, |
| 31 | InterpClass=None, *args, **kwds): |
| 32 | """Create Crust instance.""" |
| 33 | wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name) |
| 34 | self.shell = Shell(parent=self, introText=intro, |
| 35 | locals=locals, InterpClass=InterpClass, |
| 36 | *args, **kwds) |
| 37 | self.editor = self.shell |
| 38 | if rootObject is None: |
| 39 | rootObject = self.shell.interp.locals |
| 40 | self.notebook = wx.Notebook(parent=self, id=-1) |
| 41 | self.shell.interp.locals['notebook'] = self.notebook |
| 42 | self.filling = Filling(parent=self.notebook, |
| 43 | rootObject=rootObject, |
| 44 | rootLabel=rootLabel, |
| 45 | rootIsNamespace=rootIsNamespace) |
| 46 | # Add 'filling' to the interpreter's locals. |
| 47 | self.shell.interp.locals['filling'] = self.filling |
| 48 | self.notebook.AddPage(page=self.filling, text='Namespace', select=True) |
| 49 | self.display = Display(parent=self.notebook) |
| 50 | self.notebook.AddPage(page=self.display, text='Display') |
| 51 | # Add 'pp' (pretty print) to the interpreter's locals. |
| 52 | self.shell.interp.locals['pp'] = self.display.setItem |
| 53 | self.calltip = Calltip(parent=self.notebook) |
| 54 | self.notebook.AddPage(page=self.calltip, text='Calltip') |
| 55 | self.sessionlisting = SessionListing(parent=self.notebook) |
| 56 | self.notebook.AddPage(page=self.sessionlisting, text='Session') |
| 57 | self.dispatcherlisting = DispatcherListing(parent=self.notebook) |
| 58 | self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher') |
| 59 | ## from wxd import wx_ |
| 60 | ## self.wxdocs = Filling(parent=self.notebook, |
| 61 | ## rootObject=wx_, |
| 62 | ## rootLabel='wx', |
| 63 | ## rootIsNamespace=False, |
| 64 | ## static=True) |
| 65 | ## self.notebook.AddPage(page=self.wxdocs, text='wxPython Docs') |
| 66 | ## from wxd import stc_ |
| 67 | ## self.stcdocs = Filling(parent=self.notebook, |
| 68 | ## rootObject=stc_.StyledTextCtrl, |
| 69 | ## rootLabel='StyledTextCtrl', |
| 70 | ## rootIsNamespace=False, |
| 71 | ## static=True) |
| 72 | ## self.notebook.AddPage(page=self.stcdocs, text='StyledTextCtrl Docs') |
| 73 | self.SplitHorizontally(self.shell, self.notebook, 300) |
| 74 | self.SetMinimumPaneSize(1) |
| 75 | |
| 76 | |
| 77 | class Display(editwindow.EditWindow): |
| 78 | """STC used to display an object using Pretty Print.""" |
| 79 | |
| 80 | def __init__(self, parent, id=-1, pos=wx.DefaultPosition, |
| 81 | size=wx.DefaultSize, |
| 82 | style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER, |
| 83 | static=False): |
| 84 | """Create Display instance.""" |
| 85 | editwindow.EditWindow.__init__(self, parent, id, pos, size, style) |
| 86 | # Configure various defaults and user preferences. |
| 87 | self.SetReadOnly(True) |
| 88 | self.SetWrapMode(False) |
| 89 | if not static: |
| 90 | dispatcher.connect(receiver=self.push, signal='Interpreter.push') |
| 91 | |
| 92 | def push(self, command, more): |
| 93 | """Receiver for Interpreter.push signal.""" |
| 94 | self.Refresh() |
| 95 | |
| 96 | def Refresh(self): |
| 97 | if not hasattr(self, "item"): |
| 98 | return |
| 99 | self.SetReadOnly(False) |
| 100 | text = pprint.pformat(self.item) |
| 101 | self.SetText(text) |
| 102 | self.SetReadOnly(True) |
| 103 | |
| 104 | def setItem(self, item): |
| 105 | """Set item to pretty print in the notebook Display tab.""" |
| 106 | self.item = item |
| 107 | self.Refresh() |
| 108 | |
| 109 | |
| 110 | class Calltip(wx.TextCtrl): |
| 111 | """Text control containing the most recent shell calltip.""" |
| 112 | |
| 113 | def __init__(self, parent=None, id=-1): |
| 114 | style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2) |
| 115 | wx.TextCtrl.__init__(self, parent, id, style=style) |
| 116 | self.SetBackgroundColour(wx.Colour(255, 255, 232)) |
| 117 | dispatcher.connect(receiver=self.display, signal='Shell.calltip') |
| 118 | |
| 119 | def display(self, calltip): |
| 120 | """Receiver for Shell.calltip signal.""" |
| 121 | ## self.SetValue(calltip) # Caused refresh problem on Windows. |
| 122 | self.Clear() |
| 123 | self.AppendText(calltip) |
| 124 | |
| 125 | |
| 126 | class SessionListing(wx.TextCtrl): |
| 127 | """Text control containing all commands for session.""" |
| 128 | |
| 129 | def __init__(self, parent=None, id=-1): |
| 130 | style = (wx.TE_MULTILINE | wx.TE_READONLY | |
| 131 | wx.TE_RICH2 | wx.TE_DONTWRAP) |
| 132 | wx.TextCtrl.__init__(self, parent, id, style=style) |
| 133 | dispatcher.connect(receiver=self.push, signal='Interpreter.push') |
| 134 | |
| 135 | def push(self, command, more): |
| 136 | """Receiver for Interpreter.push signal.""" |
| 137 | if command and not more: |
| 138 | self.SetInsertionPointEnd() |
| 139 | start, end = self.GetSelection() |
| 140 | if start != end: |
| 141 | self.SetSelection(0, 0) |
| 142 | self.AppendText(command + '\n') |
| 143 | |
| 144 | |
| 145 | class DispatcherListing(wx.TextCtrl): |
| 146 | """Text control containing all dispatches for session.""" |
| 147 | |
| 148 | def __init__(self, parent=None, id=-1): |
| 149 | style = (wx.TE_MULTILINE | wx.TE_READONLY | |
| 150 | wx.TE_RICH2 | wx.TE_DONTWRAP) |
| 151 | wx.TextCtrl.__init__(self, parent, id, style=style) |
| 152 | dispatcher.connect(receiver=self.spy) |
| 153 | |
| 154 | def spy(self, signal, sender): |
| 155 | """Receiver for Any signal from Any sender.""" |
| 156 | text = '%r from %s' % (signal, sender) |
| 157 | self.SetInsertionPointEnd() |
| 158 | start, end = self.GetSelection() |
| 159 | if start != end: |
| 160 | self.SetSelection(0, 0) |
| 161 | self.AppendText(text + '\n') |
| 162 | |
| 163 | |
| 164 | class CrustFrame(frame.Frame): |
| 165 | """Frame containing all the PyCrust components.""" |
| 166 | |
| 167 | name = 'CrustFrame' |
| 168 | revision = __revision__ |
| 169 | |
| 170 | def __init__(self, parent=None, id=-1, title='PyCrust', |
| 171 | pos=wx.DefaultPosition, size=wx.DefaultSize, |
| 172 | style=wx.DEFAULT_FRAME_STYLE, |
| 173 | rootObject=None, rootLabel=None, rootIsNamespace=True, |
| 174 | locals=None, InterpClass=None, *args, **kwds): |
| 175 | """Create CrustFrame instance.""" |
| 176 | frame.Frame.__init__(self, parent, id, title, pos, size, style) |
| 177 | intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION |
| 178 | intro += '\nSponsored by Orbtech - ' |
| 179 | intro += 'Your source for Python programming expertise.' |
| 180 | self.SetStatusText(intro.replace('\n', ', ')) |
| 181 | self.crust = Crust(parent=self, intro=intro, |
| 182 | rootObject=rootObject, |
| 183 | rootLabel=rootLabel, |
| 184 | rootIsNamespace=rootIsNamespace, |
| 185 | locals=locals, |
| 186 | InterpClass=InterpClass, *args, **kwds) |
| 187 | self.shell = self.crust.shell |
| 188 | # Override the filling so that status messages go to the status bar. |
| 189 | self.crust.filling.tree.setStatusText = self.SetStatusText |
| 190 | # Override the shell so that status messages go to the status bar. |
| 191 | self.shell.setStatusText = self.SetStatusText |
| 192 | # Fix a problem with the sash shrinking to nothing. |
| 193 | self.crust.filling.SetSashPosition(200) |
| 194 | # Set focus to the shell editor. |
| 195 | self.shell.SetFocus() |
| 196 | |
| 197 | def OnClose(self, event): |
| 198 | """Event handler for closing.""" |
| 199 | self.crust.shell.destroy() |
| 200 | self.Destroy() |
| 201 | |
| 202 | def OnAbout(self, event): |
| 203 | """Display an About window.""" |
| 204 | title = 'About PyCrust' |
| 205 | text = 'PyCrust %s\n\n' % VERSION + \ |
| 206 | 'Yet another Python shell, only flakier.\n\n' + \ |
| 207 | 'Half-baked by Patrick K. O\'Brien,\n' + \ |
| 208 | 'the other half is still in the oven.\n\n' + \ |
| 209 | 'Shell Revision: %s\n' % self.shell.revision + \ |
| 210 | 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \ |
| 211 | 'Platform: %s\n' % sys.platform + \ |
| 212 | 'Python Version: %s\n' % sys.version.split()[0] + \ |
| 213 | 'wxPython Version: %s\n' % wx.VERSION_STRING + \ |
| 214 | ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:])) |
| 215 | dialog = wx.MessageDialog(self, text, title, |
| 216 | wx.OK | wx.ICON_INFORMATION) |
| 217 | dialog.ShowModal() |
| 218 | dialog.Destroy() |