+"""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
+
+
+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.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