Merged the wxPy_newswig branch into the HEAD branch (main trunk)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24541 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		@@ -1,8 +1,846 @@
 | 
			
		||||
"""PyAlaCarte and PyAlaMode editors."""
 | 
			
		||||
 | 
			
		||||
"""Renamer stub: provides a way to drop the wx prefix from wxPython objects."""
 | 
			
		||||
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 | 
			
		||||
__cvsid__ = "$Id$"
 | 
			
		||||
__revision__ = "$Revision$"[11:-2]
 | 
			
		||||
 | 
			
		||||
from wx import _rename
 | 
			
		||||
from wxPython.py import editor
 | 
			
		||||
_rename(globals(), editor.__dict__, modulename='py.editor')
 | 
			
		||||
del editor
 | 
			
		||||
del _rename
 | 
			
		||||
import wx
 | 
			
		||||
 | 
			
		||||
from buffer import Buffer
 | 
			
		||||
import crust
 | 
			
		||||
import dispatcher
 | 
			
		||||
import editwindow
 | 
			
		||||
import frame
 | 
			
		||||
from shell import Shell
 | 
			
		||||
import version
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    True
 | 
			
		||||
except NameError:
 | 
			
		||||
    True = 1==1
 | 
			
		||||
    False = 1==0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
        wx.EVT_IDLE(self, 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)
 | 
			
		||||
        wx.EVT_ERASE_BACKGROUND(panel, 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)
 | 
			
		||||
        wx.EVT_ERASE_BACKGROUND(panel, 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.NO_FULL_REPAINT_ON_RESIZE)
 | 
			
		||||
        wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
 | 
			
		||||
                                      self.OnPageChanging)
 | 
			
		||||
        wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
 | 
			
		||||
                                     self.OnPageChanged)
 | 
			
		||||
        wx.EVT_IDLE(self, 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()
 | 
			
		||||
        wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
 | 
			
		||||
 | 
			
		||||
    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.
 | 
			
		||||
        wx.EVT_CHAR(self.window, self.OnChar)
 | 
			
		||||
        wx.EVT_KEY_DOWN(self.window, 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."""
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    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.KeyCode()
 | 
			
		||||
        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.KeyCode()
 | 
			
		||||
        # 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.HIDE_READONLY | 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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user