git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41077 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			842 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			842 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""PyAlaCarte and PyAlaMode editors."""
 | 
						|
 | 
						|
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 | 
						|
__cvsid__ = "$Id$"
 | 
						|
__revision__ = "$Revision$"[11:-2]
 | 
						|
 | 
						|
import wx
 | 
						|
 | 
						|
from buffer import Buffer
 | 
						|
import crust
 | 
						|
import dispatcher
 | 
						|
import editwindow
 | 
						|
import frame
 | 
						|
from shell import Shell
 | 
						|
import version
 | 
						|
 | 
						|
 | 
						|
class EditorFrame(frame.Frame):
 | 
						|
    """Frame containing one editor."""
 | 
						|
 | 
						|
    def __init__(self, parent=None, id=-1, title='PyAlaCarte',
 | 
						|
                 pos=wx.DefaultPosition, size=(800, 600), 
 | 
						|
                 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
 | 
						|
                 filename=None):
 | 
						|
        """Create EditorFrame instance."""
 | 
						|
        frame.Frame.__init__(self, parent, id, title, pos, size, style)
 | 
						|
        self.buffers = {}
 | 
						|
        self.buffer = None  # Current buffer.
 | 
						|
        self.editor = None
 | 
						|
        self._defaultText = title + ' - the tastiest Python editor.'
 | 
						|
        self._statusText = self._defaultText
 | 
						|
        self.SetStatusText(self._statusText)
 | 
						|
        self.Bind(wx.EVT_IDLE, self.OnIdle)
 | 
						|
        self._setup()
 | 
						|
        if filename:
 | 
						|
            self.bufferCreate(filename)
 | 
						|
 | 
						|
    def _setup(self):
 | 
						|
        """Setup prior to first buffer creation.
 | 
						|
 | 
						|
        Useful for subclasses."""
 | 
						|
        pass
 | 
						|
 | 
						|
    def setEditor(self, editor):
 | 
						|
        self.editor = editor
 | 
						|
        self.buffer = self.editor.buffer
 | 
						|
        self.buffers[self.buffer.id] = self.buffer
 | 
						|
 | 
						|
    def OnAbout(self, event):
 | 
						|
        """Display an About window."""
 | 
						|
        title = 'About PyAlaCarte'
 | 
						|
        text = 'Another fine, flaky program.'
 | 
						|
        dialog = wx.MessageDialog(self, text, title,
 | 
						|
                                  wx.OK | wx.ICON_INFORMATION)
 | 
						|
        dialog.ShowModal()
 | 
						|
        dialog.Destroy()
 | 
						|
 | 
						|
    def OnClose(self, event):
 | 
						|
        """Event handler for closing."""
 | 
						|
        for buffer in self.buffers.values():
 | 
						|
            self.buffer = buffer
 | 
						|
            if buffer.hasChanged():
 | 
						|
                cancel = self.bufferSuggestSave()
 | 
						|
                if cancel and event.CanVeto():
 | 
						|
                    event.Veto()
 | 
						|
                    return
 | 
						|
        self.Destroy()
 | 
						|
 | 
						|
    def OnIdle(self, event):
 | 
						|
        """Event handler for idle time."""
 | 
						|
        self._updateStatus()
 | 
						|
        if hasattr(self, 'notebook'):
 | 
						|
            self._updateTabText()
 | 
						|
        self._updateTitle()
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
    def _updateStatus(self):
 | 
						|
        """Show current status information."""
 | 
						|
        if self.editor and hasattr(self.editor, 'getStatus'):
 | 
						|
            status = self.editor.getStatus()
 | 
						|
            text = 'File: %s  |  Line: %d  |  Column: %d' % status
 | 
						|
        else:
 | 
						|
            text = self._defaultText
 | 
						|
        if text != self._statusText:
 | 
						|
            self.SetStatusText(text)
 | 
						|
            self._statusText = text
 | 
						|
 | 
						|
    def _updateTabText(self):
 | 
						|
        """Show current buffer information on notebook tab."""
 | 
						|
##         suffix = ' **'
 | 
						|
##         notebook = self.notebook
 | 
						|
##         selection = notebook.GetSelection()
 | 
						|
##         if selection == -1:
 | 
						|
##             return
 | 
						|
##         text = notebook.GetPageText(selection)
 | 
						|
##         window = notebook.GetPage(selection)
 | 
						|
##         if window.editor and window.editor.buffer.hasChanged():
 | 
						|
##             if text.endswith(suffix):
 | 
						|
##                 pass
 | 
						|
##             else:
 | 
						|
##                 notebook.SetPageText(selection, text + suffix)
 | 
						|
##         else:
 | 
						|
##             if text.endswith(suffix):
 | 
						|
##                 notebook.SetPageText(selection, text[:len(suffix)])
 | 
						|
 | 
						|
    def _updateTitle(self):
 | 
						|
        """Show current title information."""
 | 
						|
        title = self.GetTitle()
 | 
						|
        if self.bufferHasChanged():
 | 
						|
            if title.startswith('* '):
 | 
						|
                pass
 | 
						|
            else:
 | 
						|
                self.SetTitle('* ' + title)
 | 
						|
        else:
 | 
						|
            if title.startswith('* '):
 | 
						|
                self.SetTitle(title[2:])
 | 
						|
        
 | 
						|
    def hasBuffer(self):
 | 
						|
        """Return True if there is a current buffer."""
 | 
						|
        if self.buffer:
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
 | 
						|
    def bufferClose(self):
 | 
						|
        """Close buffer."""
 | 
						|
        if self.bufferHasChanged():
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        self.bufferDestroy()
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferCreate(self, filename=None):
 | 
						|
        """Create new buffer."""
 | 
						|
        self.bufferDestroy()
 | 
						|
        buffer = Buffer()
 | 
						|
        self.panel = panel = wx.Panel(parent=self, id=-1)
 | 
						|
        panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)        
 | 
						|
        editor = Editor(parent=panel)
 | 
						|
        panel.editor = editor
 | 
						|
        sizer = wx.BoxSizer(wx.VERTICAL)
 | 
						|
        sizer.Add(editor.window, 1, wx.EXPAND)
 | 
						|
        panel.SetSizer(sizer)
 | 
						|
        panel.SetAutoLayout(True)
 | 
						|
        sizer.Layout()
 | 
						|
        buffer.addEditor(editor)
 | 
						|
        buffer.open(filename)
 | 
						|
        self.setEditor(editor)
 | 
						|
        self.editor.setFocus()
 | 
						|
        self.SendSizeEvent()
 | 
						|
        
 | 
						|
 | 
						|
    def bufferDestroy(self):
 | 
						|
        """Destroy the current buffer."""
 | 
						|
        if self.buffer:
 | 
						|
            for editor in self.buffer.editors.values():
 | 
						|
                editor.destroy()
 | 
						|
            self.editor = None
 | 
						|
            del self.buffers[self.buffer.id]
 | 
						|
            self.buffer = None
 | 
						|
            self.panel.Destroy()
 | 
						|
 | 
						|
 | 
						|
    def bufferHasChanged(self):
 | 
						|
        """Return True if buffer has changed since last save."""
 | 
						|
        if self.buffer:
 | 
						|
            return self.buffer.hasChanged()
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
 | 
						|
    def bufferNew(self):
 | 
						|
        """Create new buffer."""
 | 
						|
        if self.bufferHasChanged():
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        self.bufferCreate()
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferOpen(self):
 | 
						|
        """Open file in buffer."""
 | 
						|
        if self.bufferHasChanged():
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        filedir = ''
 | 
						|
        if self.buffer and self.buffer.doc.filedir:
 | 
						|
            filedir = self.buffer.doc.filedir
 | 
						|
        result = openSingle(directory=filedir)
 | 
						|
        if result.path:
 | 
						|
            self.bufferCreate(result.path)
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
##     def bufferPrint(self):
 | 
						|
##         """Print buffer."""
 | 
						|
##         pass
 | 
						|
 | 
						|
##     def bufferRevert(self):
 | 
						|
##         """Revert buffer to version of file on disk."""
 | 
						|
##         pass
 | 
						|
 | 
						|
    def bufferSave(self):
 | 
						|
        """Save buffer to its file."""
 | 
						|
        if self.buffer.doc.filepath:
 | 
						|
            self.buffer.save()
 | 
						|
            cancel = False
 | 
						|
        else:
 | 
						|
            cancel = self.bufferSaveAs()
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferSaveAs(self):
 | 
						|
        """Save buffer to a new filename."""
 | 
						|
        if self.bufferHasChanged() and self.buffer.doc.filepath:
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        filedir = ''
 | 
						|
        if self.buffer and self.buffer.doc.filedir:
 | 
						|
            filedir = self.buffer.doc.filedir
 | 
						|
        result = saveSingle(directory=filedir)
 | 
						|
        if result.path:
 | 
						|
            self.buffer.saveAs(result.path)
 | 
						|
            cancel = False
 | 
						|
        else:
 | 
						|
            cancel = True
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferSuggestSave(self):
 | 
						|
        """Suggest saving changes.  Return True if user selected Cancel."""
 | 
						|
        result = messageDialog(parent=None,
 | 
						|
                               message='%s has changed.\n'
 | 
						|
                                       'Would you like to save it first'
 | 
						|
                                       '?' % self.buffer.name,
 | 
						|
                               title='Save current file?')
 | 
						|
        if result.positive:
 | 
						|
            cancel = self.bufferSave()
 | 
						|
        else:
 | 
						|
            cancel = result.text == 'Cancel'
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def updateNamespace(self):
 | 
						|
        """Update the buffer namespace for autocompletion and calltips."""
 | 
						|
        if self.buffer.updateNamespace():
 | 
						|
            self.SetStatusText('Namespace updated')
 | 
						|
        else:
 | 
						|
            self.SetStatusText('Error executing, unable to update namespace')
 | 
						|
 | 
						|
 | 
						|
class EditorNotebookFrame(EditorFrame):
 | 
						|
    """Frame containing one or more editors in a notebook."""
 | 
						|
 | 
						|
    def __init__(self, parent=None, id=-1, title='PyAlaMode',
 | 
						|
                 pos=wx.DefaultPosition, size=(800, 600), 
 | 
						|
                 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
 | 
						|
                 filename=None):
 | 
						|
        """Create EditorNotebookFrame instance."""
 | 
						|
        self.notebook = None
 | 
						|
        EditorFrame.__init__(self, parent, id, title, pos,
 | 
						|
                             size, style, filename)
 | 
						|
        if self.notebook:
 | 
						|
            dispatcher.connect(receiver=self._editorChange,
 | 
						|
                               signal='EditorChange', sender=self.notebook)
 | 
						|
 | 
						|
    def _setup(self):
 | 
						|
        """Setup prior to first buffer creation.
 | 
						|
 | 
						|
        Called automatically by base class during init."""
 | 
						|
        self.notebook = EditorNotebook(parent=self)
 | 
						|
        intro = 'Py %s' % version.VERSION
 | 
						|
        import imp
 | 
						|
        module = imp.new_module('__main__')
 | 
						|
        import __builtin__
 | 
						|
        module.__dict__['__builtins__'] = __builtin__
 | 
						|
        namespace = module.__dict__.copy()
 | 
						|
        self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
 | 
						|
        self.shell = self.crust.shell
 | 
						|
        # Override the filling so that status messages go to the status bar.
 | 
						|
        self.crust.filling.tree.setStatusText = self.SetStatusText
 | 
						|
        # Override the shell so that status messages go to the status bar.
 | 
						|
        self.shell.setStatusText = self.SetStatusText
 | 
						|
        # Fix a problem with the sash shrinking to nothing.
 | 
						|
        self.crust.filling.SetSashPosition(200)
 | 
						|
        self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
 | 
						|
        self.setEditor(self.crust.editor)
 | 
						|
        self.crust.editor.SetFocus()
 | 
						|
 | 
						|
    def _editorChange(self, editor):
 | 
						|
        """Editor change signal receiver."""
 | 
						|
        self.setEditor(editor)
 | 
						|
 | 
						|
    def OnAbout(self, event):
 | 
						|
        """Display an About window."""
 | 
						|
        title = 'About PyAlaMode'
 | 
						|
        text = 'Another fine, flaky program.'
 | 
						|
        dialog = wx.MessageDialog(self, text, title,
 | 
						|
                                  wx.OK | wx.ICON_INFORMATION)
 | 
						|
        dialog.ShowModal()
 | 
						|
        dialog.Destroy()
 | 
						|
 | 
						|
    def _updateTitle(self):
 | 
						|
        """Show current title information."""
 | 
						|
        pass
 | 
						|
##         title = self.GetTitle()
 | 
						|
##         if self.bufferHasChanged():
 | 
						|
##             if title.startswith('* '):
 | 
						|
##                 pass
 | 
						|
##             else:
 | 
						|
##                 self.SetTitle('* ' + title)
 | 
						|
##         else:
 | 
						|
##             if title.startswith('* '):
 | 
						|
##                 self.SetTitle(title[2:])
 | 
						|
        
 | 
						|
    def bufferCreate(self, filename=None):
 | 
						|
        """Create new buffer."""
 | 
						|
        buffer = Buffer()
 | 
						|
        panel = wx.Panel(parent=self.notebook, id=-1)
 | 
						|
        panel.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: x)        
 | 
						|
        editor = Editor(parent=panel)
 | 
						|
        panel.editor = editor
 | 
						|
        sizer = wx.BoxSizer(wx.VERTICAL)
 | 
						|
        sizer.Add(editor.window, 1, wx.EXPAND)
 | 
						|
        panel.SetSizer(sizer)
 | 
						|
        panel.SetAutoLayout(True)
 | 
						|
        sizer.Layout()
 | 
						|
        buffer.addEditor(editor)
 | 
						|
        buffer.open(filename)
 | 
						|
        self.setEditor(editor)
 | 
						|
        self.notebook.AddPage(page=panel, text=self.buffer.name, select=True)
 | 
						|
        self.editor.setFocus()
 | 
						|
 | 
						|
    def bufferDestroy(self):
 | 
						|
        """Destroy the current buffer."""
 | 
						|
        selection = self.notebook.GetSelection()
 | 
						|
##         print "Destroy Selection:", selection
 | 
						|
        if selection > 0:  # Don't destroy the PyCrust tab.
 | 
						|
            if self.buffer:
 | 
						|
                del self.buffers[self.buffer.id]
 | 
						|
                self.buffer = None  # Do this before DeletePage().
 | 
						|
            self.notebook.DeletePage(selection)
 | 
						|
 | 
						|
    def bufferNew(self):
 | 
						|
        """Create new buffer."""
 | 
						|
        self.bufferCreate()
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferOpen(self):
 | 
						|
        """Open file in buffer."""
 | 
						|
        filedir = ''
 | 
						|
        if self.buffer and self.buffer.doc.filedir:
 | 
						|
            filedir = self.buffer.doc.filedir
 | 
						|
        result = openMultiple(directory=filedir)
 | 
						|
        for path in result.paths:
 | 
						|
            self.bufferCreate(path)
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
 | 
						|
class EditorNotebook(wx.Notebook):
 | 
						|
    """A notebook containing a page for each editor."""
 | 
						|
 | 
						|
    def __init__(self, parent):
 | 
						|
        """Create EditorNotebook instance."""
 | 
						|
        wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
 | 
						|
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging, id=self.GetId())
 | 
						|
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
 | 
						|
        self.Bind(wx.EVT_IDLE, self.OnIdle)
 | 
						|
 | 
						|
    def OnIdle(self, event):
 | 
						|
        """Event handler for idle time."""
 | 
						|
        self._updateTabText()
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
    def _updateTabText(self):
 | 
						|
        """Show current buffer display name on all but first tab."""
 | 
						|
        size = 3
 | 
						|
        changed = ' **'
 | 
						|
        unchanged = ' --'
 | 
						|
        selection = self.GetSelection()
 | 
						|
        if selection < 1:
 | 
						|
            return
 | 
						|
        text = self.GetPageText(selection)
 | 
						|
        window = self.GetPage(selection)
 | 
						|
        if not window.editor:
 | 
						|
            return
 | 
						|
        if text.endswith(changed) or text.endswith(unchanged):
 | 
						|
            name = text[:-size]
 | 
						|
        else:
 | 
						|
            name = text
 | 
						|
        if name != window.editor.buffer.name:
 | 
						|
            text = window.editor.buffer.name
 | 
						|
        if window.editor.buffer.hasChanged():
 | 
						|
            if text.endswith(changed):
 | 
						|
                text = None
 | 
						|
            elif text.endswith(unchanged):
 | 
						|
                text = text[:-size] + changed
 | 
						|
            else:
 | 
						|
                text += changed
 | 
						|
        else:
 | 
						|
            if text.endswith(changed):
 | 
						|
                text = text[:-size] + unchanged
 | 
						|
            elif text.endswith(unchanged):
 | 
						|
                text = None
 | 
						|
            else:
 | 
						|
                text += unchanged
 | 
						|
        if text is not None:
 | 
						|
            self.SetPageText(selection, text)
 | 
						|
            self.Refresh()  # Needed on Win98.
 | 
						|
 | 
						|
    def OnPageChanging(self, event):
 | 
						|
        """Page changing event handler."""
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
    def OnPageChanged(self, event):
 | 
						|
        """Page changed event handler."""
 | 
						|
        new = event.GetSelection()
 | 
						|
        window = self.GetPage(new)
 | 
						|
        dispatcher.send(signal='EditorChange', sender=self,
 | 
						|
                        editor=window.editor)
 | 
						|
        window.SetFocus()
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
 | 
						|
class EditorShellNotebookFrame(EditorNotebookFrame):
 | 
						|
    """Frame containing a notebook containing EditorShellNotebooks."""
 | 
						|
 | 
						|
    def __init__(self, parent=None, id=-1, title='PyAlaModeTest',
 | 
						|
                 pos=wx.DefaultPosition, size=(600, 400), 
 | 
						|
                 style=wx.DEFAULT_FRAME_STYLE,
 | 
						|
                 filename=None, singlefile=False):
 | 
						|
        """Create EditorShellNotebookFrame instance."""
 | 
						|
        self._singlefile = singlefile
 | 
						|
        EditorNotebookFrame.__init__(self, parent, id, title, pos,
 | 
						|
                                     size, style, filename)
 | 
						|
 | 
						|
    def _setup(self):
 | 
						|
        """Setup prior to first buffer creation.
 | 
						|
 | 
						|
        Called automatically by base class during init."""
 | 
						|
        if not self._singlefile:
 | 
						|
            self.notebook = EditorNotebook(parent=self)
 | 
						|
 | 
						|
    def OnAbout(self, event):
 | 
						|
        """Display an About window."""
 | 
						|
        title = 'About PyAlaModePlus'
 | 
						|
        text = 'Another fine, flaky program.'
 | 
						|
        dialog = wx.MessageDialog(self, text, title,
 | 
						|
                                  wx.OK | wx.ICON_INFORMATION)
 | 
						|
        dialog.ShowModal()
 | 
						|
        dialog.Destroy()
 | 
						|
 | 
						|
    def bufferCreate(self, filename=None):
 | 
						|
        """Create new buffer."""
 | 
						|
        if self._singlefile:
 | 
						|
            self.bufferDestroy()
 | 
						|
            notebook = EditorShellNotebook(parent=self,
 | 
						|
                                           filename=filename)
 | 
						|
            self.notebook = notebook
 | 
						|
        else:
 | 
						|
            notebook = EditorShellNotebook(parent=self.notebook,
 | 
						|
                                           filename=filename)
 | 
						|
        self.setEditor(notebook.editor)
 | 
						|
        if not self._singlefile:
 | 
						|
            self.notebook.AddPage(page=notebook, text=self.buffer.name,
 | 
						|
                                  select=True)
 | 
						|
        self.editor.setFocus()
 | 
						|
 | 
						|
    def bufferDestroy(self):
 | 
						|
        """Destroy the current buffer."""
 | 
						|
        if self.buffer:
 | 
						|
            self.editor = None
 | 
						|
            del self.buffers[self.buffer.id]
 | 
						|
            self.buffer = None  # Do this before DeletePage().
 | 
						|
        if self._singlefile:
 | 
						|
            self.notebook.Destroy()
 | 
						|
            self.notebook = None
 | 
						|
        else:
 | 
						|
            selection = self.notebook.GetSelection()
 | 
						|
##             print "Destroy Selection:", selection
 | 
						|
            self.notebook.DeletePage(selection)
 | 
						|
 | 
						|
    def bufferNew(self):
 | 
						|
        """Create new buffer."""
 | 
						|
        if self._singlefile and self.bufferHasChanged():
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        self.bufferCreate()
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
    def bufferOpen(self):
 | 
						|
        """Open file in buffer."""
 | 
						|
        if self._singlefile and self.bufferHasChanged():
 | 
						|
            cancel = self.bufferSuggestSave()
 | 
						|
            if cancel:
 | 
						|
                return cancel
 | 
						|
        filedir = ''
 | 
						|
        if self.buffer and self.buffer.doc.filedir:
 | 
						|
            filedir = self.buffer.doc.filedir
 | 
						|
        if self._singlefile:
 | 
						|
            result = openSingle(directory=filedir)
 | 
						|
            if result.path:
 | 
						|
                self.bufferCreate(result.path)
 | 
						|
        else:
 | 
						|
            result = openMultiple(directory=filedir)
 | 
						|
            for path in result.paths:
 | 
						|
                self.bufferCreate(path)
 | 
						|
        cancel = False
 | 
						|
        return cancel
 | 
						|
 | 
						|
 | 
						|
class EditorShellNotebook(wx.Notebook):
 | 
						|
    """A notebook containing an editor page and a shell page."""
 | 
						|
 | 
						|
    def __init__(self, parent, filename=None):
 | 
						|
        """Create EditorShellNotebook instance."""
 | 
						|
        wx.Notebook.__init__(self, parent, id=-1)
 | 
						|
        usePanels = True
 | 
						|
        if usePanels:
 | 
						|
            editorparent = editorpanel = wx.Panel(self, -1)
 | 
						|
            shellparent = shellpanel = wx.Panel(self, -1)
 | 
						|
        else:
 | 
						|
            editorparent = self
 | 
						|
            shellparent = self
 | 
						|
        self.buffer = Buffer()
 | 
						|
        self.editor = Editor(parent=editorparent)
 | 
						|
        self.buffer.addEditor(self.editor)
 | 
						|
        self.buffer.open(filename)
 | 
						|
        self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
 | 
						|
                           style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
 | 
						|
        self.buffer.interp.locals.clear()
 | 
						|
        if usePanels:
 | 
						|
            self.AddPage(page=editorpanel, text='Editor', select=True)
 | 
						|
            self.AddPage(page=shellpanel, text='Shell')
 | 
						|
            # Setup sizers
 | 
						|
            editorsizer = wx.BoxSizer(wx.VERTICAL)
 | 
						|
            editorsizer.Add(self.editor.window, 1, wx.EXPAND)
 | 
						|
            editorpanel.SetSizer(editorsizer)
 | 
						|
            editorpanel.SetAutoLayout(True)
 | 
						|
            shellsizer = wx.BoxSizer(wx.VERTICAL)
 | 
						|
            shellsizer.Add(self.shell, 1, wx.EXPAND)
 | 
						|
            shellpanel.SetSizer(shellsizer)
 | 
						|
            shellpanel.SetAutoLayout(True)
 | 
						|
        else:
 | 
						|
            self.AddPage(page=self.editor.window, text='Editor', select=True)
 | 
						|
            self.AddPage(page=self.shell, text='Shell')
 | 
						|
        self.editor.setFocus()
 | 
						|
        self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
 | 
						|
 | 
						|
    def OnPageChanged(self, event):
 | 
						|
        """Page changed event handler."""
 | 
						|
        selection = event.GetSelection()
 | 
						|
        if selection == 0:
 | 
						|
            self.editor.setFocus()
 | 
						|
        else:
 | 
						|
            self.shell.SetFocus()
 | 
						|
        event.Skip()
 | 
						|
 | 
						|
    def SetFocus(self):
 | 
						|
        wx.Notebook.SetFocus(self)
 | 
						|
        selection = self.GetSelection()
 | 
						|
        if selection == 0:
 | 
						|
            self.editor.setFocus()
 | 
						|
        else:
 | 
						|
            self.shell.SetFocus()
 | 
						|
 | 
						|
 | 
						|
class Editor:
 | 
						|
    """Editor having an EditWindow."""
 | 
						|
 | 
						|
    def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
 | 
						|
                 size=wx.DefaultSize,
 | 
						|
                 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
 | 
						|
        """Create Editor instance."""
 | 
						|
        self.window = EditWindow(self, parent, id, pos, size, style)
 | 
						|
        self.id = self.window.GetId()
 | 
						|
        self.buffer = None
 | 
						|
        # Assign handlers for keyboard events.
 | 
						|
        self.window.Bind(wx.EVT_CHAR, self.OnChar)
 | 
						|
        self.window.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
 | 
						|
 | 
						|
    def _setBuffer(self, buffer, text):
 | 
						|
        """Set the editor to a buffer.  Private callback called by buffer."""
 | 
						|
        self.buffer = buffer
 | 
						|
        self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
 | 
						|
        self.clearAll()
 | 
						|
        self.setText(text)
 | 
						|
        self.emptyUndoBuffer()
 | 
						|
        self.setSavePoint()
 | 
						|
 | 
						|
    def destroy(self):
 | 
						|
        """Destroy all editor objects."""
 | 
						|
        self.window.Destroy()
 | 
						|
 | 
						|
    def clearAll(self):
 | 
						|
        self.window.ClearAll()
 | 
						|
 | 
						|
    def emptyUndoBuffer(self):
 | 
						|
        self.window.EmptyUndoBuffer()
 | 
						|
 | 
						|
    def getStatus(self):
 | 
						|
        """Return (filepath, line, column) status tuple."""
 | 
						|
        if self.window:
 | 
						|
            pos = self.window.GetCurrentPos()
 | 
						|
            line = self.window.LineFromPosition(pos) + 1
 | 
						|
            col = self.window.GetColumn(pos)
 | 
						|
            if self.buffer:
 | 
						|
                name = self.buffer.doc.filepath or self.buffer.name
 | 
						|
            else:
 | 
						|
                name = ''
 | 
						|
            status = (name, line, col)
 | 
						|
            return status
 | 
						|
        else:
 | 
						|
            return ('', 0, 0)
 | 
						|
 | 
						|
    def getText(self):
 | 
						|
        """Return contents of editor."""
 | 
						|
        return self.window.GetText()
 | 
						|
 | 
						|
    def hasChanged(self):
 | 
						|
        """Return True if contents have changed."""
 | 
						|
        return self.window.GetModify()
 | 
						|
 | 
						|
    def setFocus(self):
 | 
						|
        """Set the input focus to the editor window."""
 | 
						|
        self.window.SetFocus()
 | 
						|
 | 
						|
    def setSavePoint(self):
 | 
						|
        self.window.SetSavePoint()
 | 
						|
 | 
						|
    def setText(self, text):
 | 
						|
        """Set contents of editor."""
 | 
						|
        self.window.SetText(text)
 | 
						|
 | 
						|
    def OnChar(self, event):
 | 
						|
        """Keypress event handler.
 | 
						|
        
 | 
						|
        Only receives an event if OnKeyDown calls event.Skip() for the
 | 
						|
        corresponding event."""
 | 
						|
 | 
						|
        key = event.GetKeyCode()
 | 
						|
        if key in self.autoCompleteKeys:
 | 
						|
            # Usually the dot (period) key activates auto completion.
 | 
						|
            if self.window.AutoCompActive(): 
 | 
						|
                self.window.AutoCompCancel()
 | 
						|
            self.window.ReplaceSelection('')
 | 
						|
            self.window.AddText(chr(key))
 | 
						|
            text, pos = self.window.GetCurLine()
 | 
						|
            text = text[:pos]
 | 
						|
            if self.window.autoComplete: 
 | 
						|
                self.autoCompleteShow(text)
 | 
						|
        elif key == ord('('):
 | 
						|
            # The left paren activates a call tip and cancels an
 | 
						|
            # active auto completion.
 | 
						|
            if self.window.AutoCompActive(): 
 | 
						|
                self.window.AutoCompCancel()
 | 
						|
            self.window.ReplaceSelection('')
 | 
						|
            self.window.AddText('(')
 | 
						|
            text, pos = self.window.GetCurLine()
 | 
						|
            text = text[:pos]
 | 
						|
            self.autoCallTipShow(text)
 | 
						|
        else:
 | 
						|
            # Allow the normal event handling to take place.
 | 
						|
            event.Skip()
 | 
						|
 | 
						|
    def OnKeyDown(self, event):
 | 
						|
        """Key down event handler."""
 | 
						|
 | 
						|
        key = event.GetKeyCode()
 | 
						|
        # If the auto-complete window is up let it do its thing.
 | 
						|
        if self.window.AutoCompActive():
 | 
						|
            event.Skip()
 | 
						|
            return
 | 
						|
        controlDown = event.ControlDown()
 | 
						|
        altDown = event.AltDown()
 | 
						|
        shiftDown = event.ShiftDown()
 | 
						|
        # Let Ctrl-Alt-* get handled normally.
 | 
						|
        if controlDown and altDown:
 | 
						|
            event.Skip()
 | 
						|
        # Increase font size.
 | 
						|
        elif controlDown and key in (ord(']'),):
 | 
						|
            dispatcher.send(signal='FontIncrease')
 | 
						|
        # Decrease font size.
 | 
						|
        elif controlDown and key in (ord('['),):
 | 
						|
            dispatcher.send(signal='FontDecrease')
 | 
						|
        # Default font size.
 | 
						|
        elif controlDown and key in (ord('='),):
 | 
						|
            dispatcher.send(signal='FontDefault')
 | 
						|
        else:
 | 
						|
            event.Skip()
 | 
						|
 | 
						|
    def autoCompleteShow(self, command):
 | 
						|
        """Display auto-completion popup list."""
 | 
						|
        list = self.buffer.interp.getAutoCompleteList(command, 
 | 
						|
                    includeMagic=self.window.autoCompleteIncludeMagic, 
 | 
						|
                    includeSingle=self.window.autoCompleteIncludeSingle, 
 | 
						|
                    includeDouble=self.window.autoCompleteIncludeDouble)
 | 
						|
        if list:
 | 
						|
            options = ' '.join(list)
 | 
						|
            offset = 0
 | 
						|
            self.window.AutoCompShow(offset, options)
 | 
						|
 | 
						|
    def autoCallTipShow(self, command):
 | 
						|
        """Display argument spec and docstring in a popup window."""
 | 
						|
        if self.window.CallTipActive():
 | 
						|
            self.window.CallTipCancel()
 | 
						|
        (name, argspec, tip) = self.buffer.interp.getCallTip(command)
 | 
						|
        if tip:
 | 
						|
            dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
 | 
						|
        if not self.window.autoCallTip:
 | 
						|
            return
 | 
						|
        if argspec:
 | 
						|
            startpos = self.window.GetCurrentPos()
 | 
						|
            self.window.AddText(argspec + ')')
 | 
						|
            endpos = self.window.GetCurrentPos()
 | 
						|
            self.window.SetSelection(endpos, startpos)
 | 
						|
        if tip:
 | 
						|
            curpos = self.window.GetCurrentPos()
 | 
						|
            size = len(name)
 | 
						|
            tippos = curpos - (size + 1)
 | 
						|
            fallback = curpos - self.window.GetColumn(curpos)
 | 
						|
            # In case there isn't enough room, only go back to the
 | 
						|
            # fallback.
 | 
						|
            tippos = max(tippos, fallback)
 | 
						|
            self.window.CallTipShow(tippos, tip)
 | 
						|
            self.window.CallTipSetHighlight(0, size)
 | 
						|
 | 
						|
 | 
						|
class EditWindow(editwindow.EditWindow):
 | 
						|
    """EditWindow based on StyledTextCtrl."""
 | 
						|
 | 
						|
    def __init__(self, editor, parent, id=-1, pos=wx.DefaultPosition,
 | 
						|
                 size=wx.DefaultSize,
 | 
						|
                 style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
 | 
						|
        """Create EditWindow instance."""
 | 
						|
        editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
 | 
						|
        self.editor = editor
 | 
						|
 | 
						|
 | 
						|
class DialogResults:
 | 
						|
    """DialogResults class."""
 | 
						|
 | 
						|
    def __init__(self, returned):
 | 
						|
        """Create wrapper for results returned by dialog."""
 | 
						|
        self.returned = returned
 | 
						|
        self.positive = returned in (wx.ID_OK, wx.ID_YES)
 | 
						|
        self.text = self._asString()
 | 
						|
        
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return str(self.__dict__)
 | 
						|
 | 
						|
    def _asString(self):
 | 
						|
        returned = self.returned
 | 
						|
        if returned == wx.ID_OK:
 | 
						|
            return "Ok"
 | 
						|
        elif returned == wx.ID_CANCEL:
 | 
						|
            return "Cancel"
 | 
						|
        elif returned == wx.ID_YES:
 | 
						|
            return "Yes"
 | 
						|
        elif returned == wx.ID_NO:
 | 
						|
            return "No"
 | 
						|
 | 
						|
 | 
						|
def fileDialog(parent=None, title='Open', directory='', filename='',
 | 
						|
               wildcard='All Files (*.*)|*.*',
 | 
						|
               style=wx.OPEN | wx.MULTIPLE):
 | 
						|
    """File dialog wrapper function."""
 | 
						|
    dialog = wx.FileDialog(parent, title, directory, filename,
 | 
						|
                           wildcard, style)
 | 
						|
    result = DialogResults(dialog.ShowModal())
 | 
						|
    if result.positive:
 | 
						|
        result.paths = dialog.GetPaths()
 | 
						|
    else:
 | 
						|
        result.paths = []
 | 
						|
    dialog.Destroy()
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def openSingle(parent=None, title='Open', directory='', filename='',
 | 
						|
               wildcard='All Files (*.*)|*.*', style=wx.OPEN):
 | 
						|
    """File dialog wrapper function."""
 | 
						|
    dialog = wx.FileDialog(parent, title, directory, filename,
 | 
						|
                           wildcard, style)
 | 
						|
    result = DialogResults(dialog.ShowModal())
 | 
						|
    if result.positive:
 | 
						|
        result.path = dialog.GetPath()
 | 
						|
    else:
 | 
						|
        result.path = None
 | 
						|
    dialog.Destroy()
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def openMultiple(parent=None, title='Open', directory='', filename='',
 | 
						|
                 wildcard='All Files (*.*)|*.*',
 | 
						|
                 style=wx.OPEN | wx.MULTIPLE):
 | 
						|
    """File dialog wrapper function."""
 | 
						|
    return fileDialog(parent, title, directory, filename, wildcard, style)
 | 
						|
 | 
						|
 | 
						|
def saveSingle(parent=None, title='Save', directory='', filename='',
 | 
						|
               wildcard='All Files (*.*)|*.*',
 | 
						|
               style=wx.SAVE | wx.OVERWRITE_PROMPT):
 | 
						|
    """File dialog wrapper function."""
 | 
						|
    dialog = wx.FileDialog(parent, title, directory, filename,
 | 
						|
                           wildcard, style)
 | 
						|
    result = DialogResults(dialog.ShowModal())
 | 
						|
    if result.positive:
 | 
						|
        result.path = dialog.GetPath()
 | 
						|
    else:
 | 
						|
        result.path = None
 | 
						|
    dialog.Destroy()
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def directory(parent=None, message='Choose a directory', path='', style=0,
 | 
						|
              pos=wx.DefaultPosition, size=wx.DefaultSize):
 | 
						|
    """Dir dialog wrapper function."""
 | 
						|
    dialog = wx.DirDialog(parent, message, path, style, pos, size)
 | 
						|
    result = DialogResults(dialog.ShowModal())
 | 
						|
    if result.positive:
 | 
						|
        result.path = dialog.GetPath()
 | 
						|
    else:
 | 
						|
        result.path = None
 | 
						|
    dialog.Destroy()
 | 
						|
    return result
 | 
						|
 | 
						|
 | 
						|
def messageDialog(parent=None, message='', title='Message box',
 | 
						|
                  style=wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION,
 | 
						|
                  pos=wx.DefaultPosition):
 | 
						|
    """Message dialog wrapper function."""
 | 
						|
    dialog = wx.MessageDialog(parent, message, title, style, pos)
 | 
						|
    result = DialogResults(dialog.ShowModal())
 | 
						|
    dialog.Destroy()
 | 
						|
    return result
 |